natclipm.cpp

Go to the documentation of this file.
00001 // $Id: natclipm.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 // clipboard mapping for native files
00099 
00100 #include "camtypes.h"
00101 
00102 #include "clipext.h"
00103 #include "native.h"
00104 #include "natclipm.h"
00105 
00106 #include "clipint.h"
00107 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 #include "layer.h"
00110 
00111 CC_IMPLEMENT_DYNCREATE(NativeClipMap, ClipboardMapping)
00112 
00113 
00114 /********************************************************************************************
00115 
00116 >   NativeClipMap::NativeClipMap(ClipboardMappingType TheType, UINT32 ClaimType = 0)
00117     
00118     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00119     Created:    12/09/96
00120 
00121     Inputs:     TheType - indicates import / export / import & export
00122 
00123                 ClaimType - specifies the text type that this mapping will claim from the
00124                 windows clipboard - that is, create 3 of these mappings, specifying
00125                 CF_TEXT, CF_UNICODETEXT, and CF_OEMTEXT, and they will all ask the
00126                 clipboard for UNICODE text when they actually go to import. This allows
00127                 us to detect the 3 implicitly-converted clipboard formats, and map them
00128                 all to UNICODE, i.e. use the UNICODE mapping for all 3 available formats.
00129                 If ClaimType == 0, UNICODE is assumed
00130 
00131     Purpose:    Constructs a clipboard mapping with the ExternalClipboard
00132                 manager. This mapping info describes a filter which is able to import
00133                 data from or export data to a windows clipboard in some way.
00134 
00135     Notes:      DON'T call the constructor - call CreateAndRegister
00136 
00137     SeeAlso:    BodgeTextClipMap::CreateAndRegister
00138 
00139 ********************************************************************************************/
00140 
00141 NativeClipMap::NativeClipMap(ClipboardMappingType TheType, UINT32 ClaimType)
00142                 : ClipboardMapping(TheType, NULL, InternalClipboardFormat(CLIPTYPE_VECTOR),
00143                     ClaimType, 130)
00144 {
00145     if (ClaimType != 0)
00146         ExternalDataType = ClaimType;
00147 }
00148 
00149 NativeClipMap::NativeClipMap()
00150 {
00151     ERROR3("Please don't press that button again");
00152 }
00153 
00154 /********************************************************************************************
00155 
00156 >   static void NativeClipMap::CreateAndRegister(ClipboardMappingType TheType, UINT32 ClaimType = 0)
00157 
00158     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00159     Created:    12/09/96
00160 
00161     Inputs:     TheType - indicates import / export / import & export
00162 
00163                 ClaimType - specifies the text type that this mapping will claim from the
00164 
00165     Purpose:    Constructs and registers a clipboard mapping with the ExternalClipboard
00166                 manager. This mapping info describes a filter which is able to import
00167                 data from or export data to a windows clipboard in some way.
00168 
00169 ********************************************************************************************/
00170 
00171 void NativeClipMap::CreateAndRegister(ClipboardMappingType TheType, UINT32 ClaimType)
00172 {
00173     NativeClipMap *Mapping = new NativeClipMap(TheType, ClaimType);
00174     if (Mapping == NULL)
00175         InformError();
00176     else
00177         ExternalClipboard::RegisterDataType(Mapping);
00178 }
00179 
00180 /********************************************************************************************
00181 
00182 >   virtual BOOL NativeClipMap::HandleImport(SelOperation *Caller, HANDLE ClipboardData,
00183                                                 InternalClipboard *Dest)
00184     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00185     Created:    12/09/96
00186     Inputs:     Caller - The operation within which this method is being called
00187                 ClipboardData - The result of calling GetClipboardData for your datatype
00188                 Dest - The InternalClipboard (document) to import the data into.
00189     Returns:    TRUE for success
00190     Purpose:    Calls the parent filter as appropriate to import the given data from
00191                 the external clipboard.
00192 
00193 ********************************************************************************************/
00194 
00195 BOOL NativeClipMap::HandleImport(SelOperation *Caller, HANDLE ClipboardData, InternalClipboard *Dest)
00196 {
00197 /*
00198     Ben Summers wrote this on 12/9/96:
00199 
00200         The following code does work as far as getting data off the clipboard is concerned.
00201         
00202         However, it can't work as it should as there are are fundamental problems with the
00203         clipboard document and the way the native file format is imported.
00204 
00205         The native filter ignores the old system for importing data, and grafts the new
00206         subtree into a document tree all by it's very own. It always imports with layers,
00207         and this shafts the internal clipboard which expects everything to go onto a
00208         special layer it creates, preferably getting the Op to do the attaching.
00209 
00210         It's also possible that the Op can get a bit confused with the nodes going
00211         directly into the tree, but this could be a incorrect rumour.
00212 
00213         It could be done with some major bodging, but it has been decided not to do this.
00214 
00215         So we've got an export only thingy for OLE.
00216 
00217         It's stuff like this which makes me think that programming is in fact a
00218         particularly bad career choice. Why can't we just sit down and do lots
00219         of mathematics all day?
00220 
00221         We could also sit down more often for tea and biscuits, be nice to
00222         each other, design systems without letting spurious unjustified religious
00223         ideas from assembly language ideas hang over into OO programs, and maybe
00224         even stop inventing the wheel.
00225 
00226         Maybe then we'd all be happier, and Camelot smaller, neater and possible
00227         to maintain.
00228 
00229   Markn wrote this on 9/10/96:
00230         
00231         This func can now import native files safely using the current paste system by doing
00232         a bit of housekeeping on the doc before returning, ensuring that all the objects on the 
00233         clipboard are pastable. This housekeeping is done in RemoveMultipleLayers().
00234 
00235         It is a little bit of a bodge, but it's not horrendous.  It gives the same level of pasting you
00236         get when you copy objects from one doc, and paste into another doc, where both docs live in the
00237         same instance of Camelot.
00238 
00239         I agree with Ben that we should have tea and biscuits more often.  But do we have to be nice
00240         to each other as well?
00241 
00242 ---------------------------- */
00243 
00244     BOOL ok = FALSE;
00245 
00246     // Get a scratch file - if TMP isn't set, this will try for c:\temp.
00247     // The filename will have XS as a prefix
00248     char *tempname = GetTempFileName();
00249     if (tempname == NULL)
00250     {
00251         ERROR3("Couldn't get a temp filename");
00252         return(FALSE);
00253     }
00254 
00255     void *pMem = GlobalLock(ClipboardData);
00256     ok = (pMem != NULL);
00257 
00258     // you may not want to stop importing with layers -- but only
00259     // do this if you're not importing into the InternalClipboard
00260     // document -- it's not too happy if you bung layers in it
00261     BOOL Layers = Filter::ImportWithLayers;
00262     Filter::ImportWithLayers = FALSE;
00263 
00264     // pFilter is a class var which is the filter which will be used
00265     // for importing this file
00266     pFilter = 0;
00267 
00268     // find the cam native filter...
00269     Filter* pSearchFilter = Filter::GetFirst();
00270     while (pSearchFilter != NULL)
00271     {
00272         // is this the right filter?
00273         if(pSearchFilter->FilterID == FILTERID_NATIVE)
00274         {
00275             // got it!
00276             pFilter = pSearchFilter;
00277             break;
00278         }
00279 
00280         // next!
00281         pSearchFilter = Filter::GetNext(pSearchFilter);
00282     }
00283 
00284     TRACEUSER( "Ben", _T("NativeClipMap prospective native filter is 0x%x\n"), pFilter);            
00285 
00286     // got one?
00287     ok = (pFilter != NULL);
00288 
00289     CCDiskFile File;
00290     if(ok)
00291     {
00292         // get a file and write to it
00293         PathName pathname(tempname);
00294         if(!File.open(pathname, (ios::out | ios::binary)))
00295             ok = FALSE;     // error!
00296     }
00297 
00298     // bung out the data
00299     if(ok)
00300     {
00301         File.write(pMem, GlobalSize(ClipboardData));
00302 
00303         File.close();
00304     }
00305 
00306     // unlock the block of data
00307     GlobalUnlock(ClipboardData);
00308 
00309     // do our funky stuff with the large lump of stuff
00310     if(ok)
00311     {
00312         ok = ImportFromTempFile(tempname, Caller, Dest);
00313     }
00314 
00315     // we don't like temp files which aren't needed any more
00316     RemoveTempFile();
00317 
00318     // Make sure all the objects in the clipboard live on the first layer, so that paste works correctly
00319     ok = RemoveMultipleLayers(Dest);
00320 
00321     // unset our pointer to the filter
00322     pFilter = NULL;
00323 
00324     // we don't want to screw things up with importing layers, because that would be bad
00325     Filter::ImportWithLayers = Layers;
00326 
00327     return(ok);
00328 }
00329 
00330 /********************************************************************************************
00331 
00332 >   BOOL NativeClipMap::RemoveMultipleLayers(InternalClipboard* pImportDoc)
00333 
00334     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00335     Created:    9/10/96
00336     Inputs:     pImportDoc = ptr to the clipboard doc that received the imported file.
00337     Returns:    TRUE if ok, FALSE otherwise
00338     Purpose:    This ensures that there is only one layer after an import into the given clipboard doc.
00339                 Objects that live in any extra layers are moved to the first layer, and the extra layers
00340                 are deleted.
00341                 
00342                 This function is used to get around the limitation of the current pasting system.
00343                 Pasting assumes that all the objects live on the first layer in the clipboard doc.
00344                 This function ensures that the doc is in a state that allows its entire contents to
00345                 be pasted by the paste op.
00346 
00347 ********************************************************************************************/
00348 
00349 BOOL NativeClipMap::RemoveMultipleLayers(InternalClipboard* pImportDoc)
00350 {
00351     ERROR2IF(pImportDoc == NULL,FALSE,"NULL import doc ptr");
00352 
00353     // We must have a spread.  If not, error
00354     Spread* pSpread = pImportDoc->FindFirstSpread();
00355     if (pSpread == NULL)
00356         return FALSE;
00357 
00358     // There must be a first layer.  If not error
00359     Layer* pFirstLayer = pSpread->FindFirstLayer();
00360     if (pFirstLayer == NULL)
00361         return FALSE;
00362 
00363     // Likewise, there must be a last layer.
00364     Layer* pLastLayer = pSpread->FindLastLayer();
00365     if (pLastLayer == NULL)
00366         return FALSE;
00367 
00368     // If there isn't a layer after the first layer (i.e. there's only one layer), 
00369     // then return now, as there's nothing to do
00370     Layer* pLayer = pFirstLayer->FindNextLayer();
00371     if (pLayer == NULL)
00372         return TRUE;
00373 
00374     // If the layer after the first layer is also the last layer, then we have only two layers.
00375     // When there's only two layers, don't bother grouping the objects from the second layer when
00376     // moving them onto the first layer.
00377     BOOL GroupLayerContents = (pLayer != pLastLayer);
00378 
00379     while (pLayer != NULL)
00380     {
00381         Node* pContextNode = NULL;
00382 
00383         // If moving the contents of the layer into a group, create a group, attach it into the 
00384         // first layer, and make the group the context node
00385         if (GroupLayerContents)
00386         {
00387             pContextNode = new NodeGroup;
00388             if (pContextNode == NULL)       // If unable to make a group, fail
00389                 return FALSE;
00390 
00391             pContextNode->AttachNode(pFirstLayer,LASTCHILD);
00392         }
00393         else
00394             pContextNode = pFirstLayer;     // Otherwise just make the first layer the context node
00395 
00396         if (pContextNode != NULL)
00397         {
00398             Node* pNode = pLayer->FindFirstChild();
00399             while (pNode != NULL)
00400             {
00401                 // Move each child of the layer as a last child of the context node
00402                 Node* pNext = pNode->FindNext();
00403                 pNode->MoveNode(pContextNode,LASTCHILD);
00404                 pNode = pNext;
00405             }
00406         }
00407 
00408         // This layer is an extra layer that is now empty, so make it the layer to delete
00409         Layer* pLayerToDelete = pLayer;
00410         // First, invalidate the bounding rect
00411         pLayerToDelete->InvalidateBoundingRect();
00412 
00413         // Find the next layer before we delete the current one
00414         pLayer = pLayer->FindNextLayer();
00415 
00416         // Delete that empty layer
00417         pLayerToDelete->CascadeDelete();
00418         delete pLayerToDelete;
00419     }
00420 
00421     // Lastly, invalidate the bounding rect of the layer where all the objects are now
00422     pFirstLayer->InvalidateBoundingRect();
00423 
00424     return TRUE;
00425 }
00426 
00427 /********************************************************************************************
00428 
00429 >   virtual BOOL NativeClipMap::HandleExport(Operation *Caller,
00430                                                 InternalClipboard *Source)
00431 
00432     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00433     Created:    12/09/96
00434 
00435     Inputs:     Caller - the operation within which this method is being called
00436                 Source - the internal clipboard (document) to be exported
00437 
00438     Returns:    NULL (if it failed), or a windows handle of the data to be placed on
00439                 the clipboard.
00440 
00441     Purpose:    Invokes this mapping for exporting
00442                 This takes the document tree of Source, and exports it to the external
00443                 (windows) clipboard. Usually this just involves calling Filter::DoExport
00444                 for the parent filter, and then returning the handle to the global memory
00445                 block to be placed onto the external clipboard.
00446 
00447     Notes:      The returned handle should be the thing you'd pass to SetClipboardData
00448                 if you were dealing with it directly. You must adhere to all the Windows
00449                 rules for this - i.e. a global data block, unlocked, etc etc.
00450 
00451 ********************************************************************************************/
00452 
00453 HANDLE NativeClipMap::HandleExport(Operation *Caller, InternalClipboard *Source)
00454 {
00455     // get a temporary file name from the base class to use as 
00456     // something to export files into it -- this is only one
00457     // possible way of getting a CCLexFile derivative to
00458     // put the exported data into.
00459     char *tempname = GetTempFileName();
00460     if (tempname == NULL)
00461     {
00462         ERROR3("Couldn't get a temp filename");
00463         return(FALSE);
00464     }
00465 
00466     // make a new disk file of this name
00467     CCDiskFile File;
00468     PathName pathname(tempname);
00469     if(!File.open(pathname, (ios::in | ios::out | ios::binary)))
00470         return 0;       // error!
00471     
00472     // get a filter to export the thingy to
00473     // we create a new filter to use rather than scanning for the
00474     // one in the filter list because it's basically just that
00475     // little bit easier
00476     CamelotNativeFilter *pFilter = new CamelotNativeFilter;
00477     BOOL ok = (pFilter != NULL);
00478 
00479     if(ok)
00480     {
00481         // export to the file -- the filter will realise it's exporting
00482         // from a clipboard, so won't get destressed and export a preview
00483         // bitmap, which won't work as we don't have an OilDoc for
00484         // the InternalClipboard documents
00485         ok = pFilter->DoExport(Caller, &File, &pathname, (Document *)Source, FALSE);
00486     }
00487 
00488     // delete the filter, we don't need it any more
00489     delete pFilter;
00490     pFilter = NULL;
00491 
00492     // this is scary Windows stuff. We're allocating a chunk of memory we
00493     // can throw at the clipboard, and we're going to read the temporary
00494     // file into it.
00495     void* pMem;
00496     INT32 FileSize;
00497     HANDLE hGlobalMem;
00498 
00499     if (ok)
00500     {
00501         // find out how big the file is
00502         FileSize = File.Size();
00503 
00504     #if (_OLE_VER >= 0x200)
00505     
00506         // Is memory already allocated?
00507         if ((hGlobalMem = m_hMem) != 0)
00508         {
00509             // Is the file too big?
00510             if (UINT32(FileSize) > m_cbMemSize) return 0;
00511         }
00512         else
00513         {
00514             // No.  Allocate some.
00515             hGlobalMem = m_hMem = GlobalAlloc(GHND, FileSize);
00516         }
00517 
00518     #else
00519         
00520         // copy the file into the global block
00521         pMem = GlobalLock(hGlobalMem);
00522     
00523     #endif
00524 
00525         // Lock the block.
00526         pMem = GlobalLock(hGlobalMem);
00527         ok = (pMem != 0);
00528     }
00529 
00530     if (ok)
00531     {
00532         // seek to beginning of file
00533         File.seekIn(0);
00534 
00535         // load data..
00536         File.read(pMem, FileSize);
00537     }
00538 
00539     // close the file
00540     if(File.isOpen()) File.close();
00541 
00542     // get rid of the temp file
00543     RemoveTempFile();
00544 
00545     // We must unlock the block before giving it to the clipboard
00546     GlobalUnlock(hGlobalMem);
00547 
00548     // and there we go, one block of memory with a native file sans preview bitmap
00549     // ready to be splatted onto the windows clipboard
00550     return hGlobalMem;
00551 }
00552 
00553 
00554 

Generated on Sat Nov 10 03:48:40 2007 for Camelot by  doxygen 1.4.4