00001 // $Id: node.cpp 1621 2006-07-31 15:35:28Z phil $ 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 // Implementation of the Node class 00101 00102 // Check in comments 00103 00104 00105 00106 #include "camtypes.h" 00107 //#include "mario.h" // for _R(IDE_NOMORE_MEMORY) 00108 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00109 #include "chapter.h" 00110 #include "nodedoc.h" 00111 #include "page.h" 00112 #include "progress.h" 00113 #include "insertnd.h" 00114 #include "lineattr.h" 00115 #include "objchge.h" 00116 #include "nodepath.h" 00117 #include "ndoptmz.h" 00118 #include "dbugtree.h" 00119 //#include "camfiltr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00120 #include "cxftags.h" 00121 #include "nodetxts.h" 00122 00123 #include "extender.h" 00124 #include "ngcore.h" // NameGallery, for stretching functionality 00125 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00126 00127 #ifdef RALPH 00128 #include "ralphcri.h" 00129 #endif 00130 00131 00132 MILLIPOINT Node::PixelWidth; 00133 MILLIPOINT Node::PixelHeight; 00134 BOOL Node::HourglassOn = FALSE; // When TRUE certain slow routines will call ContinueSlowJob 00135 00136 DECLARE_SOURCE("$Revision: 1621 $"); 00137 CC_IMPLEMENT_DYNAMIC(Node, CCObject) 00138 00139 // Declare smart memory handling in Debug builds 00140 #define new CAM_DEBUG_NEW 00141 00142 00143 /*********************************************************************************************** 00144 00145 > Node::Node(void) 00146 00147 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00148 Created: 19/4/93 00149 Inputs: - 00150 Outputs: - 00151 Returns: - (Constructor) 00152 Purpose: This constructor creates a node linked to no other with all status flags 00153 FALSE. Also updates the Node counter of the current Document. 00154 Errors: An assertion failure will occur if there is no current document 00155 Notes: This method relies on the current document having been set in the Document 00156 object. 00157 00158 ***********************************************************************************************/ 00159 00160 00161 Node::Node() 00162 { 00163 Previous=Next=Child=Parent=NULL; 00164 // Set OpPermission stuff here too as SetOpPermission does a GetOpPermission which otherwise reads an undefined value 00165 Flags.Locked=Flags.Mangled=Flags.Marked=Flags.Selected=Flags.Renderable=Flags.OpPermission1=Flags.OpPermission2 = FALSE; 00166 Flags.SelectedChildren = FALSE; 00167 SetOpPermission(PERMISSION_UNDEFINED); 00168 HiddenRefCnt = 0; 00169 00170 // Has no TAG because it is not in a document yet. 00171 Tag = TAG_NOT_IN_DOC; 00172 } 00173 00174 00175 /*********************************************************************************************** 00176 00177 > Node::Node( Node* ContextNode, 00178 AttachNodeDirection Direction, 00179 BOOL Locked = FALSE, 00180 BOOL Mangled = FALSE, 00181 BOOL Marked = FALSE, 00182 BOOL Selected = FALSE, 00183 BOOL Renderable = FALSE) 00184 00185 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00186 Created:26/4/93 00187 00188 Inputs: ContextNode: Pointer to a node which this node is to be attached to. 00189 00190 Direction: 00191 00192 Specifies the direction in which the node is to be attached to the 00193 ContextNode. The values this variable can take are as follows: 00194 00195 PREV : Attach node as a previous sibling of the context node 00196 NEXT : Attach node as a next sibling of the context node 00197 FIRSTCHILD: Attach node as the first child of the context node 00198 LASTCHILD : Attach node as a last child of the context node 00199 00200 00201 The remaining inputs specify the status of the node: 00202 00203 Locked: Is node locked ? 00204 Mangled: Is node mangled ? 00205 Marked: Is node marked ? 00206 Selected: Is node selected ? 00207 Renderable: Is node renderable ? 00208 Compound: Can node contain non attribute children (eg. a group) 00209 00210 Outputs: - 00211 Returns: - 00212 Purpose: This constructor initialises a node and links it to ContextNode in the 00213 direction specified by Direction. All necessary tree links are 00214 updated. For example if a node is inserted as a FirstChild of ContextNode, 00215 and Context node already has children, then the current first child of context 00216 node will become the next sibling of the new first child node. 00217 00218 Also updates the Node counter of the current document. 00219 00220 Errors: An assertion failure will occur if the ContextNode is NULL 00221 00222 ***********************************************************************************************/ 00223 /* 00224 Technical notes: 00225 00226 This method Initializes the flags to the values specified, and then calls a method 00227 to attach a node to ContextNode, in the direction specified by Direction. 00228 00229 ***********************************************************************************************/ 00230 00231 00232 Node::Node(Node* ContextNode, 00233 AttachNodeDirection Direction, 00234 BOOL Locked, 00235 BOOL Mangled, 00236 BOOL Marked, 00237 BOOL Selected, 00238 BOOL Renderable 00239 ) 00240 { 00241 // Defensive programming 00242 ENSURE(ContextNode != NULL,"Trying to attach a node to a NULL node"); 00243 00244 // Initialize the flags 00245 Flags.Locked = Locked; 00246 Flags.Mangled = Mangled; 00247 Flags.Marked = Marked; 00248 Flags.Selected = Selected; 00249 Flags.SelectedChildren = FALSE; 00250 Flags.Renderable = Renderable; 00251 Flags.OpPermission1 = Flags.OpPermission2 = FALSE; // because SetOpPermission does a GetOpPermission 00252 00253 // Has no TAG because it is not in a document yet. 00254 Tag = TAG_NOT_IN_DOC; 00255 00256 SetOpPermission(PERMISSION_UNDEFINED); 00257 Child=NULL; // New node has no children 00258 AttachNode(ContextNode,Direction); 00259 00260 // Sanity check of unique TAG for object 00261 BaseDocument* pDoc = ContextNode->FindOwnerDoc(); 00262 if (pDoc != NULL) 00263 { 00264 ERROR3IF(Tag==TAG_NOT_IN_DOC, "Tag should have a valid value"); 00265 // Get a tag for this node and update the count of nodes in the document. 00266 if (Tag==TAG_NOT_IN_DOC) 00267 SetTags(pDoc); 00268 } 00269 else 00270 { 00271 ERROR3IF(Tag!=TAG_NOT_IN_DOC, "Tag should be TAG_NOT_IN_DOC"); 00272 Tag = TAG_NOT_IN_DOC; // Has no TAG 00273 } 00274 00275 HiddenRefCnt = 0; 00276 00277 if (Selected) 00278 { 00279 // Inform the Selection SelRange that the selection has changed 00280 // Pass in 'this' to let it know that I am the most recently selected node 00281 SelRange *Selection = GetApplication()->FindSelection(); 00282 if (Selection != NULL) 00283 Selection->Update(FALSE, this); 00284 } 00285 } 00286 00287 00288 00289 00290 /******************************************************************************************** 00291 00292 > virtual Node::~Node() 00293 00294 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00295 Created: 30/11/93 00296 Inputs: - 00297 Outputs: - 00298 Returns: - 00299 Purpose: Destroys a Node object. The base class updates the node counter of the 00300 current document, and ensures that the SelRange doesn't have a cached pointer 00301 to 'this' as its 'Last Selected Node'. 00302 Errors: - 00303 SeeAlso: Document::DecCurrentNodeCount 00304 00305 ********************************************************************************************/ 00306 00307 Node::~Node() 00308 { 00309 ERROR3IF(Child != NULL,"Deleting a node that has a ptr to child nodes"); 00310 00311 // Ensure that the Selection SelRange doesn't still keep a cached pointer to me 00312 SelRange *Selection = GetApplication()->FindSelection(); 00313 if (Selection != NULL) 00314 Selection->ClearLastSelectedNodeIfItIs(this); 00315 00316 } 00317 00318 00319 /*********************************************************************************************** 00320 00321 > virtual void Node::Render(void) 00322 00323 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00324 Created: 30/4/93 00325 Inputs: RendRegion: Render region to render into 00326 Outputs: - 00327 Returns: - 00328 Purpose: For rendering a node 00329 00330 ***********************************************************************************************/ 00331 00332 void Node::Render( RenderRegion* pRender ) {}; 00333 00334 00335 00336 /******************************************************************************************** 00337 00338 > void Node::RenderTreeAtomic(RenderRegion* pRender) 00339 00340 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00341 Created: 29/09/2000 00342 Inputs: pRender the RenderRegion to render into. 00343 00344 Purpose: Renders the tree rooted at this node into the given RenderRegion. 00345 00346 Notes: !!! THIS FUNCTION IS NOT RECURSIVE AS OF 23/06/2004 - Phil !!! 00347 00348 *** THIS FUNCTION IS CURRENTLY RECURSIVE *** 00349 00350 *** THIS FUNCTION IS CURRENTLY ATOMIC *** 00351 So don't call it willy-nilly, as you will ruin Camelot's interruptible 00352 background rendering functionality. 00353 00354 Rendering is depth-first, with PreRenderChildren() called on all nodes. 00355 00356 This function currently goes *down* the tree, so it will miss any attributes 00357 applied to this node via its parent. To get around this, do: 00358 00359 NodeRenderableInk* pParent = (NodeRenderableInk*)pNodeToRender->FindParent(); 00360 if (pParent != NULL) 00361 { 00362 CCAttrMap* pAttrMap = CCAttrMap::MakeAppliedAttrMap(pParent); 00363 if (pAttrMap != NULL) 00364 { 00365 pAttrMap->Render(pRenderRegion); 00366 delete pAttrMap; 00367 } 00368 } 00369 pNodeToRender->RenderTreeAtomic(pRenderRegion); 00370 00371 Misconceptions: Render() does not render a tree - only one node. 00372 RenderAppliedAttributes() cannot be used generally - it is 00373 only designed for and used in the hit-test code. 00374 00375 Errors: pRender is checked for NULL in DEBUG builds. 00376 00377 ********************************************************************************************/ 00378 void Node::RenderTreeAtomic(RenderRegion* pRender) 00379 { 00380 ERROR3IF(pRender == NULL, "Node::RenderTreeAtomic; NULL pRender parameter not allowed!"); 00381 00382 pRender->RenderTree(this, FALSE); 00383 } 00384 00385 00386 00387 /******************************************************************************************** 00388 00389 > BOOL Node::NeedsToRender(RenderRegion *pRender) 00390 00391 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00392 Created: 07/02/94 00393 Inputs: pRender - the render region in question (NULL if none) 00394 Returns: TRUE => This node should be rendered, 00395 FALSE => This node does not need to be rendered. 00396 Purpose: Decide whether this node needs to be rendered, given the information 00397 provided by the parameters. 00398 This is a virtual function which defaults to returning FALSE - i.e. the 00399 node never needs to be rendered. This function should be overridden for 00400 any renderable nodes, so that they use the info provided to determine 00401 whether or not they need to be rendered. 00402 SeeAlso: Node::Render 00403 00404 ********************************************************************************************/ 00405 00406 BOOL Node::NeedsToRender(RenderRegion* pRender) 00407 { 00408 // NeedsToRender has been deprecated and replaced by RenderSubtree 00409 // It is retained in this base class for those algorithms that still have to use 00410 // NeedsToRender and FindNextForClippedInkRender 00411 // 00412 // Now implemented by calling RenderSubtree 00413 // 00414 SubtreeRenderState state = RenderSubtree(pRender); 00415 ERROR2IF(state==SUBTREE_JUMPTO, FALSE, "Complex render state return to BOOL NeedsToRender\n"); 00416 00417 return (state==SUBTREE_ROOTONLY || state==SUBTREE_ROOTANDCHILDREN); 00418 } 00419 00420 00421 /********************************************************************************************* 00422 00423 > void Node::SetRender(BOOL Status, BOOL bAndChildren=FALSE) const 00424 00425 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00426 Created: 19/4/93 00427 Inputs: val: Status of node's renderable flag 00428 Recursion flag 00429 Outputs: - 00430 Returns: - 00431 Purpose: To set Nodes renderable status (TRUE/FALSE) 00432 Errors: - 00433 00434 **********************************************************************************************/ 00435 00436 00437 void Node::SetRender(BOOL Status, BOOL bAndChildren) 00438 { 00439 Flags.Renderable = Status; 00440 00441 if (bAndChildren) 00442 { 00443 Node* pNode = FindFirstChild(); 00444 while (pNode) 00445 { 00446 pNode->SetRender(Status, bAndChildren); 00447 pNode = pNode->FindNext(); 00448 } 00449 } 00450 } 00451 00452 00453 00454 /******************************************************************************************** 00455 00456 > void Node::PreExportRender( RenderRegion* pRender ) 00457 00458 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00459 Created: 25/03/94 00460 Inputs: pRender - the render region we are exporting to. 00461 Purpose: Perform any rendering required when exporting to a file, and this node 00462 is being 'passed by' during the tree searching. For example, a group 00463 node being exported to EPS would output a "start group" token, and then 00464 its ExportRender function would output a "end group" token. 00465 By default, it does nothing. Nodes wishing to do special export processing 00466 should override this function (and ExportRender). 00467 SeeAlso: Node::ExportRender; Node::NeedsToExport 00468 00469 ********************************************************************************************/ 00470 00471 void Node::PreExportRender( RenderRegion* pRender ) 00472 { 00473 } 00474 00475 /******************************************************************************************** 00476 00477 > BOOL Node::ExportRender( RenderRegion* pRender ) 00478 00479 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00480 Created: 25/03/94 00481 Inputs: pRender - the render region we are exporting to. 00482 Returns: TRUE => Rendered (exported) ok; don't call Render(). 00483 FALSE => Exporting is the same as normal rendering; nothing has been 00484 rendered, so call the default Render() function. 00485 Purpose: Perform special export rendering of an object, if it is different to the 00486 way the object would be rendered normally (e.g. graduated fill attributes, 00487 and so on). 00488 By default, the base class function returns FALSE, so by default all 00489 objects will be exported by calling the Render() function unless they 00490 override this function. 00491 SeeAlso: Node::PreExportRender; Node::NeedsToExport 00492 00493 ********************************************************************************************/ 00494 00495 BOOL Node::ExportRender( RenderRegion* pRender ) 00496 { 00497 // By default, use normal rendering when exporting. 00498 return FALSE; 00499 } 00500 00501 /******************************************************************************************** 00502 00503 > BOOL Node::NeedsToExport(RenderRegion* pRender, BOOL VisibleLayersOnly = FALSE, 00504 BOOL CheckSelected = FALSE) 00505 00506 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00507 Created: 23/03/94 00508 Inputs: pRender - the render region we are exporting to (NULL if none) 00509 VisibleLayersOnly - TRUE => remove nodes which are on invisible layers 00510 - FALSE => export everything 00511 CheckSelected - TRUE => we check if object selected and only export selected bjects 00512 - FALSE => we don't bother checking for selection or not 00513 Returns: TRUE => Yes, export this node. 00514 FALSE => Do not export this node. 00515 Purpose: To indicate whether a given node needs to be rendered when exporting the 00516 document tree to a foreign file format. The base class always returns 00517 FALSE; if derived nodes wish to be exported they must override it and 00518 return TRUE. 00519 SeeAlso: Node::NeedsToRender. 00520 00521 ********************************************************************************************/ 00522 00523 BOOL Node::NeedsToExport(RenderRegion* pRender, BOOL VisibleLayersOnly, BOOL CheckSelected) 00524 { 00525 return FALSE; 00526 } 00527 00528 00529 00530 /******************************************************************************************** 00531 00532 > virtual String Describe(BOOL Plural, BOOL Verbose = TRUE) 00533 00534 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00535 Created: 18/6/93 00536 Inputs: Plural: Flag indicating if the string description should be plural or 00537 singular. 00538 Verbose: Flag indicating if a shortended or full description is required. 00539 Most classes will ignore this, but some (eg. Bitmaps) will just 00540 give shortended desciptions more appropriate for menus. 00541 Outputs: - 00542 Retuns: Description of the object 00543 Purpose: To return a description of the Node object in either the singular or the 00544 plural. This method is called by the DescribeRange method. 00545 00546 The description will always begin with a lower case letter. 00547 00548 Errors: A resource exception will be thrown if a problem occurs when loading the 00549 string resource. 00550 SeeAlso: - 00551 00552 ********************************************************************************************/ 00553 /* 00554 Technical Notes: 00555 00556 The String resource identifiers should be of the form: ID_<Class>_DescriptionS for the 00557 singular description and ID_<Class>_DescriptionP for the plural. 00558 */ 00559 00560 String Node::Describe(BOOL Plural, BOOL Verbose) 00561 { 00562 ENSURE (FALSE,"The illegal function Node::Describe was called\n"); 00563 00564 return( _T("") ); // Just to keep the compiler happy 00565 }; 00566 00567 /*********************************************************************************************** 00568 00569 00570 > void Node::AttachNode( Node* ContextNode, 00571 AttachNodeDirection Direction, 00572 BOOL fCheckTransparent = TRUE, 00573 BOOL InvalidateBounds = TRUE) 00574 00575 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00576 Created: 28/4/93 00577 00578 Inputs: ContextNode: Pointer to a node to which this node is to be attached 00579 00580 Direction: 00581 00582 Specifies the direction in which this node is to be attached to the 00583 ContextNode. The values this variable can take are as follows: 00584 00585 PREV : Attach node as a previous sibling of the context node 00586 NEXT : Attach node as a next sibling of the context node 00587 FIRSTCHILD: Attach node as the first child of the context node 00588 LASTCHILD : Attach node as a last child of the context node 00589 00590 fCheckTransparent whether the insertion routine should test if the 00591 node to be inserted requires transparency mode to 00592 render, and if so, to prompt the user about this. 00593 InvalidateBounds When TRUE the parents bounds + all its childrens bounds 00594 will be invalidated if this is neccessary. 00595 Outputs: - 00596 Returns: - 00597 Purpose: This method attaches the node to a context node in the direction specified 00598 by Direction. All necessary tree links are updated. 00599 00600 Errors: An assertion failure will occur if ContextNode is NULL 00601 00602 Scope: private 00603 00604 ***********************************************************************************************/ 00605 00606 void Node::AttachNode( Node* ContextNode, 00607 AttachNodeDirection Direction, 00608 BOOL fCheckTransparent, 00609 BOOL InvalidateBounds) 00610 { 00611 ERROR3IF(IsAnAttribute() && (!(((NodeAttribute*)this)->CanBeAppliedToObject())) && 00612 ContextNode->IsAnObject(), 00613 "Trying to attach invalid attribute to this object"); 00614 00615 ENSURE(ContextNode != NULL,"Trying to attach a node to a NULL node"); 00616 switch (Direction) 00617 { 00618 case PREV: // Attach node as a previous sibling of the ContextNode 00619 AttachAsPreviousNode(ContextNode); 00620 break; 00621 case NEXT: // Attach node as a next sibling of the ContextNode 00622 AttachAsNextNode(ContextNode); 00623 break; 00624 case FIRSTCHILD: // Attach node as the first child of the Context node 00625 AttachAsFirstChildNode(ContextNode); 00626 break; 00627 case LASTCHILD: // Attach node as the last child of the Context node 00628 AttachAsLastChildNode(ContextNode); 00629 break; 00630 } 00631 00632 // If an attribute is being attached which affects the parents bounds then we need to 00633 // invalidate it's parent and all children of the parent!. 00634 00635 if (InvalidateBounds) 00636 { 00637 Node* pParent = FindParent(); 00638 if (pParent != NULL) 00639 { 00640 if (pParent->IsBounded()) 00641 { 00642 BOOL AffectsParentsChildren = (this->IsAnAttribute() && ((NodeAttribute*)this)->EffectsParentBounds()); 00643 if (AffectsParentsChildren) 00644 { 00645 ((NodeRenderableBounded*)pParent)->InvalidateBoundingRect(TRUE); 00646 } 00647 } 00648 } 00649 } 00650 00651 // Set the tags for this node and any children 00652 BaseDocument* pDoc = ContextNode->FindOwnerDoc(); 00653 SetTags(pDoc); 00654 } 00655 00656 00657 /*********************************************************************************************** 00658 00659 > void Node::SetTags(BaseDocument *pOwnerDoc) 00660 00661 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00662 Created: 3/11/95 00663 Inputs: pOwnerDoc - the document that this node is in; NULL if not in a document. 00664 Purpose: Sets the tag of this node and all its descendants to a legal value, according 00665 to which document it is in, if any. 00666 00667 ***********************************************************************************************/ 00668 00669 void Node::SetTags(BaseDocument *pOwnerDoc) 00670 { 00671 // Set the tag for this node according to the document. 00672 if (pOwnerDoc != NULL) 00673 { 00674 // Only set the tag if it is not already a legal tag. 00675 if (Tag == TAG_NOT_IN_DOC) 00676 { 00677 Tag = pOwnerDoc->NewTag(); 00678 pOwnerDoc->IncNodeCount(); 00679 } 00680 } 00681 else 00682 { 00683 // Ensure this is marked as not being in a document. 00684 Tag = TAG_NOT_IN_DOC; 00685 } 00686 00687 // Now set the tags of any children of this node - start with the first child of this node. 00688 Node *pChild = FindFirstChild(); 00689 00690 while (pChild != NULL) 00691 { 00692 // Set the tags of this child and its children. 00693 pChild->SetTags(pOwnerDoc); 00694 00695 // Do the next child. 00696 pChild = pChild->FindNext(); 00697 } 00698 } 00699 00700 /*********************************************************************************************** 00701 00702 > void Node::AttachAsPreviousNode(Node* ContextNode) 00703 00704 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00705 Created: 25/4/93 00706 00707 Inputs: ContextNode: Pointer to a node to which the new node is to be attached as a 00708 previous sibling 00709 Outputs: - 00710 Returns: - 00711 Purpose: Links the node as a previous sibling of ContextNode. 00712 00713 Errors: An assertion failure will occur if ContextNode is NULL 00714 00715 Scope: private 00716 00717 ***********************************************************************************************/ 00718 /* 00719 Technical notes: 00720 00721 When linking the node as a previous sibling of the context node there are a number of 00722 cases to consider. 00723 00724 1. The context node has no existing previous sibling 00725 1.1 The context node has a parent 00726 1.2 The context node has no parent 00727 2. The context node has an existing previous sibling 00728 00729 ***********************************************************************************************/ 00730 00731 00732 void Node::AttachAsPreviousNode(Node* ContextNode) 00733 { 00734 ENSURE(ContextNode != NULL,"Trying to attach a node to a NULL node"); 00735 00736 // Check if ContextNode already has a Previous sibling 00737 if (ContextNode->Previous == NULL) // ContextNode has no previous sibling 00738 { 00739 Previous = NULL; // The new node has no previous sibling 00740 00741 // If ContextNode has a parent then ContextNode will currently be the 00742 // first child of the parent because Previous == NULL 00743 if (ContextNode->Parent != NULL) 00744 { 00745 // Make the new node the first child of ContextNode 00746 ContextNode->Parent->Child = this; 00747 } 00748 } 00749 else // Context node has a previous sibling 00750 { 00751 // The new node's Previous sibling becomes the context node's previous sibling 00752 Previous = ContextNode->Previous; 00753 // The previous siblings next sibling becomes the new node 00754 Previous->Next = this; 00755 } 00756 ContextNode->Previous = this; // Attach new node as previous sibling 00757 Next = ContextNode; // New node's next sibling is ContextNode 00758 Parent = ContextNode->Parent; // New nodes parent same as the ContextNode. 00759 } 00760 00761 00762 /*********************************************************************************************** 00763 00764 > void Node::AttachAsNextNode(Node* ContextNode) 00765 00766 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00767 Created: 25/4/93 00768 * 00769 Inputs: ContextNode: Pointer to a node to which the new node is to be attached as a 00770 next sibling 00771 Outputs: - 00772 Returns: - 00773 Purpose: Links the node as a next sibling of ContextNode. 00774 Errors: An assertion failure will occur if ContextNode is NULL 00775 Scope: Private 00776 00777 ***********************************************************************************************/ 00778 /* 00779 Technical notes: 00780 00781 When linking the node as a next sibling of the context node there are two 00782 cases to consider. 00783 00784 1. The context node has no existing next sibling 00785 2. The context node has an existing next sibling 00786 00787 ***********************************************************************************************/ 00788 00789 00790 void Node::AttachAsNextNode(Node* ContextNode) 00791 { 00792 ENSURE(ContextNode != NULL,"Trying to attach a node to a NULL node"); 00793 00794 // Check if ContextNode already has a Next sibling 00795 if (ContextNode->Next == NULL) // Context node has no next sibling 00796 Next = NULL; // New node has no next sibling 00797 else 00798 { 00799 // The new node's next sibling = the context node's next sibling 00800 Next = ContextNode->Next; 00801 // The next sibling's previous sibling becomes the new node 00802 Next->Previous = this; 00803 } 00804 ContextNode->Next = this; // Attach new node as next sibling 00805 Previous = ContextNode; // New node's previous sibling is ContextNode 00806 Parent = ContextNode->Parent; // New node's parent same as the ContextNode 00807 } 00808 00809 00810 /*********************************************************************************************** 00811 00812 > void Node::AttachAsFirstChildNode(Node* ContextNode) 00813 00814 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00815 Created: 25/4/93 00816 00817 Inputs: ContextNode: Pointer to a node to which the new node is to be attached as a 00818 first child 00819 Outputs: - 00820 Returns: - 00821 Purpose: Links the node as a first child of ContextNode. 00822 Errors: An assertion failure will occur if ContextNode is NULL 00823 Notes: This is a private method 00824 Scope: private 00825 00826 ***********************************************************************************************/ 00827 /* 00828 Technical notes: 00829 00830 When linking the node as a first child of the context node there are two 00831 cases to consider. 00832 00833 1. The context node has no existing first child 00834 2. The context node has an existing first child 00835 00836 ***********************************************************************************************/ 00837 00838 00839 void Node::AttachAsFirstChildNode(Node* ContextNode) 00840 { 00841 ENSURE(ContextNode != NULL,"Trying to attach a node to a NULL node"); 00842 00843 // Check if ContextNode already has a Child 00844 if (ContextNode->Child == NULL) 00845 Next = NULL; // If not then new node has no next sibling 00846 else 00847 { 00848 // Context node's first child becomes the new node's next sibling 00849 Next = ContextNode->Child; 00850 // The next sibling's previous sibling becomes the new node 00851 Next->Previous = this; 00852 } 00853 ContextNode->Child = this; // Attach new node as first child of context node 00854 Previous = NULL; // A first child cannot have a previous sibling 00855 Parent = ContextNode; // New node's parent is ContextNode 00856 } 00857 00858 00859 /*********************************************************************************************** 00860 00861 > void Node::AttachAsLastChildNode(Node* ContextNode) 00862 00863 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00864 Created: 25/4/93 00865 00866 Inputs: ContextNode: Pointer to a node to which the new node is to be attached as a 00867 last child 00868 Outputs: - 00869 Returns: - 00870 Purpose: Links the node as a last child of ContextNode. 00871 Errors: An assertion failure will occur if ContextNode is NULL 00872 Scope: private 00873 00874 00875 ***********************************************************************************************/ 00876 /* 00877 Technical notes: 00878 00879 When linking the node as a last child of the context node there are two 00880 cases to consider: 00881 00882 1. The context node has no existing children 00883 In this case we can attach the node as a first child 00884 2. The context node has existing children 00885 In this case we can find the current last child, and attach the node to it as a next sibling . 00886 00887 ***********************************************************************************************/ 00888 00889 00890 void Node::AttachAsLastChildNode(Node* ContextNode) 00891 { 00892 ENSURE(ContextNode != NULL,"Trying to attach a node to a NULL node"); 00893 if (!ContextNode) 00894 return; // Don't just blow up 00895 00896 if (ContextNode->Child == NULL) // The context node has no children 00897 AttachAsFirstChildNode(ContextNode); // Add node as first child of context node 00898 else 00899 { 00900 // Search for the current last child of Context node 00901 Node* np; 00902 for(np=ContextNode->Child; (np->Next != NULL); np = np->Next); 00903 // Add node as the next node of the current last child of ContextNode 00904 AttachAsNextNode(np); 00905 } 00906 } 00907 00908 /*********************************************************************************************** 00909 00910 > void Node::CascadeDelete(void) 00911 00912 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00913 Created: 26/4/93 00914 Purpose: This method removes the node from the tree and deletes all its child nodes 00915 (including hidden nodes). 00916 00917 "IT DOES NOT DELETE THE NODE ITSELF (only its children)" 00918 00919 00920 The following before and after diagram illustrates this form of deletion: 00921 00922 00923 Notes: Before:- 00924 00925 00926 MonoOn 00927 .-----. 00928 | N1 | 00929 | | 00930 .-----. 00931 | 00932 V 00933 .-----. .-----. .-----. 00934 |N2 |----->|N3 |----->| N4 | 00935 | | | | | | 00936 .-----. .-----. .-----. 00937 | 00938 V 00939 .-----. .-----. 00940 |N5 |----->|N6 | 00941 | | | | 00942 .-----. .-----. 00943 | 00944 V 00945 .-----. 00946 |N7 | 00947 | | 00948 .-----. 00949 00950 MonoOff 00951 00952 00953 After deleting node N3 00954 00955 MonoOn 00956 .-----. 00957 |N1 | 00958 | | 00959 .-----. 00960 | 00961 V 00962 .-----. .-----. 00963 |N2 |----->|N4 | 00964 | | | | 00965 .-----. .-----. 00966 00967 MonoOff 00968 00969 00970 Errors: - 00971 ***********************************************************************************************/ 00972 /* 00973 Technical notes: 00974 00975 The routine calls methods to firstly delete the children of the node, and then to unlink the 00976 node from the tree. 00977 00978 ***********************************************************************************************/ 00979 00980 00981 void Node::CascadeDelete(void) 00982 { 00983 ERROR3IF(GetHiddenCnt() != 0, "Trying to delete a node with a hidden ref cnt"); 00984 // Delete all the node's children 00985 DeleteChildren(Child); 00986 // Unlink the node from the tree 00987 UnlinkNodeFromTree(); 00988 } 00989 00990 /*********************************************************************************************** 00991 00992 > void Node::DeleteChildren(Node* FirstChild) 00993 00994 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00995 Created: 26/4/93 00996 Inputs: FirstChild: Pointer to the first child to be deleted 00997 Outputs: - 00998 Returns: - 00999 Purpose: Deletes the children and all the children's children etc. 01000 starting from FirstChild. 01001 01002 Certain nodes are not deleted but simply unlinked, these are the nodes which are 01003 pointed at by the OperationHistory. 01004 01005 NodeHidden nodes (ShowNodeActions point at them) 01006 Nodes with a HiddenCnt not equal to 0 - HiddenNodes point at them 01007 01008 01009 01010 01011 Errors: - 01012 Scope: private 01013 ***********************************************************************************************/ 01014 /* 01015 Technical notes: 01016 01017 The implementation is recursive: 01018 01019 For each child 01020 IF the child has children THEN delete the child's children 01021 delete the child 01022 01023 01024 ***********************************************************************************************/ 01025 01026 01027 void Node::DeleteChildren(Node* FirstChild) 01028 { 01029 Node* CurrentNode = FirstChild; 01030 01031 if (ShowHourglass()) 01032 { 01033 ContinueSlowJob(); 01034 } 01035 01036 BaseDocument *pOwnerDoc = NULL; 01037 01038 if (FirstChild != NULL) 01039 FirstChild->FindOwnerDoc(); 01040 01041 while (CurrentNode != NULL) // While there are children left to process 01042 { 01043 Node* NextNode = CurrentNode->Next; 01044 // It is not the job of DeleteChildren to delete HiddenNodes or nodes pointed to by hidden nodes 01045 // They should be considered to be in the OperationHistory 01046 if ( (!CurrentNode->IsNodeHidden()) && (CurrentNode->GetHiddenCnt() == 0) ) 01047 { 01048 if (CurrentNode->Child != NULL) // There are children to delete 01049 DeleteChildren(CurrentNode->Child); 01050 01051 // Unlink from tree before deleting it 01052 CurrentNode->UnlinkNodeFromTree(pOwnerDoc); // Nice and safe !!!! 01053 01054 delete CurrentNode; // Current node has no children so can be deleted 01055 } 01056 else 01057 CurrentNode->UnlinkNodeFromTree(pOwnerDoc); 01058 01059 CurrentNode = NextNode; // Process next sibling 01060 01061 if (ShowHourglass()) 01062 { 01063 ContinueSlowJob(); 01064 } 01065 01066 } //end while 01067 Child = NULL; 01068 } 01069 01070 01071 /*********************************************************************************************** 01072 01073 > void Node::UnlinkNodeFromTree(BaseDocument *pOwnerDoc == NULL) 01074 01075 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01076 Created: 26/4/93 01077 Inputs: pOwnerDoc - pointer to the document that this node is in. This is used to 01078 update the node count. If it is NULL, then the tree is scanned 01079 upwards to find the owner document instead. This is merely a 01080 performance enhancement, so that if a lot of nodes are being 01081 deleted, then we don't have to scan the tree all the time. 01082 01083 This parameter is passed in automatically by Node functions which 01084 delete many nodes in one go, such as: 01085 01086 Node::CascadeDelete 01087 Node::DeleteChildren 01088 ... 01089 etc. 01090 01091 Purpose: Unlinks the node from the tree. 01092 SeeAlso: Node::FindOwnerDoc 01093 01094 ***********************************************************************************************/ 01095 /* 01096 Technical notes: 01097 01098 When unlinking the node there are a number of cases to consider: 01099 01100 1. The Node has a previous node 01101 01102 2. The Node has no previous node 01103 2.1 The node has a parent 01104 2.2 The node has no parent 01105 01106 3. The Node has a next node 01107 4. The Node has no next Node 01108 01109 ***********************************************************************************************/ 01110 01111 void Node::UnlinkNodeFromTree(BaseDocument *pOwnerDoc) 01112 { 01113 // Find the owner document if we don't have one 01114 if (pOwnerDoc == NULL) 01115 pOwnerDoc = FindOwnerDoc(); 01116 01117 // Update the node count if this node is actually in a document 01118 if (pOwnerDoc != NULL) 01119 pOwnerDoc->DecNodeCount(); 01120 01121 // Inform classes that may be holding pointers to this node 01122 RenderRegionList* pRList = GetApplication()->GetRegionList(); 01123 if (pRList) 01124 pRList->HandleNodeDeletion(this); 01125 01126 if (pOwnerDoc && pOwnerDoc->IsKindOf(CC_RUNTIME_CLASS(Document))) 01127 ((Document*)pOwnerDoc)->HandleNodeDeletion(this); 01128 01129 // Now do the actual unlinking 01130 if (Previous == NULL) // Node must be a first child or root 01131 { 01132 if (Parent != NULL) // Node is a first child 01133 // The parent's new first child is the next sibling of the node being deleted 01134 Parent->Child = Next; 01135 } 01136 else 01137 //The previous node's next sibling becomes the node's Next sibling 01138 Previous->Next = Next; 01139 01140 if (Next != NULL) 01141 //The next node's previous sibling becomes the node's Previous sibling 01142 Next->Previous = Previous; 01143 01144 // Remove nodes links into the tree 01145 Next = NULL; 01146 Previous = NULL; 01147 Parent = NULL; 01148 } 01149 01150 01151 01152 /*********************************************************************************************** 01153 01154 > BOOL Node::CopyNode(Node* Destination, 01155 AttachNodeDirection Direction) 01156 01157 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01158 Created: 28/4/93 01159 01160 Inputs: Destination: The destination node the copied node is to be attached to. 01161 01162 Direction: 01163 01164 Specifies the direction in which the copied node is to be attached to the 01165 Destination node. The values this variable can take are as follows: 01166 01167 PREV : Attach node as a previous sibling of the destination node 01168 NEXT : Attach no de as a next sibling of the destination node 01169 FIRSTCHILD: Attach node as the first child of the destination node 01170 LASTCHILD : Attach node as a last child of the destination node 01171 01172 Outputs: 01173 Returns: FALSE if memory ran out during the copy. 01174 Otherwise TRUE. 01175 01176 Purpose: This method creates a 'deep' copy of the node and then attaches it to the 01177 destination node. The Direction input specifies how the node is to be 01178 attached to the Destination node. The following before and after diagram 01179 illustrates this method. 01180 01181 Notes: Before:- 01182 01183 MonoOn 01184 .-----. .-----. .-----. 01185 |N1 |----->|N2 |----->| N3 | 01186 | | | | | | 01187 .-----. .-----. .-----. 01188 | 01189 V 01190 .-----. .-----. 01191 |N4 |----->|N5 | 01192 | | | | 01193 .-----. .-----. 01194 01195 MonoOff 01196 01197 After copying node N2 to destination N2 as a next sibling:- 01198 01199 01200 MonoOn 01201 .-----. .-----. .-----. .-----. 01202 |N1 |----->|N2 |------------->| N2C |----->|N3 | 01203 | | | | | | | | 01204 .-----. .-----. .-----. .-----. 01205 | | 01206 V V 01207 .-----. .-----. .-----. .-----. 01208 |N4 |----->|N5 | |N4C |----->|N5C | 01209 | | | | | | | | 01210 .-----. .-----. .-----. .-----. 01211 MonoOff 01212 01213 Errors: If memory is exhausted whilst copying, the routine returns FALSE after 01214 deleting any partially copied subtree. 01215 01216 ***********************************************************************************************/ 01217 /* 01218 Technical notes: 01219 01220 This method makes a call to the recursive CopyChildren to create a copy of the subtree, and 01221 then attaches the subtree to the destination node. 01222 01223 ***********************************************************************************************/ 01224 01225 BOOL Node::CopyNode(Node* DestinationNode, AttachNodeDirection Direction) 01226 { 01227 // Get a copy of the subtree 01228 if (ShowHourglass()) 01229 { 01230 ContinueSlowJob(); 01231 } 01232 01233 Node* NewNode; 01234 if (!NodeCopy(&NewNode)) 01235 return FALSE; 01236 01237 // Attach the copied node to the Destination node 01238 NewNode->AttachNode(DestinationNode, Direction); 01239 return (TRUE); 01240 } 01241 01242 01243 /******************************************************************************************** 01244 01245 > BOOL Node::NodeCopy(Node** NodeCopy) 01246 01247 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> / Mike 01248 Created: 4/3/94 01249 Inputs: - 01250 Outputs: NodeCopy: A deep copy of the node if Successful 01251 Returns: - 01252 Purpose: This method outputs a 'deep' copy of the node. It is the same as CopyNode 01253 except that the copy is not linked into the tree. 01254 01255 Errors: - 01256 SeeAlso: Node::CopyNode 01257 01258 ********************************************************************************************/ 01259 01260 BOOL Node::NodeCopy(Node** ppNodeCopy) 01261 { 01262 Node* NewNode =