00001 // $Id: clipint.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 /* 00099 //*/ 00100 // Camelot's Internal clipboard 00101 00102 00103 #include "camtypes.h" 00104 00105 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00106 #include "chapter.h" 00107 //#include "clipext.h" // External (oil) clipboard stuff 00108 #include "clipint.h" // Internal clipboard stuff 00109 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00110 #include "layer.h" 00111 //#include "simon.h" 00112 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00113 #include "colourix.h" 00114 #include "collist.h" 00115 #include "cliptype.h" 00116 00117 #include "camdoc.h" 00118 #include "optspage.h" // for PageResizeInfo page settings 00119 00120 #include <math.h> // for floor() 00121 00122 #include "nodetxts.h" //To add text to the clipboard 00123 #include "nodedoc.h" 00124 //#include "srvritem.h" //for justin's clever "add-text-to-the-clipboard" function 00125 00126 //#include "will2.h" 00127 //#include "mario.h" 00128 //#include "justin3.h" 00129 00130 #include "bmpcomp.h" // BitmapList 00131 00132 DECLARE_SOURCE("$Revision: 1282 $"); 00133 00134 00135 CC_IMPLEMENT_DYNAMIC(InternalClipboard, Document) 00136 CC_IMPLEMENT_MEMDUMP(InternalClipboardFormat, CC_CLASS_MEMDUMP) 00137 00138 #define new CAM_DEBUG_NEW 00139 00140 00141 InternalClipboard* InternalClipboard::pInstance = 0; 00142 InternalClipboard* InternalClipboard::pOther = 0; 00143 00144 00145 00146 /******************************************************************************************** 00147 00148 > InternalClipboard::InternalClipboard(InternalClipboard::ID id, BOOL fHide = TRUE) 00149 00150 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00151 Created: 5/7/94 00152 00153 Purpose: InternalClipboard constructor. 00154 00155 ********************************************************************************************/ 00156 00157 InternalClipboard::InternalClipboard(InternalClipboard::ID id, BOOL fHide) 00158 : Document(fHide), 00159 pClipboardRange(new Range), 00160 ClipOp(FALSE), 00161 m_id(id) 00162 { 00163 // Empty. 00164 } 00165 00166 00167 /******************************************************************************************** 00168 00169 > virtual InternalClipboard::~InternalClipboard(); // Destructor 00170 00171 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00172 Created: 5/7/94 00173 00174 Purpose: InternalClipboard destructor 00175 00176 ********************************************************************************************/ 00177 00178 InternalClipboard::~InternalClipboard() 00179 { 00180 delete pClipboardRange; 00181 pClipboardRange = 0; 00182 } 00183 00184 00185 00186 /******************************************************************************************** 00187 > static InternalClipboard::ID InternalClipboard::GetCurrentID() 00188 00189 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00190 Created: 13/10/96 00191 Returns: The ID of the 'current' clipboard, the one return by Instance(). 00192 ********************************************************************************************/ 00193 00194 InternalClipboard::ID InternalClipboard::GetCurrentID() 00195 { 00196 return pInstance->m_id; 00197 } 00198 00199 00200 00201 /******************************************************************************************** 00202 00203 > static BOOL InternalClipboard::Initialise() 00204 00205 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00206 Created: 15/8/94 00207 00208 Purpose: This method creates the one and only instance of the InternalClipboard and 00209 then initialises it. Called by main3.cpp 00210 00211 ********************************************************************************************/ 00212 00213 BOOL InternalClipboard::Initialise() 00214 { 00215 // Create the clipboards. 00216 if (!(pInstance = new InternalClipboard(InternalClipboard::CLIPBOARD))) return FALSE; 00217 00218 if (!(pOther = new InternalClipboard(InternalClipboard::DRAGDROP))) 00219 { 00220 delete pInstance; 00221 return FALSE; 00222 } 00223 00224 // if (!CCamDoc::Create(pInstance)) 00225 PORTNOTE("other", "Clipboard doc should be hidden") 00226 CCamDoc* pOilDoc1 = new CCamDoc(pInstance); 00227 if (pOilDoc1 == NULL) 00228 { 00229 delete pInstance; 00230 delete pOther; 00231 return FALSE; 00232 } 00233 00234 // if (!CCamDoc::Create(pOther)) 00235 PORTNOTE("other", "Clipboard doc should be hidden") 00236 CCamDoc* pOilDoc2 = new CCamDoc(pOther); 00237 if (pOilDoc2 == NULL) 00238 { 00239 delete pInstance->GetOilDoc(); 00240 delete pOther; 00241 return FALSE; 00242 } 00243 00244 pInstance->OriginalCentreLock = TRUE; 00245 00246 return TRUE; 00247 } 00248 00249 00250 00251 /******************************************************************************************** 00252 00253 > BOOL InternalClipboard::Init(CCamDoc* pOilDoc) 00254 00255 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00256 Created: 15/8/94 00257 00258 Inputs: pOilDoc - the CCamDoc to attach the cliboard to, if any. 00259 00260 Returns: FALSE if it failed 00261 00262 Purpose: This method initialises the Internal clipboard. 00263 It is an internal method, called by Initialise() 00264 It calls down to Document::Init, then adds an insertion Layer node to the 00265 bottom of the basic doc tree. 00266 00267 SeeAlso: InternalClipboard::Initialise(); Document::Init; Document::InitTree 00268 00269 ********************************************************************************************/ 00270 00271 BOOL InternalClipboard::Init(CCamDoc* pOilDoc) 00272 { 00273 if (!Document::Init(pOilDoc)) return FALSE; 00274 00275 Node *pSpread = FindFirstSpread(); 00276 ERROR3IF(pSpread == NULL, "No Spread in document!"); 00277 00278 Node *InsPos = pSpread->FindFirstChild(); 00279 ERROR3IF(InsPos == NULL, "No Spread-child in document!"); 00280 00281 // Now scan the children of the first spread until we find a layer, or run out of nodes 00282 while (InsPos != NULL && !InsPos->IsLayer()) 00283 InsPos = InsPos->FindNext(); 00284 00285 if (InsPos == NULL) // No Layer, so we'd better add one for ourselves 00286 { 00287 String_256 LayerID = String_256(_R(IDS_K_CLIPINT_LAYERNAME)); 00288 Layer *pLayer = new Layer(pSpread, LASTCHILD, LayerID); 00289 ERRORIF(!pLayer, _R(IDE_NOMORE_MEMORY), InitFailed()) 00290 } 00291 00292 OriginalCentreLock = TRUE; 00293 00294 // Sucess. 00295 return(TRUE);; 00296 } 00297 00298 00299 00300 /******************************************************************************************** 00301 00302 > static void InternalClipboard::Deinit() 00303 00304 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00305 Created: 15/8/94 00306 00307 Purpose: This method destroys the InternalClipboard 00308 It is called by main.cpp on shutdown 00309 (and now by CCamDocTemplate::CloseAllDocuments immediately prior to shutdown) 00310 00311 Notes: This code may be called multiple times without problems. Please keep it that way. 00312 00313 ********************************************************************************************/ 00314 00315 void InternalClipboard::Deinit() 00316 { 00317 // Make sure the clipboards are empty. 00318 // Sort out the main clipboard first 00319 Clear(); 00320 00321 // Now sort out the alternate clipborad 00322 Swap(); 00323 Clear(); 00324 Swap(); 00325 00326 if (pInstance) 00327 { 00328 delete pInstance->GetOilDoc(); 00329 pInstance = 0; 00330 } 00331 00332 if (pOther) 00333 { 00334 delete pOther->GetOilDoc(); 00335 pOther = 0; 00336 } 00337 } 00338 00339 00340 00341 /******************************************************************************************** 00342 00343 > static void InternalClipboard::Swap() 00344 00345 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00346 Created: 29/9/96 00347 Purpose: Swaps the two internal clipboards, pInstance and pOther. Used to allow 00348 drag'n'drop operations to happen without disturbing the internal 00349 clipboard. 00350 Errors: - 00351 SeeAlso: - 00352 00353 ********************************************************************************************/ 00354 00355 void InternalClipboard::Swap() 00356 { 00357 InternalClipboard* pcb = pInstance; 00358 pInstance = pOther; 00359 pOther = pcb; 00360 } 00361 00362 00363 00364 /******************************************************************************************** 00365 00366 > static Layer *InternalClipboard::GetInsertionLayer() 00367 00368 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> (recoded from Simon's for new clipboard document layout) 00369 Created: 23/4/95 (21/7/94) 00370 00371 Returns: A pointer to the layer which is the parent of all objects placed on the 00372 clipboard 00373 00374 Purpose: Returns a pointer to the clipboard's layer node which is the parent of all 00375 nodes which get added to the clipboard. 00376 00377 Errors: ERROR3 and returns NULL if an internal consistency check fails 00378 00379 ********************************************************************************************/ 00380 00381 Layer* InternalClipboard::GetInsertionLayer() 00382 { 00383 // Is there a tree (this gets called during destruction, which is a real pain). 00384 if (!pInstance || !pInstance->GetFirstNode()) 00385 { 00386 TRACEUSER( "JustinF", _T("No first node in InternalClipboard::GetInsertionLayer\n")); 00387 return 0; 00388 } 00389 00390 // Get the first spread 00391 Node* pSpread = pInstance->FindFirstSpread(); 00392 ERROR3IF(pSpread == NULL, "No spread found in clipboard doc"); 00393 00394 // Get the spread's first child... 00395 Node *InsPos = pSpread->FindFirstChild(); 00396 ERROR3IF(InsPos == NULL, "No spread-child found in clipboard doc"); 00397 00398 // And now search across until we find the first layer 00399 while (InsPos != NULL && !InsPos->IsLayer()) 00400 InsPos = InsPos->FindNext(); 00401 00402 ERROR3IF(InsPos == NULL, "No insertion layer found in clipboard doc"); 00403 return (Layer*) InsPos; 00404 } 00405 00406 00407 00408 /******************************************************************************************** 00409 00410 > void InternalClipboard::Clear(); 00411 00412 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00413 Created: 21/7/94 00414 00415 Purpose: Deletes the contents of the internal clipboard 00416 00417 ********************************************************************************************/ 00418 00419 void InternalClipboard::Clear() 00420 { 00421 Layer* Root = GetInsertionLayer(); 00422 if (Root == NULL || Root->FindFirstChild() == NULL) 00423 return; // The clipboard is empty already 00424 00425 // The clipboard range is no longer valid 00426 if (pInstance->pClipboardRange) delete pInstance->pClipboardRange; 00427 00428 // An empty range. We need to create this cos the operation could fail 00429 pInstance->pClipboardRange = new Range; 00430 00431 // Delete all objects in clipboard 00432 Root->DeleteChildren(Root->FindFirstChild()); 00433 00434 00435 // Ensure that the top level of the tree has bounding rect caches invalidated, 00436 // as we' ve just vaped the entire subtree below it 00437 Root->InvalidateBoundingRect(); 00438 00439 // We can't do this at the moment because by the time we're called it seems the component 00440 // copy is already under way, and so we're well screwed 00441 00442 // Destroy and re-initialise the doc-components (to chuck away unneeded stuff) 00443 // DestroyDocComponents(); 00444 // if (!InitDocComponents()) 00445 // { 00446 // ERROR3("DocComponent initialisation failed in InternalClipboard::ClearClipboard"); 00447 // } 00448 00449 // Instead, we are really only concerned about stacks of colours building up, so 00450 // we'll just delete any *unused* IndexedColours from the document's list. (Some colours 00451 // are kept in-use by the attribute manager and stuff...) 00452 00453 // First, all named colours (styles) 00454 ColourList *ColList = pInstance->GetIndexedColours(); 00455 IndexedColour *Ptr = (IndexedColour *) ColList->GetHead(); 00456 IndexedColour *Next; 00457 while (Ptr != NULL) 00458 { 00459 Next = (IndexedColour *) ColList->GetNext((ListItem*)Ptr); 00460 if (!Ptr->IsInUse()) 00461 { 00462 // Remove this colour from the list 00463 ColList->RemoveItem(Ptr); 00464 00465 // Ensure this is not in use as a parent of other colours 00466 ColList->RemoveLinksToColour(Ptr); 00467 00468 // And vape it 00469 delete Ptr; 00470 } 00471 00472 Ptr = Next; 00473 } 00474 00475 // Now all unnamed colours (locals) 00476 List *Locals = ColList->GetUnnamedColours(); 00477 Ptr = (IndexedColour *) Locals->GetHead(); 00478 while (Ptr != NULL) 00479 { 00480 Next = (IndexedColour *) Locals->GetNext(Ptr); 00481 if (!Ptr->IsInUse()) 00482 { 00483 // Remove this colour from the list 00484 Locals->RemoveItem(Ptr); 00485 00486 // And vape it (locals can't be parent colours, so no need to 00487 // RemoveLinksToColour() for them) 00488 delete Ptr; 00489 } 00490 00491 Ptr = Next; 00492 } 00493 00494 // Now do the same for this document's bitmap list 00495 BitmapList *pBmpList = pInstance->GetBitmapList(); 00496 if (pBmpList) 00497 { 00498 ListItem* pItem = pBmpList->GetHead(); 00499 ListItem* pNextItem; 00500 while (pItem) 00501 { 00502 pNextItem = pBmpList->GetNext(pItem); 00503 00504 KernelBitmap* pBmpItem = (KernelBitmap*)pItem; 00505 // check if it is the default bitmap, if so then leave in the list 00506 if (!pBmpItem->IsDefaultBitmap()) 00507 { 00508 pBmpList->RemoveItem(pBmpItem); 00509 delete pBmpItem; 00510 } 00511 00512 pItem = pNextItem; 00513 } 00514 } 00515 } 00516 00517 00518 00519 /******************************************************************************************** 00520 00521 > static BOOL InternalClipboard::AttrsHaveChanged() 00522 00523 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00524 Purpose: This function should be called if the attributes of the Internal clipboard 00525 have changed in some way. eg. if a bitmap has been deleted. It destroys 00526 the cache of common attributes. 00527 00528 ********************************************************************************************/ 00529 00530 void InternalClipboard::AttrsHaveChanged() 00531 { 00532 if (pInstance && pInstance->pClipboardRange) 00533 { 00534 pInstance->pClipboardRange->AttrsHaveChanged(); 00535 } 00536 } 00537 00538 00539 00540 /******************************************************************************************** 00541 00542 > BOOL InternalClipboard::CopyObjects(Range& RangeToCopy, Operation * pOp) 00543 00544 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00545 Created: 21/7/94 00546 Inputs: RangeToCopy: The objects to copy to the clipboard 00547 00548 Returns: FALSE if we could not copy 00549 00550 Purpose: Copies a range of objects to the clipboard, all previous clipboard contents 00551 are deleted. If the copy fails the clipboard is emptied and FALSE returned. 00552 It can be called via CALL_WITH_FAIL. 00553 00554 SeeAlso: InternalClipboard::CopyComponentData() 00555 00556 ********************************************************************************************/ 00557 00558 00559 00560 BOOL InternalClipboard::CopyObjects(Range& RangeToCopy, Operation * pOp) 00561 { 00562 // Delete the current contents of the clipboard 00563 pInstance->ClipOp = TRUE; 00564 Clear(); 00565 00566 // All objects to be copied to the clipboard need to be made attribute complete or else 00567 // they may loose important attributes. This is especially true of objects within groups. 00568 00569 if (!(RangeToCopy.MakeAttributeComplete(TRUE,FALSE,TRUE))) 00570 return(FALSE); // Failed 00571 00572 BOOL Failed = FALSE; // until we know better 00573 00574 Node* Root = GetInsertionLayer(); 00575 ENSURE(Root != NULL, "Root of clipboard is NULL"); 00576 00577 if (!Root->CopyComplexRange(RangeToCopy)) 00578 { 00579 Failed = TRUE; 00580 Clear(); // Tidy up 00581 ERROR3("Failed to copy objects"); 00582 } 00583 00584 // Matt (+Karim, + MarkH + loads of other people I whined to) - 02/02/2001 00585 // Removed David McClarnon's fix for 'copy-inside on bevelled blends' as it causes the operation history to 00586 // reference the object in the clipboard - which is deleted when the clipboard is changed !!! -> AccessViolation-ahoy! 00587 /* 00588 // call post duplicate on all nodes 00589 Node * pChildNode = Root->FindFirstDepthFirst(); 00590 00591 while (pChildNode && pChildNode != Root) 00592 { 00593 if (pChildNode->IsAnObject()) 00594 { 00595 if (pOp != NULL) 00596 { 00597 if (pOp->IS_KIND_OF(UndoableOperation)) 00598 { 00599 ((NodeRenderableInk *)pChildNode)->PostDuplicate((UndoableOperation *)pOp); 00600 } 00601 else 00602 { 00603 if (!pChildNode->IsABaseTextClass()) 00604 ((NodeRenderableInk *)pChildNode)->PostDuplicate(NULL); 00605 } 00606 } 00607 } 00608 00609 pChildNode = pChildNode->FindNextDepthFirst(Root); 00610 } 00611 */ 00612 // We now need to optimise the attributes on all objects copied to the clipboard 00613 if (!Failed) 00614 { 00615 Node* FirstNode = pInstance->GetFirstNode(); 00616 ERROR3IF(!FirstNode, "Cannot find first clipboard node"); 00617 if (FirstNode) 00618 { 00619 Node* Root = FirstNode->FindNext(); 00620 ERROR3IF(!Root, "Clipboard has no root"); 00621 ERROR3IF(!(IS_A(Root, NodeDocument)), "This should be the root of the clipboard"); 00622 if (Root) 00623 { 00624 if (!Root->OptimiseAttributes()) 00625 { 00626 Failed = TRUE; 00627 Clear(); 00628 } 00629 } 00630 } 00631 00632 } 00633 00634 00635 // Ensure that the top level of the tree has bounding rect caches invalidated, 00636 // as we've just plugged an entire new subtree in! 00637 ((Layer *)Root)->InvalidateBoundingRect(); 00638 00639 // We now need to Normalise the attributes of all objects copied 00640 RangeToCopy.NormaliseAttributes(FALSE,TRUE); 00641 00642 pInstance->ClipOp = FALSE; 00643 return (!Failed); 00644 } 00645 00646 00647 00648 00649 00650 /******************************************************************************************** 00651 00652 > BOOL InternalClipboard::CopyComponentData(BaseDocument* pSrcDoc) 00653 00654 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00655 Created: 21/7/94 00656 Inputs: pSrcDoc: The source document 00657 00658 Returns: FALSE if the component data has not successfuly been copied accross. In this 00659 situation AbortComponentCopy gets called. 00660 00661 Purpose: This function should get called after CopyObjects has been called. It asks 00662 all objects to copy accross their component data to the clipboard. It can 00663 be called via CALL_WITH_FAIL. 00664 00665 ********************************************************************************************/ 00666 00667 BOOL InternalClipboard::CopyComponentData(BaseDocument* pSrcDoc) 00668 { 00669 if (IsEmpty(FALSE)) 00670 { 00671 // The CopyObjects either was not called, or failed 00672 ERROR3("InternalClipboard::CopyComponentData called when clipboard is empty!"); 00673 return(FALSE); 00674 } 00675 00676 // Scan all clipboard nodes 00677 Node* Root = GetInsertionLayer(); 00678 Node* Current = Root->FindFirstDepthFirst(); 00679 while (Current != NULL) 00680 { 00681 // Ask the current node if it would copy it's data to the relevant DocComponents 00682 if (Current->IsKindOf(CC_RUNTIME_CLASS(NodeRenderable))) 00683 { 00684 if (!((NodeRenderable*) Current)->CopyComponentData(pSrcDoc, pInstance)) 00685 { 00686 // No luck 00687 pInstance->AbortComponentCopy(); // Cancel all data which has been copied 00688 Clear(); // Tidy up 00689 return FALSE; 00690 } 00691 } 00692 00693 Current = Current->FindNextDepthFirst(Root); 00694 } 00695 00696 return TRUE; // Success 00697 } 00698 00699 00700 00701 /******************************************************************************************** 00702 00703 > DocRect InternalClipboard::GetObjectsBounds() 00704 00705 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00706 Created: 28/7/94 00707 00708 Returns: The bounds of all objects in the clipboard 00709 00710 Purpose: For finding the bounds of all objects in the clipboard 00711 00712 ********************************************************************************************/ 00713 00714 DocRect InternalClipboard::GetObjectsBounds() 00715 { 00716 DocRect Bounds; 00717 00718 ERROR3IF(IsEmpty(FALSE), "InternalClipboard::GetObjectsBounds called when CB is empty"); 00719 00720 Node* CurrentNode = GetInsertionLayer()->FindFirstChild(); 00721 while (CurrentNode != NULL) 00722 { 00723 if (CurrentNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableBounded))) 00724 { 00725 Bounds = Bounds.Union( 00726 ( ((NodeRenderableBounded*)CurrentNode)->GetBoundingRect(TRUE, FALSE)) ); 00727 } 00728 CurrentNode = CurrentNode->FindNext(); 00729 } 00730 00731 return Bounds; 00732 } 00733 00734 00735 00736 /******************************************************************************************** 00737 00738 > static BOOL InternalClipboard::CopyInProgress(void) 00739 00740 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00741 Created: 19/4/95 00742 00743 Returns: TRUE if we are currently busy copying 00744 00745 Purpose: Allows external entities to determine if they were called during a 00746 clipboard copy operation. 00747 00748 ********************************************************************************************/ 00749 00750 BOOL InternalClipboard::CopyInProgress() 00751 { 00752 return pInstance->ClipOp; 00753 } 00754 00755 00756 /******************************************************************************************** 00757 00758 > static BOOL InternalClipboard::IsEmpty(BOOL AskExternalClipboard = TRUE) 00759 00760 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00761 Created: 19/4/95 00762 00763 Inputs: AskExternalClipboard - if TRUE, this method will tell you if there is ANY 00764 data available for pasting. If FALSE, it simply checks if the internal 00765 clipboard (esentially an internal cache) is empty. ONLY the external clipboard 00766 (or internal calls in this class) should ever pass in FALSE for this parameter! 00767 00768 Returns: TRUE if the clipboard is empty (no data to paste) 00769 FALSE if the clipboard is non-empty (there is data available to paste) 00770 00771 Purpose: To determine if there is anything currently stored on the internal clipboard 00772 00773 Notes: If there is no internal clipboard, it will return TRUE 00774 00775 ********************************************************************************************/ 00776 00777 BOOL InternalClipboard::IsEmpty(BOOL AskExternalClipboard) 00778 { 00779 if (pInstance == NULL) 00780 return(TRUE); 00781 00782 Layer *templayer = pInstance->GetInsertionLayer(); 00783 if (!templayer) { ERROR3("Can't get clipboard insertion layer!"); return TRUE; } 00784 00785 Node* n = templayer->FindFirstChild(); 00786 BOOL Empty = (n == NULL); 00787 00788 if (Empty && AskExternalClipboard) 00789 { 00790 PORTNOTE("extclipboard", "Removed use of External Clipboard") 00791 #ifndef EXCLUDE_FROM_XARALX 00792 // We're empty, so ask the External clipboard if it can supply us with data 00793 ExternalClipboard *Clipboard = ExternalClipboard::GetExternalClipboard(); 00794 00795 if (Clipboard == NULL) 00796 return(TRUE); 00797 00798 return(Clipboard->IsEmpty()); 00799 #else 00800 return TRUE; 00801 #endif 00802 } 00803 00804 return(Empty); 00805 } 00806 00807 00808 00809 /******************************************************************************************** 00810 00811 > BOOL InternalClipboard::PrepareForCopy(void) 00812 00813 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00814 Created: 19/4/95 00815 00816 Returns: TRUE if the clipboard is ready to accept new data 00817 FALSE if the copy must be aborted 00818 00819 Purpose: To ready the clipboard for a cut/copy operation (copy data TO the clipboard). 00820 This will interact with the external clipboard in order to claim the global 00821 clipboard, and readies the clipboard for use. 00822 00823 Notes: After you have copied data to the clipboard, you MUST call CopyCompleted 00824 00825 SeeAlso: InternalClipboard::CopyCompleted; InternalClipboard::PrepareForPaste; 00826 ExternalClipboard::PrepareForCopy 00827 00828 ********************************************************************************************/ 00829 00830 BOOL InternalClipboard::PrepareForCopy(void) 00831 { 00832 Clear(); 00833 PORTNOTE("extclipboard", "Removed use of External Clipboard") 00834 #ifndef EXCLUDE_FROM_XARALX 00835 ExternalClipboard* pcb = ExternalClipboard::GetExternalClipboard(); 00836 return pcb ? pcb->PrepareForCopy() : FALSE; 00837 #else 00838 return TRUE; 00839 #endif 00840 } 00841 00842 00843 00844 /******************************************************************************************** 00845 00846 > BOOL InternalClipboard::CopyCompleted(void) 00847 00848 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00849 Created: 19/4/95 00850 00851 Returns: TRUE if all went well 00852 FALSE if the copy failed in some way 00853 00854 Purpose: Tells the InternalClipboard that you have finished copying data to it. 00855 This interacts with the external clipboard in order to make the new data 00856 available to the outside world. 00857 00858 Notes: Before starting to copy data to the clipboard you MUST call PrepareForCopy 00859 00860 SeeAlso: InternalClipboard::PrepareForCopy; ExternalClipboard::CopyCompleted 00861 00862 ********************************************************************************************/ 00863 00864 BOOL InternalClipboard::CopyCompleted(void) 00865 { 00866 if (IsEmpty(FALSE)) 00867 { 00868 ERROR3("That copy wasn't much fun - the clipboard's still empty!"); 00869 return(FALSE); 00870 } 00871 00872 PORTNOTE("extclipboard", "Removed use of External Clipboard") 00873 #ifndef EXCLUDE_FROM_XARALX 00874 ExternalClipboard *Clipboard = ExternalClipboard::GetExternalClipboard(); 00875 if (Clipboard == NULL) return(FALSE); 00876 00877 if (Clipboard->CopyCompleted()) 00878 { 00879 #endif 00880 // Objects have successfully been moved to clipboard. Perform neccessary processing 00881 if (!pInstance->OnNewClipboardObjects()) InformError(); 00882 return TRUE; 00883 #ifndef EXCLUDE_FROM_XARALX 00884 } 00885 else 00886 { 00887 return FALSE; 00888 } 00889 #endif 00890 } 00891 00892 00893 00894 /******************************************************************************************** 00895 00896 > BOOL InternalClipboard::PrepareForPaste(BOOL* ExternalSource = NULL) 00897 00898 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00899 Created: 19/4/95 00900 00901 Outputs: ExternalSource: When the function returns TRUE, ExternalSource will be TRUE 00902 if the data has come from the external clipboard, and 00903 FALSE if not. 00904 00905 Returns: TRUE if the clipboard is ready to provide data for pasting 00906 FALSE if the paste must be aborted (nothing to paste) 00907 00908 Purpose: To ready the clipboard for a paste operation (copy data FROM the clipboard). 00909 This may interact with the external clipboard in order to provide the 00910 necessary data. 00911 00912 Notes: After copying data from the clipboard you MUST call PasteCompleted 00913 00914 SeeAlso: InternalClipboard::PasteCompleted; InternalClipboard::PrepareForCopy; 00915 ExternalClipboard::PrepareForPaste 00916 00917 ********************************************************************************************/ 00918 00919 BOOL InternalClipboard::PrepareForPaste(BOOL* ExternalSource) 00920 { 00921 if (ExternalSource) 00922 *ExternalSource = FALSE; // Until we know better 00923 00924 pInstance->OriginalCentreLock = TRUE; // Don't allow centre to be reset 00925 00926 // If we are empty, then we'll have to go and look outside for something to put onto 00927 // the internal clipboard. 00928 if (IsEmpty(FALSE)) 00929 { 00930 PORTNOTE("extclipboard", "Removed use of External Clipboard") 00931 #ifndef EXCLUDE_FROM_XARALX 00932 ExternalClipboard *Clipboard = ExternalClipboard::GetExternalClipboard(); 00933 if (Clipboard == NULL || !Clipboard->PrepareForPaste()) 00934 return(FALSE); 00935 00936 // Optimise attributes on the clipboard 00937 Node* FirstNode = pInstance->GetFirstNode(); 00938 ERROR3IF(!FirstNode, "Cannot find first clipboard node"); 00939 if (FirstNode) 00940 { 00941 Node* Root = FirstNode->FindNext(); 00942 ERROR3IF(!Root, "Clipboard has no root"); 00943 ERROR3IF(!(IS_A(Root, NodeDocument)), "This should be the root of the clipboard"); 00944 if (Root && !Root->OptimiseAttributes()) return FALSE; 00945 } 00946 00947 // Objects successfully transferred to clipboard. Perform neccessary processing 00948 if (!pInstance->OnNewClipboardObjects()) InformError(); 00949 00950 pInstance->OriginalCentreLock = FALSE; // Allow centre to be reset on first Paste 00951 00952 // Data has come from external clipboard 00953 if (ExternalSource) *ExternalSource = TRUE; 00954 #endif 00955 } 00956 00957 return(TRUE); 00958 } 00959 00960 00961 00962 /******************************************************************************************** 00963 00964 > BOOL InternalClipboard::PasteCompleted(void) 00965 00966 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00967 Created: 19/4/95 00968 00969 Returns: TRUE if all went well 00970 FALSE if the paste failed in some way 00971 00972 Purpose: Tells the InternalClipboard that you have finished copying data from it. 00973 This provides interaction with the external clipboard. 00974 00975 Notes: Before starting to copy data to the clipboard you MUST call PrepareForCopy 00976 00977 SeeAlso: InternalClipboard::PrepareForPaste; ExternalClipboard::PasteCompleted 00978 00979 ********************************************************************************************/ 00980 00981 BOOL InternalClipboard::PasteCompleted(void) 00982 { 00983 if (IsEmpty(FALSE)) 00984 { 00985 ERROR3("That paste wasn't much fun - the clipboard's empty now!"); 00986 } 00987 00988 PORTNOTE("extclipboard", "Removed use of External Clipboard") 00989 #ifndef EXCLUDE_FROM_XARALX 00990 ExternalClipboard *Clipboard = ExternalClipboard::GetExternalClipboard(); 00991 00992 if (Clipboard == NULL) 00993 return(FALSE); 00994 00995 return(Clipboard->PasteCompleted()); 00996 #else 00997 return TRUE; 00998 #endif 00999 } 01000 01001 01002 01003 /******************************************************************************************** 01004 01005 > static void InternalClipboard::DescribeContents(String_64 *Result); 01006 01007 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01008 Created: 21/5/95 01009 01010 Outputs: Result will be filled in with either a blank string, or a description of the 01011 current internal clipboard contents. 01012 01013 Purpose: To determine the description of the clipboard contents 01014 01015 Notes: Redirects the call to the external clipboard, as it has a better idea 01016 of the overall picture. 01017 01018 SeeAlso: ExternalClipboard::DescribeContents 01019 01020 ********************************************************************************************/ 01021 01022 void InternalClipboard::DescribeContents(String_64 *Result) 01023 { 01024 ERROR3IF(Result == NULL, "Illegal NULL param"); 01025 PORTNOTE("extclipboard", "Removed use of External Clipboard") 01026 #ifndef EXCLUDE_FROM_XARALX 01027 ExternalClipboard::DescribeContents(Result); 01028 #else 01029 static String_64 strDesc = String_64(_T("No description (see InternalClipboard::DescribeContents)")); 01030 Result = &strDesc; 01031 #endif 01032 } 01033 01034 01035 01036 /******************************************************************************************** 01037 01038 > static void InternalClipboard::DescribeContentsInternal(String_64* Result); 01039 01040 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01041 Created: 21/5/95 01042 01043 Outputs: Result will be filled in with either a blank string, or a description of the 01044 current internal clipboard contents. 01045 01046 Purpose: To determine the description of the clipboard contents 01047 01048 Notes: Internal version of this call, for the external clipboard only. 01049 01050 SeeAlso: InternalClipboard::DescribeContents 01051 01052 ********************************************************************************************/ 01053 01054 void InternalClipboard::DescribeContentsInternal(String_64* Result) 01055 { 01056 ERROR3IF(Result == NULL, "Illegal NULL param"); 01057 01058 *Result = TEXT(""); 01059 if (IsEmpty(FALSE)) return; 01060 01061 // --- Scan the document tree to determine the description. Note that this should be 01062 // done by calling a range, except that the code is in SelRange, so I've rewritten it here 01063 // to save myself half a day's delay waiting for a range.h rebuild when I can't afford it... 01064 01065 Node* Subtree = GetInsertionLayer(); 01066 if (Subtree == NULL) 01067 return; 01068 01069 Range ClipRange(Subtree->FindFirstChild(), Subtree->FindLastChild(), 01070 RangeControl(TRUE,TRUE,TRUE,TRUE)); 01071 01072 String_256 Description; 01073 Node* Current = ClipRange.FindFirst(); 01074 if (Current == NULL) return; 01075 01076 // Implementation 01077 Node* FirstInRange = Current; 01078 CCRuntimeClass* NodeType = Current->GetRuntimeClass(); 01079 01080 // -------------------------------------------------------------------------------- 01081 // Determine if there is more than one type of object selected 01082 01083 BOOL OneTypeOfObject = TRUE; // TRUE if range contains only 01084 // one type of object. 01085 do 01086 { 01087 if (Current->GetRuntimeClass() != NodeType) // Range contains more than one 01088 // type of object 01089 { 01090 // Current object is not the same type as the first so we know there is more 01091 // than one type of object. 01092 OneTypeOfObject = FALSE; 01093 break; 01094 } 01095 01096 Current = ClipRange.FindNext(Current); 01097 } 01098 while (Current); 01099 01100 UINT32 NumObjectsInRange = ClipRange.Count(); // Count is cached 01101 ERROR3IF(NumObjectsInRange <= 0, "No objects selected"); 01102 01103 if (OneTypeOfObject) 01104 { 01105 // All objects in the selection are of the same type 01106 01107 String_32 Name; 01108 BOOL UseClassToDescribe = TRUE; 01109 01110 NodeGroup* FirstGroup = NULL; 01111 01112 if (FirstInRange->GetRuntimeClass() == CC_RUNTIME_CLASS(NodeGroup)) 01113 { 01114 UseClassToDescribe = FALSE; 01115 // If all selected groups have the same name then the name is used in the 01116 // description 01117 FirstGroup = (NodeGroup*)FirstInRange; 01118 NodeGroup* CurrentGroup = FirstGroup; 01119 Name = CurrentGroup->GetName(); 01120 if (!(Name.IsEmpty())) 01121 { 01122 do 01123 { 01124 CurrentGroup=(NodeGroup*)ClipRange.FindNext(CurrentGroup); 01125 01126 if (CurrentGroup != NULL) 01127 { 01128 if (CurrentGroup->GetName() != Name) 01129 { 01130 // A group has been found with a different name. Stop the search and 01131 // use the class to describe the selection. 01132 UseClassToDescribe = TRUE; 01133 break; 01134 } 01135 } 01136 01137 } while (CurrentGroup != NULL); 01138 } 01139 else 01140 { 01141 UseClassToDescribe = TRUE; 01142 } 01143 } 01144 if (UseClassToDescribe) 01145 { 01146 Description = (FirstInRange->Describe(NumObjectsInRange>1)); 01147 } 01148 else 01149 { 01150 // Use the group name to describe the selection 01151 ERROR3IF(FirstGroup == NULL, "FirstGroup should be the first selected group"); 01152 if (NumObjectsInRange > 1) 01153 { 01154 Description = SelRange::Pluralise(FirstGroup->GetName()); 01155 } 01156 else 01157 { 01158 Description = FirstGroup->GetName(); 01159 } 01160 } 01161 } 01162 else 01163 { 01164 // There must be more than one type of selected objects 01165 ERROR3IF(NumObjectsInRange <= 1, "Only a single object is in range"); 01166 // Cos there are multiple objects of different types we describe them as 'objects' 01167 Description = String(_R(IDS_OBJECTS)); 01168 } 01169 01170 Description.Left(Result, 63); 01171 } 01172 01173 01174 01175 /******************************************************************************************** 01176 01177 > BOOL InternalClipboard::OnNewClipboardObjects() 01178 01179 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01180 Created: 6/9/95 01181 Returns: FALSE if something has gone wrong. An InformError should be called if this 01182 occurs. The Cut/Copy/Paste Operation being performed should not be aborted though. 01183 01184 Purpose: This fn will be called whenever data has successfuly been transfered to 01185 the InternalClipboard. i.e. After a Cut, Copy, or (paste from External Clipboard) 01186 01187 01188 Scope: private 01189 01190 ********************************************************************************************/ 01191 01192 BOOL InternalClipboard::OnNewClipboardObjects() 01193 { 01194 // Set the bounds of the spread containing the objects to the bounds of the objects. 01195 Spread* pSpread = FindFirstSpread(); 01196 ERROR2IF(!pSpread, FALSE, "No first Spread in InternalClipboard::OnNewClipboardObjects"); 01197 01198 // Calculate the bounds of all the objects on the spread (this code is based on 01199 // Spread::GetPageVisibleBounds, ie. the function that Zoom to Drawing uses). 01200 DocRect drBounds; 01201 drBounds.MakeEmpty(); 01202 01203 // Search through all the children of the spread, looking for layers. 01204 Layer* pLayer = pSpread->FindFirstLayer(); 01205 while (pLayer) 01206 { 01207 // We ignore the guide layers, which always have an empty bounding box 01208 // (according to Mark Neves!) 01209 if (!pLayer->IsGuide()) 01210 { 01211 // Include the bounds of the objects on this layer. 01212 drBounds = drBounds.Union(pLayer->GetBoundingRect()); 01213 } 01214 01215 // And onto the next layer ... 01216 pLayer = pLayer->FindNextLayer(); 01217 } 01218 01219 // If the bounds aren't empty then set the page size to be those bounds, so the 01220 // page is the smallest size that encloses the objects it contains. 01221 if (!drBounds.IsEmpty()) 01222 { 01223 // Remember the centre of the bounds of the objects, so Paste-In-Place will 01224 // still work. 01225 dcCentre.x = drBounds.lo.x + drBounds.Width() / 2; 01226 dcCentre.y = drBounds.lo.y + drBounds.Height() / 2; 01227 01228 // Now convert to document coordinates. 01229 pSpread->SpreadCoordToDocCoord(&drBounds); 01230 01231 // Work out the new dimensions of the page. 01232 /* MILLIPOINT mpWidth = drBounds.Width(); 01233 MILLIPOINT mpHeight = drBounds.Height(); 01234 01235 // Inflate the size of the page by 5% to give a pleasing border around the objects. 01236 const double fpInflate = 1.024695076596; 01237 mpWidth = (MILLIPOINT) floor(mpWidth * fpInflate + 0.5); 01238 mpHeight = (MILLIPOINT) floor(mpHeight * fpInflate + 0.5); 01239 */ 01240 01241 PORTNOTE("other", "Removed use of CCamDoc::SetPageSize") 01242 #ifndef EXCLUDE_FROM_XARALX 01243 //#if (_OLE_VER >= 0x200) 01244 // Resize the page to just surround the objects, but don't scale the objects 01245 // by the same amount. 01246 ERROR2IF(!GetOilDoc()->SetPageSize(mpWidth, mpHeight, FALSE), 01247 FALSE, "SetPageSize failed in InternalClipboard::OnNewClipboardObjects"); 01248 //#endif 01249 #endif 01250 01251 // Discard any undo information in this clipboard document. 01252 EmptyOperationHistory(); 01253 } 01254 #ifdef _DEBUG 01255 else 01256 { 01257 // This should be investigated if you see this TRACE. Perhaps because the selection 01258 // consisted of invisible layers? 01259 TRACE( _T("Warning: no bounds for SetPageSize in InternalClipboard::OnNewClipboardObjects (?)\n")); 01260 } 01261 #endif 01262 01263 // Currently this routine creates a new Range of objects on the clipboard 01264 delete pClipboardRange; 01265 pClipboardRange = NULL; 01266 01267 // Find the first child of the clipboard's layer 01268 Node* pNode = Node::FindFirstChapter(this); 01269 NodeRenderableInk* pInkNode = NULL; 01270 if (pNode) pNode = ((Chapter*) pNode)->FindFirstSpread(); 01271 if (pNode) pNode = ((Spread*) pNode)->FindFirstLayer(); 01272 if (pNode) 01273 { 01274 pInkNode = (NodeRenderableInk*)pNode->FindFirstChild(CC_RUNTIME_CLASS(NodeRenderableInk)); 01275 while (pInkNode!=NULL && !pInkNode->CanSelectAsCompoundParent()) 01276 { 01277 if (pInkNode->IsCompoundClass() && ((NodeCompound*)pInkNode)->GetInkNodeFromController()) 01278 pInkNode = ((NodeCompound*)pInkNode)->GetInkNodeFromController(); 01279 else 01280 pInkNode = (NodeRenderableInk*)pInkNode->FindFirstChild(CC_RUNTIME_CLASS(NodeRenderableInk)); 01281 } 01282 } 01283 01284 ERROR3IF(!pInkNode, "InternalClipboard::OnNewClipboardObjects, Where has the clipboard gone ??"); 01285 if (!pInkNode) return FALSE; // What else can we do ? 01286 01287 // Try to create a range of all objects. 01288 pClipboardRange = new Range(pInkNode, NULL, RangeControl(TRUE, TRUE)); 01289 return pClipboardRange != 0; 01290 } 01291 01292 01293 01294 /******************************************************************************************** 01295 > DocCoord InternalClipboard::GetOriginalCentrePoint() 01296 01297 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 01298 Created: 13/10/96 01299 Returns: The original centre point of the objects on the clipboard before they were 01300 copied. 01301 Purpose: Paste-in-place centres the objects when they are pasted at this point. 01302 SeeAlso: InternalClipboard::OnNewClipboardObjects; 01303 ********************************************************************************************/ 01304 01305 DocCoord InternalClipboard::GetOriginalCentrePoint() 01306 { 01307 return pInstance->dcCentre; 01308 } 01309 01310 01311 01312 01313 /******************************************************************************************** 01314 > void InternalClipboard::SetOriginalCentrePoint(DocCoord NewCentre) 01315 01316 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 01317 Created: 13/10/96 01318 Input: NewCentre A position that the caller would like to record as being the 01319 "original centre" of the objects on the clipboard. 01320 Returns: - 01321 Purpose: Paste-in-place centres the objects when they are pasted at this point. 01322 Reset the centre point but only do so when the centre point is unlocked. 01323 SeeAlso: InternalClipboard::OnNewClipboardObjects, OpPaste::DoPasteStandard; 01324 ********************************************************************************************/ 01325 01326 void InternalClipboard::SetOriginalCentrePoint(DocCoord NewCentre) 01327 { 01328 if (!pInstance->OriginalCentreLock) 01329 { 01330 pInstance->dcCentre = NewCentre; 01331 pInstance->OriginalCentreLock = TRUE; 01332 } 01333 } 01334 01335 /******************************************************************************************** 01336 > void InternalClipboard::CopyText(TCHAR* pcBuffer) 01337 01338 Author: Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>, liberally copied from BodgeTextMap::HandleImport 01339 Created: 24/4/97 01340 Input: pcBuffer The text to copy on to the clipboard 01341 Returns: - 01342 Purpose: Copies the text on to the clipboard (by converting it 01343 to a text object). 01344 SeeAlso: TextStory::CreateFromChars, BodgeTextMap::HandleImport 01345 ********************************************************************************************/ 01346 01347 BOOL InternalClipboard::CopyText(TCHAR* pcBuffer) 01348 { 01349 PORTNOTE("other", "InternalClipboard::CopyText disabled due to use of CCamSrvrItem") 01350 #ifndef EXCLUDE_FROM_XARALX 01351 //We need to tell CCamSrvrItem that what we are about to put on the clipboard 01352 //should be treated as text 01353 01354 //To do this, we call RenderProprietary Formats, which sets a flag. The 01355 //returned value will be the old state of this flag, which we must remember 01356 //cos otherwise Justin will beat me up 01357 BOOL fOldState = CCamSrvrItem::RenderProprietaryFormats(FALSE); 01358 01359 //If we have some text 01360 if (pcBuffer != NULL && pcBuffer[0] != '\0') 01361 { 01362 //Create a text story, which we position arbitarily on the clipboard 01363 TextStory* pTextStory=TextStory::CreateFromChars(DocCoord(100,100), pcBuffer, 01364 NULL, InternalClipboard::Instance(), NULL, TRUE); 01365 01366 if (pTextStory!=NULL) 01367 { 01368 //Prepare to copy...this will clear the clipboard 01369 PrepareForCopy(); 01370 01371 // Attach the text story to the clipboard 01372 pTextStory->AttachNode(InternalClipboard::GetInsertionLayer(), LASTCHILD); 01373 pTextStory->NormaliseAttributes(); 01374 01375 // And format the text story properly 01376 pTextStory->FormatAndChildren(NULL,FALSE,FALSE); 01377 01378 CopyCompleted(); 01379 01380 //And reset the old state of the flag 01381 CCamSrvrItem::RenderProprietaryFormats(fOldState); 01382 01383 return(TRUE); 01384 } 01385 01386 // We failed, so clear the clipboard 01387 InternalClipboard::Clear(); 01388 01389 //And reset the old state of the flag 01390 CCamSrvrItem::RenderProprietaryFormats(fOldState); 01391 01392 return FALSE; 01393 } 01394 #endif 01395 01396 return FALSE; 01397 01398 } 01399 01400 01401 01402