clipmap.cpp

Go to the documentation of this file.
00001 // $Id: clipmap.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // External clipboard interface - classes for encapsulating clipboard data mappings
00099 // and for managing data transfers between the internal and external clipboards
00100 
00101 /*
00102 */
00103 
00104 
00105 #include "camtypes.h"
00106 
00107 // -- clipboard includes
00108 #include "clipext.h"
00109 #include "clipint.h"
00110 #include "clipmap.h"
00111 
00112 // --- text includes  **** !!!! BODGE
00113 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 #include "layer.h"
00115 #include "nodetext.h"
00116 #include "nodetxtl.h"
00117 #include "nodetxts.h"
00118 #include "unicdman.h"
00119 
00120 // --- Bitmap Mapping includes
00121 #include "bitmpinf.h"
00122 //#include "dibutil.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00123 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00124 //#include "jason.h"
00125 #include "nodebmp.h"
00126 #include "wbitmap.h"
00127 #include "scrcamvw.h"
00128 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00129 
00130 // ---
00131 //#include "ccfile.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00132 //#include "filters.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00133 //#include "nev.h"
00134 
00135 #include "cmxifltr.h"
00136 
00137 // This class is defined in kernel\cliptype.h
00138 CC_IMPLEMENT_MEMDUMP(InternalClipboardFormat, CC_CLASS_MEMDUMP)
00139 
00140 CC_IMPLEMENT_DYNCREATE(ClipboardMapping, ListItem)
00141 
00142 CC_IMPLEMENT_DYNCREATE(BodgeTextClipMap, ClipboardMapping)
00143 CC_IMPLEMENT_DYNCREATE(BodgeUnicodeClipMap, ClipboardMapping)
00144 
00145 CC_IMPLEMENT_DYNAMIC(CMXClipMap, ClipboardMapping)
00146 CC_IMPLEMENT_DYNCREATE(CMX16ClipMap, CMXClipMap)
00147 CC_IMPLEMENT_DYNCREATE(CMX32ClipMap, CMXClipMap)
00148 
00149 #ifdef _DEBUG
00150 CC_IMPLEMENT_DYNCREATE(RTFClipMap, ClipboardMapping)
00151 #endif
00152 
00153 CC_IMPLEMENT_DYNCREATE(BitmapClipMap, ClipboardMapping)
00154 //CC_IMPLEMENT_DYNCREATE(PaletteClipMap, ClipboardMapping)
00155 CC_IMPLEMENT_DYNCREATE(DIBClipMap, ClipboardMapping)
00156 
00157 #if FALSE
00158 CC_IMPLEMENT_DYNCREATE(QuarkPictureClipMap, ClipboardMapping)
00159 #endif
00160 
00161 #define new CAM_DEBUG_NEW
00162 
00163 
00164 
00165 
00166 /********************************************************************************************
00167 
00168 >   ClipboardMapping::ClipboardMapping()
00169 
00170     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00171     Created:    16/4/95
00172 
00173     Purpose:    Constructor
00174 
00175     Notes:      DON'T call the constructor - call CreateAndRegister
00176 
00177     SeeAlso:    ClipboardMapping::CreateAndRegister
00178 
00179 ********************************************************************************************/
00180 
00181 ClipboardMapping::ClipboardMapping()
00182 {
00183     ERROR3("You can't directly construct an ClipboardMapping - Call CreateAndRegister");
00184 }
00185 
00186 
00187 
00188 /********************************************************************************************
00189 
00190 >   ClipboardMapping::~ClipboardMapping()
00191 
00192     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00193     Created:    16/4/95
00194 
00195     Purpose:    Destructor
00196 
00197 ********************************************************************************************/
00198 
00199 ClipboardMapping::~ClipboardMapping()
00200 {
00201     RemoveTempFile();
00202 }
00203 
00204 
00205 
00206 /********************************************************************************************
00207 
00208 >   ClipboardMapping::ClipboardMapping(ClipboardMappingType TheType, Filter *TheFilter,
00209                                         InternalClipboardFormat &TheInternalDataType,
00210                                         UINT32 TheExternalDataType,
00211                                         UINT32 ThePriority)
00212     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00213     Created:    16/4/95
00214 
00215     Inputs:     TheType - indicates import / export / import & export
00216 
00217                 TheFilter - The filter which can apply this conversion
00218 
00219                 TheInternalDatatType - A class defining the internal data type
00220                 (see cliptype.h)
00221 
00222                 TheExternalDataType - A Windows CF_ constant defining the external
00223                 clipboard data type which will be imported/exported.
00224 
00225                 ThePriority - An integer indicating the priority of this mapping.
00226                 The highest available priority mapping will be used in order to
00227                 retain as much information in the data as possible. See
00228                 docs\howtouse\ExtClip.doc for details of the existing mappings.
00229 
00230     Purpose:    Constructs a clipboard mapping with the ExternalClipboard
00231                 manager. This mapping info describes a filter which is able to import
00232                 data from or export data to a windows clipboard in some way.
00233 
00234     Notes:      DON'T call the constructor - call CreateAndRegister
00235 
00236     SeeAlso:    ClipboardMapping::CreateAndRegister; InternalClipboardFormat
00237 
00238 ********************************************************************************************/
00239 
00240 ClipboardMapping::ClipboardMapping(ClipboardMappingType TheType, Filter *TheFilter,
00241                                     InternalClipboardFormat &TheInternalDataType,
00242                                     UINT32 TheExternalDataType,
00243                                     UINT32 ThePriority)
00244 {
00245     Type        = TheType;
00246     pFilter     = TheFilter;
00247 
00248     InternalDataType.SetFormatID(TheInternalDataType.GetFormatID());
00249     ExternalDataType = RealExternalType = TheExternalDataType;
00250 
00251     Priority    = ThePriority;
00252 
00253     Available   = FALSE;
00254 
00255     tempfilename = NULL;
00256 }
00257 
00258 
00259 
00261 //
00262 //  The OLE clipboard
00263 //
00264 
00265 #if (_OLE_VER >= 0x200)
00266 
00267 /********************************************************************************************
00268 >   void ClipboardMapping::SetRenderMemory(HGLOBAL hMem, DWORD cbMemSize)
00269 
00270     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00271     Created:    16/9/96
00272     Inputs:     hMem        ---     the global memory to delay-render into, or null if
00273                                     the rendering functions themselves should allocate
00274                                     it.
00275                 cbMemSize   ---     the size of the given memory block.
00276     Purpose:    Sets the memory that the delay-render functions will render into.
00277     SeeAlso:    ExternalClipboard::SetRenderMemory; OpClipboardExport::DoWithParam
00278 ********************************************************************************************/
00279 
00280 void ClipboardMapping::SetRenderMemory(HGLOBAL hMem, DWORD cbMemSize)
00281 {
00282     // Record the handle and its size.
00283     m_hMem = hMem;
00284     m_cbMemSize = cbMemSize;
00285 }
00286 
00287 #endif
00288 
00290 
00291 
00292 
00293 /********************************************************************************************
00294 
00295 >   static void ClipboardMapping::CreateAndRegister(ClipboardMappingType TheType, Filter *TheFilter,
00296                                                     InternalClipboardFormat &TheInternalDataType,
00297                                                     UINT32 TheExternalDataType,
00298                                                     UINT32 ThePriority)
00299     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00300     Created:    16/4/95
00301 
00302     Inputs:     TheType - indicates import / export / import & export
00303 
00304                 TheFilter - The filter which can apply this conversion
00305 
00306                 TheInternalDatatType - An object defining the internal data type
00307                 (see cliptype.h)
00308 
00309                 TheExternalDataType - A Windows CF_ constant defining the external
00310                 clipboard data type which will be imported/exported.
00311 
00312                 ThePriority - An integer indicating the priority of this mapping.
00313                 The highest available priority mapping will be used in order to
00314                 retain as much information in the data as possible. See
00315                 docs\howtouse\ExtClip.doc for details of the existing mappings.
00316 
00317     Purpose:    Constructs and registers a clipboard mapping with the ExternalClipboard
00318                 manager. This mapping info describes a filter which is able to import
00319                 data from or export data to a windows clipboard in some way.
00320 
00321     SeeAlso:    InternalClipboardFormat
00322 
00323 ********************************************************************************************/
00324 
00325 void ClipboardMapping::CreateAndRegister(ClipboardMappingType TheType, Filter *TheFilter,
00326                                          InternalClipboardFormat &TheInternalDataType,
00327                                          UINT32 TheExternalDataType,
00328                                          UINT32 ThePriority)
00329 {
00330     ClipboardMapping *Mapping = new ClipboardMapping(TheType, TheFilter,
00331                                                         TheInternalDataType, TheExternalDataType,
00332                                                         ThePriority);
00333     if (Mapping == NULL)
00334         InformError();
00335     else
00336         ExternalClipboard::RegisterDataType(Mapping);
00337 }
00338 
00339 
00340 
00341 /********************************************************************************************
00342 
00343 >   BOOL ClipboardMapping::ImportFromTempFile(TCHAR *filename, SelOperation *Caller,
00344                                                 InternalClipboard *Dest)
00345 
00346     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00347     Created:    20/4/95
00348 
00349     Inputs:     filename - the file name of the temporary scratch file to be loaded
00350                 Dest - the internal clipboard document to import into
00351 
00352 
00353     Purpose:    Internal helper function. Invokes pFilter::DoImport into the Dest doc,
00354                 using the given file as a source.
00355 
00356     Notes:      You must remove() the tem file yourself afterwards.
00357 
00358 ********************************************************************************************/
00359 
00360 BOOL ClipboardMapping::ImportFromTempFile(TCHAR *filename, SelOperation *Caller,
00361                                             InternalClipboard *Dest)
00362 {
00363     PathName FileToLoad(filename);
00364     
00365     CCLexFile* pFile = new CCDiskFile(1024, FALSE, TRUE);
00366 
00367     // See if we have a valid file
00368     if (pFile == NULL)
00369         return FALSE;
00370 
00371     // we have to try and open the file
00372     TRY
00373     {
00374         if (!((CCDiskFile*)pFile)->open(FileToLoad, ios::in | ios::binary))
00375         {
00376             // Failed to open the file...
00377             delete pFile;
00378             pFile = NULL;
00379             ERROR2RAW("Failed to open temp file for import into clipboard");
00380             return(FALSE);
00381         }
00382 
00383         // Found the Filter, so ask it to import the file please
00384 
00385         // Provide a current view for the filter to chomp on; We stack the current
00386         // view so that we do not corrupt it.
00387         View *OldCurrentView = View::GetCurrent();
00388         ClipboardView ImportView;
00389         if (!ImportView.Init())
00390         {
00391             delete pFile;
00392             pFile = NULL;
00393             return(FALSE);
00394         }
00395 
00396         ImportView.SetCurrent();
00397 
00398         if (!pFilter->DoImport(Caller, pFile, InternalClipboard::Instance()))
00399         {
00400             // Something went a bit wrong - tell the user what it was.
00401             // Only tell them if not special user cancelled error message
00402             if (Error::GetErrorNumber() != _R(IDN_USER_CANCELLED))
00403                 InformError();
00404 
00405                 // If the file is open, then close it
00406             if (pFile->isOpen())
00407                 pFile->close();
00408 
00409             // and die a bit
00410             delete pFile;
00411             pFile = NULL;
00412 
00413             if (OldCurrentView != NULL)
00414                 OldCurrentView->SetCurrent();
00415             return FALSE;
00416         }
00417 
00418         if (OldCurrentView != NULL)
00419             OldCurrentView->SetCurrent();
00420 
00421         // If the file is open, then close it
00422         if (pFile->isOpen())
00423             pFile->close();
00424     }
00425 
00426     // See if there was a file I/O error
00427     CATCH(CFileException, e)
00428     {
00429         // Report the error if no one else did
00430         if (Error::GetErrorNumber() != _R(IDN_USER_CANCELLED))
00431             InformError();
00432 
00433         // Make sure that the file is closed
00434         TRY
00435         {
00436             // Close the file
00437             if (pFile->isOpen())
00438                 pFile->close();
00439         }
00440         CATCH(CFileException, e)
00441         {
00442             // Not a lot we can do really...
00443         }
00444         END_CATCH
00445 
00446         // and fail
00447         delete pFile;
00448         pFile = NULL;
00449         return FALSE;
00450     }
00451     END_CATCH
00452 
00453     // Make sure that we have got rid of the file
00454     delete pFile;
00455 
00456     return(TRUE);
00457 }
00458 
00459 
00460 
00461 /********************************************************************************************
00462 
00463 >   virtual BOOL ClipboardMapping::HandleImport(SelOperation *Caller,
00464                                                 HANDLE ClipboardData,
00465                                                 InternalClipboard *Dest)
00466     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00467     Created:    20/4/95
00468 
00469     Inputs:     Caller - The operation within which this method is being called
00470                 ClipboardData - The result of calling GetClipboardData for your datatype
00471                 Dest - The InternalClipboard (document) to import the data into.
00472 
00473     Returns:    TRUE for success
00474 
00475     Purpose:    Calls the parent filter as appropriate to import the given data from
00476                 the external clipboard.
00477 
00478     Notes:      This base-class default treats the clipboard data as a file, and makes
00479                 the associated filter import it directly. (Note: It is currently
00480                 implemented by slaving a temp file to disc, in order to avoid CCMemFiles
00481                 which are not currently good enough for us to use)
00482 
00483 ********************************************************************************************/
00484 
00485 BOOL ClipboardMapping::HandleImport(SelOperation *Caller,
00486                                     HANDLE ClipboardData, InternalClipboard *Dest)
00487 {
00488     BOOL ok = TRUE;
00489 
00490     // ---
00491     // Get a scratch file - if TMP isn't set, this will try for c:\temp.
00492     // The filename will have XS as a prefix
00493     char *tempname = GetTempFileName(); //_ttempnam("C:\temp", "XS~");
00494     if (tempname == NULL)
00495     {
00496         ERROR3("Couldn't get a temp filename");
00497         return(FALSE);
00498     }
00499 
00500     PathName FullPath(tempname);
00501 
00502     // ---
00503     // Save the clipboard data into our tempfile
00504     OFSTRUCT OpenBuf;
00505     OpenBuf.cBytes = sizeof(OpenBuf);
00506     HFILE OutFile = OpenFile(tempname, &OpenBuf, OF_CREATE);
00507 
00508     // Did it work ok?
00509     if (OutFile == HFILE_ERROR)
00510     {
00511         ERROR2RAW("Import tempfile couldn't be opened");
00512         InformError();
00513         free(tempname);
00514         return(FALSE);
00515     }
00516 
00517     // And write it to the tempfile
00518     LPCSTR lpbuffer = (LPCSTR) GlobalLock(ClipboardData);
00519     if (lpbuffer != NULL)
00520     {
00521         DWORD DataSize = GlobalSize(ClipboardData);
00522 
00523         if (DataSize != 0)
00524         {
00525             UINT32 BytesWritten = _lwrite(OutFile, lpbuffer, DataSize);
00526 
00527             if (BytesWritten != DataSize)
00528             {
00529                 ERROR2RAW("Import tempfile save seems to have failed");
00530                 InformError();
00531                 ok = FALSE;
00532             }
00533         }
00534         else
00535         {
00536             ERROR3("No data in clipboard!");
00537             ok = FALSE;
00538         }
00539 
00540         GlobalUnlock(ClipboardData);
00541     }
00542     else
00543     {
00544         ERROR3("Clipboard memory chunk couldn't be locked!");
00545         ok = FALSE;
00546     }
00547 
00548     _lclose(OutFile);
00549 
00550 
00551     // ---
00552     // Now, import the temp file using our 'parent' filter
00553     if (ok)
00554         ok = ImportFromTempFile(tempname, Caller, InternalClipboard::Instance());
00555 
00556 
00557     // Delete the temp file, and deallocate the tempname memory
00558     _tremove(tempname);
00559     free(tempname);
00560     return(ok);
00561 }
00562 
00563 
00564 
00565 /********************************************************************************************
00566 
00567 >   BOOL ClipboardMapping::ExportToTempFile(TCHAR *filename, 
00568                                         Operation *Caller, InternalClipboard *Source)
00569 
00570     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00571     Created:    20/4/95
00572 
00573     Inputs:     filename - the file name of the temporary scratch file to be loaded
00574                 Caller   - the operation we're being called from 
00575                 Source   - the internal clipboard document to export from
00576 
00577     Returns:    TRUE if it succeeds. 
00578 
00579     Purpose:    Internal helper function. Invokes pFilter::DoExport from the Source doc,
00580                 using the given file as a destination.
00581 
00582     Notes:      You must delete the temp file afterwards - use 'remove()'
00583 
00584 ********************************************************************************************/
00585 
00586 BOOL ClipboardMapping::ExportToTempFile(TCHAR *filename, 
00587                                         Operation *Caller, InternalClipboard *Source)
00588 {
00589     // Provide a current view for the filter to chomp on; We stack the current
00590     // view so that we do not corrupt it.
00591     View *OldCurrentView = View::GetCurrent();
00592     ClipboardView ExportView;
00593     if (!ExportView.Init())
00594         return(FALSE);
00595 
00596     ExportView.SetCurrent();
00597 
00598     PathName FullPath(filename);
00599 
00600     // Try and open the temporary file
00601     CCDiskFile DiskFile(1024, FALSE, TRUE);
00602     BOOL AllOK = TRUE;
00603 
00604     TRY
00605     {
00606         if (!DiskFile.open(FullPath, ios::out | ios::binary))
00607         {
00608             if (OldCurrentView != NULL)
00609                 OldCurrentView->SetCurrent();
00610             return(FALSE);      // Failed to open the export file
00611         }
00612 
00613         // Tell the filter we would like a Preview Bitmap please
00614         if (pFilter->CanIncludePreviewBmp())
00615             pFilter->IncludePreviewBmp(TRUE);
00616 
00617         // Try and export the internal clipboard document
00618         if (!pFilter->DoExport(Caller, &DiskFile, &FullPath, InternalClipboard::Instance()))
00619         {
00620             // Something went a bit wrong - tell the user what it was.
00621             // Suppress the error if it was the 'user has cancelled one'
00622             if (Error::GetErrorNumber() != _R(IDN_USER_CANCELLED))
00623             {
00624                 InformError();
00625                 // Caller should clean up the temp file
00626             }
00627             else
00628                 Error::ClearError();    // otherwise remove the error so it won't get reported
00629             
00630             // Set the error
00631             AllOK = FALSE;
00632         }
00633 
00634         // Close the file
00635         if (DiskFile.isOpen())
00636             DiskFile.close();
00637     }
00638 
00639     // See if there was a file io error
00640     CATCH(CFileException, e)
00641     {
00642         // Report the error if no one else did
00643         if (Error::GetErrorNumber() != _R(IDN_USER_CANCELLED))
00644         {
00645             InformError();
00646         }
00647         else
00648             Error::ClearError();    // otherwise remove the error so it won't get reported
00649 
00650         // Make sure that the file is closed
00651         TRY
00652         {
00653             // Close that file
00654             if (DiskFile.isOpen())
00655                 DiskFile.close();
00656         }
00657         CATCH(CFileException, e)
00658         {
00659             // Not a lot we can do really...
00660         }
00661         END_CATCH
00662 
00663         // And restore the previous current view
00664         if (OldCurrentView != NULL)
00665             OldCurrentView->SetCurrent();
00666 
00667         return(FALSE);
00668     }
00669     END_CATCH
00670 
00671     // Tell the filter we would NOT like a Preview Bitmap ready for next time
00672     if (pFilter->CanIncludePreviewBmp())
00673         pFilter->IncludePreviewBmp(FALSE);
00674 
00675     // And restore the previous current view
00676     if (OldCurrentView != NULL)
00677         OldCurrentView->SetCurrent();
00678 
00679     return(TRUE);
00680 }
00681 
00682         
00683 /********************************************************************************************
00684 
00685 >   virtual BOOL ClipboardMapping::HandleExport(Operation *Caller,
00686                                                 InternalClipboard *Source)
00687 
00688     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00689     Created:    20/4/95
00690 
00691     Inputs:     Caller - the operation within which this method is being called
00692                 Source - the internal clipboard (document) to be exported
00693 
00694     Returns:    NULL (if it failed), or a windows handle of the data to be placed on
00695                 the clipboard.
00696 
00697     Purpose:    Invokes this mapping for exporting
00698                 This takes the document tree of Source, and exports it to the external
00699                 (windows) clipboard. Usually this just involves calling Filter::DoExport
00700                 for the parent filter, and then returning the handle to the global memory
00701                 block to be placed onto the external clipboard.
00702 
00703     Notes:      The returned handle should be the thing you'd pass to SetClipboardData
00704                 if you were dealing with it directly. You must adhere to all the Windows
00705                 rules for this - i.e. a global data block, unlocked, etc etc.
00706 
00707 ********************************************************************************************/
00708 
00709 HANDLE ClipboardMapping::HandleExport(Operation *Caller, InternalClipboard *Source)
00710 {
00711     ERROR3("Base class ClipboardMapping::HandleExport called");
00712 
00713 /*
00714     PathName FullPath;
00715 
00716     char *tempname = _ttempnam("C:\temp", "XS");
00717     if (tempname == NULL)
00718     {
00719         ERROR3("Couldn't get a temp filename");
00720         return(NULL);
00721     }
00722 
00723     if (!ExportToTempFile(tempname, Caller, Source))
00724     {
00725         remove(tempname);
00726         free(tempname);
00727         return(NULL);
00728     }
00729 
00730 
00731     // In the switch statement below, set this handle to the global mem handle
00732     // of the data you want to place on the clipboard. If you don't want to
00733     // put anything on, leave this handle NULL.
00734     HANDLE hGlobalMem = NULL;
00735 
00736 
00737     // **** !!!! Export the file
00738 
00739     // Delete the temp file, and return the result
00740     remove(tempname);
00741     free(tempname);
00742     return(hGlobalMem);
00743 */
00744     return(NULL);
00745 }
00746 
00747 
00748 
00749 /********************************************************************************************
00750 
00751 >   char *ClipboardMapping::GetTempFileName(void)
00752 
00753     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00754     Created:    29/4/95
00755 
00756     Returns:    NULL, or a a filename to be used as a temporary file
00757 
00758     Purpose:    Finds a temporary file
00759                 Remove it with ClipboardMapping::RemoveTempFile
00760 
00761     SeeAlso:    ClipboardMapping::RemoveTempFile
00762 
00763 ********************************************************************************************/
00764 
00765 char *ClipboardMapping::GetTempFileName(void)
00766 {
00767     RemoveTempFile();   // Try to ensure any previous tempfile is gone
00768 
00769     tempfilename = _ttempnam("C:\temp", "XS~");
00770 
00771     return(tempfilename);
00772 }
00773 
00774 
00775 
00776 /********************************************************************************************
00777 
00778 >   void ClipboardMapping::RemoveTempFile(void)
00779 
00780     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00781     Created:    29/4/95
00782 
00783     Purpose:    Removes the last temporary file 'allocated' with GetTempFilename
00784 
00785                 This function is automatically called when the clipboard is wiped,
00786                 as usually we had to leave the tempfile around while it was "on" the
00787                 clipboard.
00788 
00789     SeeAlso:    ClipboardMapping::GetTempFilename
00790 
00791 ********************************************************************************************/
00792 
00793 void ClipboardMapping::RemoveTempFile(void)
00794 {
00795     if (tempfilename != NULL)
00796     {
00797         _tremove(tempfilename);
00798         free(tempfilename);
00799         tempfilename = NULL;
00800     }
00801 }
00802 
00803 
00804 
00805 
00806 
00807 
00808 
00809 
00810 
00811 
00812 
00813 
00814 
00815 
00816 
00817 
00818 BodgeTextClipMap::BodgeTextClipMap()
00819 {
00820     ERROR3("Please don't press that button again");
00821 }
00822 
00823 
00824 /********************************************************************************************
00825 
00826 >   BodgeTextClipMap::BodgeTextClipMap(ClipboardMappingType TheType, UINT32 ClaimType = 0)
00827     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00828     Created:    16/4/95
00829 
00830     Inputs:     TheType - indicates import / export / import & export
00831 
00832                 ClaimType - specifies the text type that this mapping will claim from the
00833                 windows clipboard - that is, create 3 of these mappings, specifying
00834                 CF_TEXT, CF_UNICODETEXT, and CF_OEMTEXT, and they will all ask the
00835                 clipboard for UNICODE text when they actually go to import. This allows
00836                 us to detect the 3 implicitly-converted clipboard formats, and map them
00837                 all to UNICODE, i.e. use the UNICODE mapping for all 3 available formats.
00838                 If ClaimType == 0, UNICODE is assumed
00839 
00840     Purpose:    Constructs a clipboard mapping with the ExternalClipboard
00841                 manager. This mapping info describes a filter which is able to import
00842                 data from or export data to a windows clipboard in some way.
00843 
00844     Notes:      DON'T call the constructor - call CreateAndRegister
00845 
00846     SeeAlso:    BodgeTextClipMap::CreateAndRegister
00847 
00848 ********************************************************************************************/
00849 
00850 BodgeTextClipMap::BodgeTextClipMap(ClipboardMappingType TheType, UINT32 ClaimType)
00851                 : ClipboardMapping(TheType, NULL, InternalClipboardFormat(CLIPTYPE_TEXT),
00852                                     CF_TEXT, 50)
00853 {
00854     if (ClaimType != 0)
00855         ExternalDataType = ClaimType;
00856 }
00857 
00858 
00859 
00860 /********************************************************************************************
00861 
00862 >   static void BodgeTextClipMap::CreateAndRegister(ClipboardMappingType TheType, UINT32 ClaimType = 0)
00863 
00864     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00865     Created:    16/4/95
00866 
00867     Inputs:     TheType - indicates import / export / import & export
00868 
00869                 ClaimType - specifies the text type that this mapping will claim from the
00870                 windows clipboard - that is, create 3 of these mappings, specifying
00871                 CF_TEXT, CF_UNICODETEXT, and CF_OEMTEXT, and they will all ask the
00872                 clipboard for UNICODE text when they actually go to import. This allows
00873                 us to detect the 3 implicitly-converted clipboard formats, and map them
00874                 all to UNICODE, i.e. use the UNICODE mapping for all 3 available formats.
00875                 If ClaimType == 0, UNICODE is assumed
00876 
00877     Purpose:    Constructs and registers a clipboard mapping with the ExternalClipboard
00878                 manager. This mapping info describes a filter which is able to import
00879                 data from or export data to a windows clipboard in some way.
00880 
00881 ********************************************************************************************/
00882 
00883 void BodgeTextClipMap::CreateAndRegister(ClipboardMappingType TheType, UINT32 ClaimType)
00884 {
00885     BodgeTextClipMap *Mapping = new BodgeTextClipMap(TheType, ClaimType);
00886     if (Mapping == NULL)
00887         InformError();
00888     else
00889         ExternalClipboard::RegisterDataType(Mapping);
00890 }
00891 
00892 
00893 
00894 /********************************************************************************************
00895 >   virtual BOOL BodgeTextClipMap::HandleImport(SelOperation *Caller, HANDLE ClipboardData,
00896                                                 InternalClipboard *Dest)
00897     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00898     Created:    20/4/95
00899     Inputs:     Caller - The operation within which this method is being called
00900                 ClipboardData - The result of calling GetClipboardData for your datatype
00901                 Dest - The InternalClipboard (document) to import the data into.
00902     Returns:    TRUE for success
00903     Purpose:    Calls the parent filter as appropriate to import the given data from
00904                 the external clipboard.
00905                 This bodge mapping for text scans the docuemnt tree for text chars and
00906                 strips them out by hand. Styles and suchlike are lost. It's a bodge.
00907 ********************************************************************************************/
00908 
00909 BOOL BodgeTextClipMap::HandleImport(SelOperation *Caller, HANDLE ClipboardData, InternalClipboard *Dest)
00910 {
00911     char *buff=(char*)GlobalLock(ClipboardData);
00912     if (buff != NULL && buff[0] != 0)
00913     {
00914         // position arbitarily on clipboard - when pasted the clip contents are centered anyway
00915         TextStory* TheStory=TextStory::CreateFromChars(DocCoord(100,100), buff, NULL,
00916                                                        InternalClipboard::Instance(), NULL, TRUE);
00917 
00918         // Unlock the clipboard data, as we won't need it again
00919         GlobalUnlock(ClipboardData);
00920 
00921         if (TheStory!=NULL)
00922         {
00923             // OK, attach the new story to the clipboard document
00924             TheStory->AttachNode(InternalClipboard::GetInsertionLayer(), LASTCHILD);
00925             TheStory->NormaliseAttributes();
00926 
00927             // And make it reformat itself properly
00928             TheStory->FormatAndChildren(NULL,FALSE,FALSE);
00929             return(TRUE);
00930         }
00931 
00932         // We failed (no text story), so report and ensure the clipboard is 'clean'
00933         InformError();
00934         InternalClipboard::Clear();
00935     }
00936 
00937     // We failed
00938     return(FALSE);
00939 }
00940 
00941 //BOOL BodgeTextClipMap::HandleImport(SelOperation *Caller,
00942 //                                  HANDLE ClipboardData, InternalClipboard *Dest)
00943 //{
00944 //  char *buff = (char *) GlobalLock(ClipboardData);
00945 //  if (buff != NULL && buff[0] != 0)
00946 //  {
00947 //      DWORD Index = 0;
00948 //  
00949 //      TextStory *pStory = new TextStory(Dest->GetInsertionLayer(), LASTCHILD);
00950 //      if (pStory == NULL)
00951 //          goto Abort;
00952 //  
00953 //      // Lob in some default attributes (black fill, no line colour, line width = 250
00954 //      Node *pNode;
00955 //      FlatFillAttribute *pAttrFill = new FlatFillAttribute(DocColour(COLOUR_BLACK));
00956 //      if (pAttrFill == NULL)
00957 //          goto Abort;
00958 //      pNode = pAttrFill->MakeNode();
00959 //      if (pNode == NULL)
00960 //          goto Abort;
00961 //      pNode->AttachNode(pStory, LASTCHILD, FALSE);
00962 //  
00963 //      StrokeColourAttribute *pAttrLine = new StrokeColourAttribute(DocColour(COLOUR_TRANS));
00964 //      if (pAttrLine == NULL)
00965 //          goto Abort;
00966 //      pNode = pAttrLine->MakeNode();
00967 //      if (pNode == NULL)
00968 //          goto Abort;
00969 //      pNode->AttachNode(pStory, LASTCHILD, FALSE);
00970 //
00971 //      LineWidthAttribute *pAttrLineWidth = new LineWidthAttribute(250);
00972 //      if (pAttrLineWidth == NULL)
00973 //          goto Abort;
00974 //      pNode = pAttrLineWidth->MakeNode();
00975 //      if (pNode == NULL)
00976 //          goto Abort;
00977 //      pNode->AttachNode(pStory, LASTCHILD, FALSE);
00978 //  
00979 //      // Set the top left position for the text area - this doesn't matter because
00980 //      // the absolute position on the clipboard is ignored when we paste
00981 //      Matrix StoryMatrix(1000, 1000);
00982 //      pStory->SetStoryMatrix(StoryMatrix);
00983 //  
00984 //      TextLine *pLine = new TextLine(pStory, LASTCHILD);
00985 //      if (pLine == NULL)
00986 //          goto Abort;
00987 //  
00988 //      Node *pChar = NULL;
00989 //
00990 //      while(buff[Index] != 0)
00991 //      {
00992 //          if (buff[Index] == 0x0D)
00993 //          {
00994 //              if (buff[Index+1] == 0x0A)  // Skip LF if it's a CRLF pair
00995 //                  Index++;
00996 //  
00997 //              pChar = new EOLNode(pLine, LASTCHILD);
00998 //              if (pChar == NULL)
00999 //                  goto Abort;
01000 //  
01001 //              // Make sure if this is the last char exported, we don't leave
01002 //              // this next TextLine without an EOLNode in it!
01003 //              pChar = NULL;
01004 //
01005 //              pLine = new TextLine(pStory, LASTCHILD);
01006 //              if (pLine == NULL)
01007 //                  goto Abort;
01008 //          }
01009 //          else
01010 //          {
01011 //              // Ignore control chars like tabs and suchlike for now
01012 //              if (buff[Index] > 31)
01013 //              {
01014 //                  pChar = new TextChar(pLine, LASTCHILD, (WCHAR) buff[Index]);
01015 //                  if (pChar == NULL)
01016 //                      goto Abort;
01017 //              }
01018 //          }
01019 //          
01020 //          Index++;
01021 //      }
01022 //  
01023 //      if (pChar == NULL || !pChar->IsKindOf(CC_RUNTIME_CLASS(EOLNode)))
01024 //      {
01025 //          // no terminating newline, so add one
01026 //          pChar = new EOLNode(pLine, LASTCHILD);
01027 //          if (pChar == NULL)
01028 //              goto Abort;
01029 //      }
01030 //  
01031 //      // And lob a caret in, 'cos it seems to get upset if this isn't in there!
01032 //      pChar = new CaretNode(pChar, PREV);
01033 //      if (pChar == NULL)
01034 //          goto Abort;
01035 //  
01036 //      // And finally, format the text, else the chars all stack on top of each other!
01037 //      pStory->FormatAndChildren();
01038 //
01039 //      GlobalUnlock(ClipboardData);
01040 //      return(TRUE);
01041 //  }
01042 //
01043 //  return(FALSE);
01044 //
01045 //Abort:
01046 //  ERROR2RAW("Text import failed, probably due to lack of memory");
01047 //  InformError();
01048 //
01049 //  GlobalUnlock(ClipboardData);
01050 //  Dest->ClearClipboard(); // We failed, so ensure the doc is wiped
01051 //  return(FALSE);
01052 //}
01053 
01054         
01055 /********************************************************************************************
01056 
01057 >   virtual BOOL BodgeTextClipMap::HandleExport(Operation *Caller,
01058                                                 InternalClipboard *Source)
01059 
01060     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01061     Created:    20/4/95
01062 
01063     Inputs:     Caller - the operation within which this method is being called
01064                 Source - the internal clipboard (document) to be exported
01065 
01066     Returns:    NULL (if it failed), or a windows handle of the data to be placed on
01067                 the clipboard.
01068 
01069     Purpose:    Invokes this mapping for exporting
01070                 This takes the document tree of Source, and exports it to the external
01071                 (windows) clipboard.
01072 
01073                 This bodge mapping for text scans the docuemnt tree for text chars and
01074                 strips them out by hand. Styles and suchlike are lost. It's a bodge.
01075 
01076     Notes:      The returned handle should be the thing you'd pass to SetClipboardData
01077                 if you were dealing with it directly. You must adhere to all the Windows
01078                 rules for this - i.e. a global data block, unlocked, etc etc.
01079 
01080 ********************************************************************************************/
01081 
01082 HANDLE BodgeTextClipMap::HandleExport(Operation *Caller, InternalClipboard *Source)
01083 {
01084     const DWORD Increment = 1024 * sizeof(char);
01085     DWORD CurrentSize   = 0;
01086     DWORD MaxSize       = Increment;
01087 
01088 #if (_OLE_VER >= 0x200)
01089 
01090     // If necessary allocate the memory.
01091     BOOL fDidAlloc = FALSE;
01092     HANDLE hGlobalMem = m_hMem;
01093     if (hGlobalMem)
01094     {
01095         // We have some already.  Set the size.
01096         MaxSize = m_cbMemSize;
01097     }
01098     else
01099     {
01100         // We don't have any, so try to allocate and remember that we did so.
01101         hGlobalMem = m_hMem = GlobalAlloc(GHND, MaxSize);
01102         if (!hGlobalMem) return 0;
01103         fDidAlloc = TRUE;
01104     }
01105 
01106 #else
01107 
01108     // Allocate a block of global memory to store the text
01109     HANDLE hGlobalMem = GlobalAlloc(GHND, MaxSize);
01110 
01111     if (hGlobalMem == NULL)
01112         return(NULL);
01113 
01114 #endif
01115 
01116     // Get a UNICODE text buffer
01117     char* buff = (char*) GlobalLock(hGlobalMem);
01118     if (buff == NULL)
01119     {
01120         return(NULL);
01121     }
01122 
01123     // Scan the entire document tree, and lob every TextChar we find into the export buffer
01124     // NOTE that the Global{Re}Alloc zeros memory, so we don't need to worry about 0-termination.
01125     Node *pSubtree = InternalClipboard::GetInsertionLayer();
01126     Node *pNode = pSubtree->FindFirstDepthFirst();
01127     while (pNode != NULL)
01128     {
01129         if (pNode->IsKindOf(CC_RUNTIME_CLASS(TextChar)) || pNode->IsKindOf(CC_RUNTIME_CLASS(EOLNode)))
01130         {
01131             if (pNode->IsKindOf(CC_RUNTIME_CLASS(TextChar)))
01132             {
01133                 UINT32 ComposedChar = UnicodeManager::UnicodeToMultiByte(((TextChar *) pNode)->GetUnicodeValue());
01134                 BYTE LeadByte = 0;
01135                 BYTE TrailByte = 0;
01136                 UnicodeManager::DecomposeMultiBytes(ComposedChar, &LeadByte, &TrailByte);
01137 
01138                 if (LeadByte != 0)
01139                     buff[CurrentSize++] = LeadByte;
01140 
01141                 buff[CurrentSize++] = TrailByte;
01142             }
01143             else
01144             {
01145                 if (!((EOLNode*)pNode)->IsVirtual())
01146                 {
01147                     buff[CurrentSize++] = (char) 0x0D;      // CRLF - newline
01148                     buff[CurrentSize++] = (char) 0x0A;
01149                 }
01150             }
01151 
01152             // Check if we've overrun the buffer - if so, we need to make the buffer bigger
01153             // (Allow 3 entries at the end (1 to guarantee we have a zero terminator, and 2 more
01154             // to allow room to fit the 2-char newline sequence in!)
01155             if ( (CurrentSize * sizeof(char)) >= MaxSize - 3)
01156             {
01157             #if (_OLE_VER >= 0x200)
01158                 // If we didn't allocate the block then we can't resize it.
01159                 if (!fDidAlloc) return 0;
01160                 m_hMem = 0;
01161             #endif
01162                 
01163                 GlobalUnlock(hGlobalMem);
01164 
01165                 MaxSize += Increment;
01166                 HANDLE hNewMem = GlobalReAlloc(hGlobalMem, MaxSize, GHND);
01167                 if (hNewMem == NULL)
01168                 {
01169                     GlobalFree(hGlobalMem);
01170                     return(NULL);
01171                 }
01172 
01173                 hGlobalMem = hNewMem;
01174                 buff = (char *)GlobalLock(hGlobalMem);
01175 
01176                 if (buff == NULL)
01177                 {
01178                     GlobalFree(hGlobalMem);
01179                     return(NULL);
01180                 }
01181 
01182             #if (_OLE_VER >= 0x200)
01183                 // Remember this block.
01184                 m_hMem = hNewMem;
01185             #endif
01186             }
01187         }
01188         pNode = pNode->FindNextDepthFirst(pSubtree);
01189     }
01190 
01191     // We must unlock the block before giving it to the clipboard
01192     GlobalUnlock(hGlobalMem);
01193 
01194     return(hGlobalMem);
01195 }
01196 
01197 
01198 
01199 
01200 
01201 
01202 
01203 
01204 
01205 
01206 BodgeUnicodeClipMap::BodgeUnicodeClipMap()
01207 {
01208     ERROR3("Please don't press that button again");
01209 }
01210 
01211 
01212 /********************************************************************************************
01213 
01214 >   BodgeUnicodeClipMap::BodgeUnicodeClipMap(ClipboardMappingType TheType, UINT32 ClaimType = 0)
01215     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01216     Created:    16/4/95
01217 
01218     Inputs:     TheType - indicates import / export / import & export
01219 
01220                 ClaimType - specifies the text type that this mapping will claim from the
01221                 windows clipboard - that is, create 3 of these mappings, specifying
01222                 CF_TEXT, CF_UNICODETEXT, and CF_OEMTEXT, and they will all ask the
01223                 clipboard for UNICODE text when they actually go to import. This allows
01224                 us to detect the 3 implicitly-converted clipboard formats, and map them
01225                 all to UNICODE, i.e. use the UNICODE mapping for all 3 available formats.
01226                 If ClaimType == 0, UNICODE is assumed
01227 
01228     Purpose:    Constructs a clipboard mapping with the ExternalClipboard
01229                 manager. This mapping info describes a filter which is able to import
01230                 data from or export data to a windows clipboard in some way.
01231 
01232     Notes:      DON'T call the constructor - call CreateAndRegister
01233 
01234     SeeAlso:    BodgeUnicodeClipMap::CreateAndRegister
01235 
01236 ********************************************************************************************/
01237 
01238 BodgeUnicodeClipMap::BodgeUnicodeClipMap(ClipboardMappingType TheType, UINT32 ClaimType)
01239                 : ClipboardMapping(TheType, NULL, InternalClipboardFormat(CLIPTYPE_TEXT),
01240                                     CF_UNICODETEXT, 55)
01241 {
01242     if (ClaimType != 0)
01243         ExternalDataType = ClaimType;
01244 }
01245 
01246 
01247 
01248 /********************************************************************************************
01249 
01250 >   static void BodgeUnicodeClipMap::CreateAndRegister(ClipboardMappingType TheType, UINT32 ClaimType = 0)
01251 
01252     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01253     Created:    16/4/95
01254 
01255     Inputs:     TheType - indicates import / export / import & export
01256 
01257                 ClaimType - specifies the text type that this mapping will claim from the
01258                 windows clipboard - that is, create 3 of these mappings, specifying
01259                 CF_TEXT, CF_UNICODETEXT, and CF_OEMTEXT, and they will all ask the
01260                 clipboard for UNICODE text when they actually go to import. This allows
01261                 us to detect the 3 implicitly-converted clipboard formats, and map them
01262                 all to UNICODE, i.e. use the UNICODE mapping for all 3 available formats.
01263                 If ClaimType == 0, UNICODE is assumed
01264 
01265     Purpose:    Constructs and registers a clipboard mapping with the ExternalClipboard
01266                 manager. This mapping info describes a filter which is able to import
01267                 data from or export data to a windows clipboard in some way.
01268 
01269 ********************************************************************************************/
01270 
01271 void BodgeUnicodeClipMap::CreateAndRegister(ClipboardMappingType TheType, UINT32 ClaimType)
01272 {
01273     BodgeUnicodeClipMap *Mapping = new BodgeUnicodeClipMap(TheType, ClaimType);
01274     if (Mapping == NULL)
01275         InformError();
01276     else
01277         ExternalClipboard::RegisterDataType(Mapping);
01278 }
01279 
01280 
01281 
01282 /********************************************************************************************
01283 >   virtual BOOL BodgeUnicodeClipMap::HandleImport(SelOperation *Caller, HANDLE ClipboardData,
01284                                                 InternalClipboard *Dest)
01285     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01286     Created:    20/4/95
01287     Inputs:     Caller - The operation within which this method is being called
01288                 ClipboardData - The result of calling GetClipboardData for your datatype
01289                 Dest - The InternalClipboard (document) to import the data into.
01290     Returns:    TRUE for success
01291     Purpose:    Calls the parent filter as appropriate to import the given data from
01292                 the external clipboard.
01293                 This bodge mapping for text scans the docuemnt tree for text chars and
01294                 strips them out by hand. Styles and suchlike are lost. It's a bodge.
01295 ********************************************************************************************/
01296 
01297 BOOL BodgeUnicodeClipMap::HandleImport(SelOperation *Caller, HANDLE ClipboardData, InternalClipboard *Dest)
01298 {
01299     WCHAR *buff=(WCHAR*)GlobalLock(ClipboardData);
01300     if (buff != NULL && buff[0] != 0)
01301     {
01302         // position arbitarily on clipboard - when pasted the clip contents are centered anyway
01303         TextStory* TheStory=TextStory::CreateFromChars(DocCoord(100,100), NULL, buff,
01304                                                        InternalClipboard::Instance(), NULL, TRUE);
01305 
01306         // Unlock the clipboard data, as we won't need it again
01307         GlobalUnlock(ClipboardData);
01308 
01309         if (TheStory!=NULL)
01310         {
01311             // OK, attach the new story to the clipboard document
01312             TheStory->AttachNode(InternalClipboard::GetInsertionLayer(), LASTCHILD);
01313             TheStory->NormaliseAttributes();
01314 
01315             // And make it reformat itself properly
01316             TheStory->FormatAndChildren(NULL,FALSE,FALSE);
01317             return(TRUE);
01318         }
01319 
01320         // We failed (no text story), so report and ensure the clipboard is 'clean'
01321         InformError();
01322         InternalClipboard::Clear();
01323     }
01324 
01325     // We failed
01326     return(FALSE);
01327 }
01328 
01329 
01330 //BOOL BodgeUnicodeClipMap::HandleImport(SelOperation *Caller, HANDLE ClipboardData, InternalClipboard *Dest)
01331 //{
01332 //  WCHAR *buff = (WCHAR *) GlobalLock(ClipboardData);
01333 //  if (buff != NULL && buff[0] != 0)
01334 //  {
01335 //      DWORD Index = 0;
01336 //
01337 //      TextStory *pStory = new TextStory(Dest->GetInsertionLayer(), LASTCHILD);
01338 //      if (pStory == NULL)
01339 //          goto Abort;
01340 //
01341 //      // Lob in some default attributes (black fill, no line colour, line width = 250
01342 //      Node *pNode;
01343 //      FlatFillAttribute *pAttrFill = new FlatFillAttribute(DocColour(COLOUR_BLACK));
01344 //      if (pAttrFill == NULL)
01345 //          goto Abort;
01346 //      pNode = pAttrFill->MakeNode();
01347 //      if (pNode == NULL)
01348 //          goto Abort;
01349 //      pNode->AttachNode(pStory, LASTCHILD, FALSE);
01350 //
01351 //      StrokeColourAttribute *pAttrLine = new StrokeColourAttribute(DocColour(COLOUR_TRANS));
01352 //      if (pAttrLine == NULL)
01353 //          goto Abort;
01354 //      pNode = pAttrLine->MakeNode();
01355