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