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 = SimpleCopy(); 01263 if (NewNode == FALSE) 01264 return (FALSE); // Out of memory 01265 01266 if (!CopyChildren(Child, NewNode, ccALL)) // Out of memory 01267 { 01268 DeleteChildren(NewNode->Child); 01269 delete NewNode; 01270 return (FALSE); 01271 } 01272 01273 *ppNodeCopy = NewNode; 01274 return (TRUE); 01275 } 01276 01277 01278 /******************************************************************************************** 01279 01280 > BOOL Node::CloneNode(Node** ppNodeCopy, BOOL bLightweight) 01281 01282 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 01283 Created: 23/07/2005 01284 Inputs: bLightweight - Only copy what you really need, 01285 Make references to original large data items instead of copying them 01286 if possible 01287 Outputs: NodeCopy: A deep copy of the node if Successful 01288 Returns: - 01289 Purpose: This method outputs a 'deep' copy of the node. It is the same as CopyNode 01290 except that the copy is not linked into the tree. 01291 Override if yor class can interpret the lightweight flag 01292 01293 Errors: - 01294 SeeAlso: Node::CopyNode 01295 01296 ********************************************************************************************/ 01297 01298 BOOL Node::CloneNode(Node** ppNodeCopy, BOOL bLightweight) 01299 { 01300 return NodeCopy(ppNodeCopy); 01301 } 01302 01303 01304 /******************************************************************************************** 01305 01306 > BOOL Node::CopyComplexRange(Range& RangeToCopy) 01307 01308 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01309 Created: 4/5/95 01310 Inputs: RangeToCopy - identifies the range of nodes to copy 01311 Outputs: 01312 Returns: - 01313 Purpose: Copy the series of nodes described by RangeToCopy and attach them to 01314 onto the last child position of this object. 01315 Errors: - 01316 SeeAlso: Node::CopyNode 01317 01318 ********************************************************************************************/ 01319 01320 BOOL Node::CopyComplexRange(Range& RangeToCopy) 01321 { 01322 BOOL Failed=FALSE; 01323 Node* Current = RangeToCopy.FindFirst(); 01324 Node* NewNode; 01325 01326 std::list<Node *> ListOfNodes(30); 01327 01328 while (Current!=NULL) 01329 { 01330 CopyType ctype = Current->GetCopyType(); 01331 switch (ctype) 01332 { 01333 case SIMPLECOPY: 01334 { 01335 Failed = !(Current->CopyNode(this, LASTCHILD)); 01336 01337 // kludge, should be part of post-copy system which does not exist!! 01338 // unwrap any text story on the clipboard 01339 if (IS_A(Current,TextStory)) 01340 { 01341 Node* pLastChild = this->FindLastChild(); 01342 if (IS_A(pLastChild,TextStory)) 01343 Failed = !((TextStory*)pLastChild)->UnWrapStory(NULL); 01344 else 01345 { 01346 ERROR2RAW("Node::CopyComplexRange() - did not find the story"); 01347 Failed = TRUE; 01348 } 01349 } 01350 01351 break; 01352 } 01353 01354 case COMPLEXCOPY: 01355 { 01356 INT32 success = Current->ComplexCopy(COPYOBJECT, RangeToCopy, &NewNode); 01357 // success=-1 then error 01358 // success= 0 then ignore 01359 // success= 1 then attach NewNode 01360 if (success>0) 01361 { 01362 NewNode->AttachNode(this, LASTCHILD); 01363 // we need to save a list of these nodes for a call back 01364 ListOfNodes.push_back( Current ); 01365 ListOfNodes.push_back( NewNode ); 01366 } 01367 01368 Failed=(success<0); 01369 break; 01370 } 01371 01372 default: 01373 { 01374 ERROR2RAW("Illegal copy type returned to CopyComplexRange()"); 01375 Failed=TRUE; 01376 break; 01377 } 01378 } 01379 01380 // if we haven't copied properly, tidy up and exit the loop 01381 if (Failed) 01382 break; 01383 01384 Current = RangeToCopy.FindNext(Current); 01385 } 01386 01387 // Now call the nodes complex copy functions again to say we've done something. 01388 // But only call those we have already! 01389 01390 while( !ListOfNodes.empty() ) 01391 { 01392 Node *pCopy = (Node *)ListOfNodes.back(); ListOfNodes.pop_back(); 01393 Node *pRecall = (Node *)ListOfNodes.back(); ListOfNodes.pop_back(); 01394 01395 if( pRecall && pCopy && pRecall->GetCopyType() == COMPLEXCOPY ) 01396 pRecall->ComplexCopy( COPYFINISHED, RangeToCopy, &pCopy ); 01397 } 01398 01399 /* 01400 if (Current!=NULL) 01401 Current=RangeToCopy.FindNext(Current); 01402 01403 Node* Recall = RangeToCopy.FindFirst(); 01404 while ((Recall!=Current) && (Recall!=NULL)) 01405 { 01406 if (Recall->GetCopyType()==COMPLEXCOPY) 01407 Recall->ComplexCopy(COPYFINISHED, RangeToCopy, &NewNode); 01408 Recall = RangeToCopy.FindNext(Recall); 01409 } 01410 */ 01411 01412 return (!Failed); 01413 } 01414 01415 01416 01417 01418 01419 01420 01421 01422 /*********************************************************************************************** 01423 01424 > BOOL Node::CopyChildren(Node* FirstChild, 01425 Node* NewParent, 01426 CopyControlFlags CopyFlags=ccALL) 01427 01428 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> / Mike 01429 Created: 28/4/93 01430 01431 Inputs: FirstChild: The first child of the subtree to be copied 01432 NewParent: The parent to which all copied children will be attached 01433 CopyFlags: The copy control flags (defaults to ALLOBJECTS) 01434 01435 Outputs: Attaches children of the subtree to NewParent. 01436 01437 Returns: FALSE if we run out of memory during a copy 01438 Otherwise TRUE 01439 01440 Purpose: This private method makes a copy of all the subtree's children and attaches 01441 them to NewParent (the root of the new subtree). It is a helper method for 01442 CopyTree. 01443 01444 Errors: If a memory allocation error occurs then FALSE is returned. 01445 01446 Scope: private 01447 ***********************************************************************************************/ 01448 /* 01449 Technical notes: 01450 01451 The algorithm recursively copies each child,and each of the child's children etc. 01452 01453 The routine returns the partially copied tree when a memory error occurs rather 01454 than deleting it. The reason for this is that the deletion is easier to perform in the 01455 calling function because of the recursive nature of CopyChildren. 01456 01457 01458 ***********************************************************************************************/ 01459 01460 BOOL Node::CopyChildren(Node* FirstChild, Node* NewParent, CopyControlFlags CopyFlags) 01461 { 01462 if (ShowHourglass()) 01463 { 01464 ContinueSlowJob(); 01465 } 01466 BOOL CopyObject=FALSE; 01467 01468 // Find out the destination document, if any. 01469 BaseDocument* pDoc = NewParent->FindOwnerDoc(); 01470 01471 NewParent->Child = NULL; // Just in case no nodes are copied 01472 01473 if (FirstChild != NULL) // New parent has children 01474 { 01475 Node* CurrentChild = FirstChild; 01476 Node* LastNewChild = NULL; 01477 while (CurrentChild != NULL) // While there are children left to copy 01478 { 01479 // We don't copy hidden nodes or the insertion node. 01480 if (!CurrentChild->IsNodeHidden() && !CurrentChild->IsAnInsertionNode()) 01481 { 01482 switch (CopyFlags) 01483 { 01484 case ccALL: 01485 CopyObject=TRUE; 01486 break; 01487 case ccLOCKED: 01488 CopyObject=((CurrentChild->IsLocked())!=0); 01489 break; 01490 case ccMANGLED: 01491 CopyObject=((CurrentChild->IsMangled())!=0); 01492 break; 01493 case ccMARKED: 01494 CopyObject=((CurrentChild->IsMarked())!=0); 01495 break; 01496 case ccSELECTED: 01497 CopyObject=((CurrentChild->IsSelected())!=0); 01498 break; 01499 case ccRENDERABLE: 01500 CopyObject=((CurrentChild->IsRenderable())!=0); 01501 break; 01502 } 01503 01504 if (CopyObject) 01505 { 01506 Node* NewChild = CurrentChild->SimpleCopy(); // Copy current node (virtual method) 01507 01508 if (NewChild == NULL) // Out of memory 01509 return FALSE; 01510 01511 // Attach the NewChild node to the previous or parent node 01512 if (LastNewChild != NULL) // Child is not a first child 01513 LastNewChild->Next = NewChild; 01514 else // Child is a first child 01515 NewParent->Child = NewChild; // NewParent's first child is the NewChild 01516 01517 NewChild->Parent = NewParent; // The parent of the new child node is NewParent 01518 NewChild->Previous = LastNewChild; // The previous sibling of the new child 01519 01520 // Karim 16/01/01 - GLA's must be re-linked up when they are copied. 01521 if (NewChild->IsAnAttribute() && ((NodeAttribute*)NewChild)->IsLinkedToNodeGeometry()) 01522 ((NodeAttribute*)NewChild)->LinkToGeometry(NewParent); 01523 01524 // Ensure that this new node has the correct tag. 01525 if (pDoc != NULL) 01526 { 01527 NewChild->Tag = pDoc->NewTag(); 01528 pDoc->IncNodeCount(); 01529 } 01530 else 01531 { 01532 // Ensure this is marked as not being in a document. 01533 NewChild->Tag = TAG_NOT_IN_DOC; 01534 } 01535 01536 if (CurrentChild->Child != NULL) // There are children to copy 01537 if(!CopyChildren(CurrentChild->Child,NewChild,CopyFlags))// Recursively copy child's children 01538 return (FALSE); // Out of memory 01539 01540 LastNewChild = NewChild; // Need to remember this for next/prev links 01541 } 01542 } 01543 CurrentChild = CurrentChild->Next; // Process next sibling 01544 01545 if (ShowHourglass()) 01546 { 01547 ContinueSlowJob(); 01548 } 01549 01550 } 01551 } 01552 return TRUE; // No errors occurred 01553 } 01554 01555 01556 /* 01557 01558 BOOL Node::CopyChildren(Node* FirstChild, Node* NewParent) 01559 { 01560 if (ShowHourglass()) 01561 { 01562 ContinueSlowJob(); 01563 } 01564 01565 // Find out the destination document, if any. 01566 BaseDocument* pDoc = NewParent->FindOwnerDoc(); 01567 01568 01569 NewParent->Child == NULL; // Just in case no nodes are copied 01570 01571 if (FirstChild != NULL) // New parent has children 01572 { 01573 Node* CurrentChild = FirstChild; 01574 Node* LastNewChild = NULL; 01575 while (CurrentChild != NULL) // While there are children left to copy 01576 { 01577 // We don't copy hidden nodes 01578 if (CurrentChild->GetRuntimeClass() != CC_RUNTIME_CLASS(NodeHidden)) 01579 { 01580 Node* NewChild = CurrentChild->SimpleCopy(); // Copy current node (virtual method) 01581 if (NewChild == NULL) // Out of memory 01582 { 01583 return (FALSE); 01584 } 01585 01586 // Attach the NewChild node to the previous or parent node 01587 if (LastNewChild != NULL) // Child is not a first child 01588 LastNewChild->Next = NewChild; 01589 else // Child is a first child 01590 { 01591 NewParent->Child = NewChild; // NewParent's first child is the NewChild 01592 } // EndElse 01593 01594 NewChild->Parent = NewParent; // The parent of the new child node is NewParent 01595 NewChild->Previous = LastNewChild; // The previous sibling of the new child 01596 01597 // Ensure that this new node has the correct tag. 01598 if (pDoc != NULL) 01599 { 01600 NewChild->Tag = pDoc->NewTag(); 01601 pDoc->IncNodeCount(); 01602 } 01603 else 01604 { 01605 // Ensure this is marked as not being in a document. 01606 NewChild->Tag = TAG_NOT_IN_DOC; 01607 } 01608 01609 if (CurrentChild->Child != NULL) // There are children to copy 01610 if(!CopyChildren(CurrentChild->Child,NewChild))// Recursively copy child's children 01611 return (FALSE); // Out of memory 01612 01613 LastNewChild = NewChild; // Need to remember this for next/prev links 01614 } 01615 CurrentChild = CurrentChild->Next; // Process next sibling 01616 01617 if (ShowHourglass()) 01618 { 01619 ContinueSlowJob(); 01620 } 01621 01622 } //end while 01623 } //end else 01624 return (TRUE); // No errors occurred 01625 } 01626 01627 */ 01628 01629 01630 01631 /******************************************************************************************** 01632 01633 > BOOL Node::CopyChildrenTo(Node* DestinationNode, CopyControlFlags CopyFlags=ccALL) 01634 01635 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01636 Created: 4/5/94 01637 Inputs: DestinationNode = a pointer to the node to copy this nodes children to 01638 CopyFlags = copy control flags indicating what flagged nodes to copy 01639 defaults to ccALL meaning copy every node. 01640 Outputs: - 01641 Returns: FALSE if we run out of memory during a copy 01642 Otherwise TRUE. 01643 01644 Purpose: This function copies the node's children to DestinationNode which should 01645 initially have no children. 01646 01647 If we run out of memory during a copy all copied nodes are deleted 01648 Errors: - 01649 SeeAlso: - 01650 01651 ********************************************************************************************/ 01652 01653 BOOL Node::CopyChildrenTo(Node* DestinationNode, CopyControlFlags CopyFlags) 01654 { 01655 Node* FirstChild = FindFirstChild(); 01656 if (FirstChild != NULL) 01657 { 01658 if (!CopyChildren(FirstChild, DestinationNode, CopyFlags)) 01659 { 01660 DeleteChildren(DestinationNode->FindFirstChild()); 01661 return (FALSE); 01662 } 01663 } 01664 return TRUE; 01665 } 01666 01667 01668 01669 /******************************************************************************************** 01670 01671 > virtual CopyType Node::GetCopyType() 01672 01673 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01674 Created: 3/5/95 01675 Inputs: - 01676 Returns: A copy type describing how to copy this object 01677 Purpose: This function returns a type describing how this object is to be copied. 01678 The fuction is called from the low level copy operation CopyObjects. 01679 There are two options at present, these being SIMPLECOPY and COMPLEXCOPY. 01680 SIMPLECOPY indicates that the node can be copied by a call to its virtual 01681 function SimpleCopy() followed by a deep copy of all its children. 01682 COMPLEXCOPY however indicates that the node needs to do its own thing when 01683 copying and must be called via the ComplexCopy() virtual function. This 01684 virtual will likely return a tree of copied objects rather than just a 01685 copy of itself. 01686 01687 ********************************************************************************************/ 01688 01689 CopyType Node::GetCopyType() 01690 { 01691 return SIMPLECOPY; 01692 } 01693 01694 01695 /*********************************************************************************************** 01696 01697 > Node* Node::SimpleCopy() 01698 01699 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01700 Created: 28/4/93 01701 01702 Inputs: - 01703 Outputs: 01704 Returns: A copy of the node, or NULL if we are out of memory 01705 01706 Purpose: This method returns a shallow copy of the node with all Node pointers NULL. 01707 The function is virtual, and must be defined for all derived classes of Node 01708 01709 Errors: If memory runs out when trying to copy, then ERROR is called with an out of memory 01710 error and the function returns NULL. 01711 01712 Scope: Protected 01713 01714 ***********************************************************************************************/ 01715 /* 01716 Technical notes: 01717 01718 This function needs to be virtual so that it can return a correct object type. 01719 The method delegates the copying of the Nodes contents to the CopyNodeContents method. 01720 01721 The method templates below show how the SimpleCopy and CopyNodeContents methods should be 01722 defined in each derived class of Node. 01723 01724 virtual Node* <Node derived class>::SimpleCopy() 01725 { 01726 Node* NodeCopy = new <Node derived class>(); 01727 ERRORIF(NodeCopy == NULL, _R(IDE_NOMORE_MEMORY), NULL); 01728 CopyNodeContents(nodeCopy); 01729 return (nodeCopy) 01730 } 01731 01732 void <Node derived class>::CopyNodeContents(<Node derived class>* nodeCopy) 01733 { 01734 <Base class>::CopyNodeContents(nodeCopy) 01735 01736 //Copy contents specific to derived class here 01737 } 01738 01739 ***********************************************************************************************/ 01740 01741 Node* Node::SimpleCopy() 01742 { 01743 Node* NodeCopy; 01744 // Will need to handle this 01745 NodeCopy = new Node(); // Allocate a new node 01746 ERRORIF( NodeCopy == NULL, _R(IDE_NOMORE_MEMORY), NULL ); 01747 CopyNodeContents(NodeCopy); 01748 return (NodeCopy); 01749 } 01750 01751 /*********************************************************************************************** 01752 01753 > void Node::CopyNodeContents(Node* NodeCopy) 01754 01755 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01756 Created: 28/4/93 01757 Inputs: 01758 Outputs: A copy of this node 01759 Returns: - 01760 Purpose: This method copies the node's contents to the node pointed to by NodeCopy. 01761 Errors: An assertion failure will occur if NodeCopy is NULL 01762 Scope: protected 01763 01764 ***********************************************************************************************/ 01765 01766 void Node::CopyNodeContents(Node* NodeCopy) 01767 { 01768 ENSURE(NodeCopy != NULL,"Trying to copy node contents to\na node pointed to by a NULL pointer"); 01769 NodeCopy->Flags = Flags; 01770 // All tree pointers are NULL 01771 // Phil, 7/1/2004 01772 // DO NOT blat the tree pointers because the node may already be in the tree!!! 01773 // NodeCopy->Previous=NodeCopy->Next=NodeCopy->Parent=NodeCopy->Child = NULL; 01774 } 01775 01776 01777 /*********************************************************************************************** 01778 01779 > Node* Node::PublicCopy() 01780 01781 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 01782 Created: 17/11/99 01783 Inputs: 01784 Outputs: A copy of this node 01785 Returns: - 01786 Purpose: This method copies the node's contents to the node pointed to by NodeCopy. 01787 Errors: An assertion failure will occur if NodeCopy is NULL 01788 Scope: protected 01789 01790 ***********************************************************************************************/ 01791 01792 Node* Node::PublicCopy() 01793 { 01794 return SimpleCopy(); 01795 } 01796 01797 01798 /******************************************************************************************** 01799 01800 > virtual INT32 Node::ComplexCopy(CopyStage Stage, Range& RangeToCopy, Node** pOutput) 01801 01802 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01803 Created: 3/5/95 01804 Inputs: Stage - COPYOBJECT if we should make a copy 01805 - COPYFINISHED once the entire copy operation has completed 01806 RangeToCopy - Describes the range which is currently being copied. 01807 pOutput - Depends on the Stage parameter 01808 if Stage= 01809 COPYOBJECT 01810 Then the node pointer pOutput points at NULL. It should be 01811 set on exit to point at the copied object or tree of objects 01812 COPYFINISHED 01813 Then the node pointer pOutput points at the resulting copy 01814 from COPYOBJECT inserted into the destination tree. 01815 Outputs: pOutput 01816 Returns: -1 = The routine failed to make a copy. 01817 0 = No copy has been made for this node. 01818 +1 = pOutput points to the copy created. 01819 01820 Purpose: This virtual function is useful for nodes needing to control how they are 01821 to be copied. It is overridden currently by text characters and line 01822 objects. These objects cannot exist outside the context of a text story. 01823 Hence when copying a character object, the parent line object and text 01824 story object must be copied along with it. 01825 To do this we must give an object the ability to copy whatever it needs 01826 to along with itself. In order to do that, the object needs to override 01827 this virtual function and the associated GetCopyType() function. 01828 ( Normally nodes which are not associated with a particular grouping will 01829 not need to override either of these functions. The copy mechanism defaults 01830 to using SimpleCopy(), whereby every node is copied as is ). 01831 01832 Copy stages: 01833 If the copy stage is COPYOBJECT, the node has been called to copy itself 01834 and do what ever it needs to to make a sensible copy of other items such 01835 as attributes. The caller (CopyObjects) will not deep copy this node 01836 (as this is a complex copy and it expects the handler to know what its doing). 01837 If the copy stage is COPYFINISHED, the node should tidy up any bits it has 01838 left over after a copy. Some nodes set bits to indicate that a complex copy 01839 is taking place. This allows them to ignore multiple calls to complex copy 01840 if the bit is set. 01841 01842 Note: Imagine you override this function for a particular node pN which 01843 exists as a selectable item inside a common parent cP. Now, for you to do 01844 so obviously means that pN cannot exist outside cP and pN can be selected 01845 without pN being selected. Not to override this function would ofcourse 01846 allow pN to be copied to the clipboard by itself which may be hazardous. 01847 So overriding the function will allow you to make a copy of cP and pN 01848 together, when the function is called. You do not need to override this 01849 function inside the class pN. When pN is selected a SimpleCopy() copies 01850 it and all its children automatically ensuring validity. Its soley for use 01851 by children that need their parents! 01852 01853 SeeAlso: Node::GetCopyType(), InternalClipboard::CopyObjects() 01854 01855 ********************************************************************************************/ 01856 01857 INT32 Node::ComplexCopy(CopyStage Stage, Range& RangeToCopy, Node** pOutput) 01858 { 01859 return -1; 01860 } 01861 01862 01863 /*********************************************************************************************** 01864 01865 > void Node::MoveNode(Node* Destination, 01866 AttachNodeDirection Direction) 01867 01868 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01869 Created: 28/4/93 01870 01871 Inputs: Destination: The destination node which the node is to be attached to. 01872 01873 Direction: 01874 01875 Specifies the direction in which the node is to be attached to the 01876 Destination node. The values this variable can take are as follows: 01877 01878 PREV : Attach node as a previous sibling of the destination node 01879 NEXT : Attach node as a next sibling of the destination node 01880 FIRSTCHILD: Attach node as the first child of the destination node 01881 LASTCHILD : Attach node as a last child of the destination node 01882 01883 Note: The destination node should not be the same as, or any child of node. 01884 01885 Outputs: - 01886 Returns: - 01887 Purpose: This method moves a node from its existing position in the tree to a 01888 new node position specified by Destination. The Direction input specifies 01889 how the node is to be attached to the Destination node. The following 01890 before and after diagram illustrates this method. 01891 01892 01893 Notes: Before:- 01894 01895 MonoOn 01896 01897 .-----. .-----. .-----. 01898 |N1 |----->|N2 |----->| N3 | 01899 | | | | | | 01900 .-----. .-----. .-----. 01901 | 01902 V 01903 .-----. .-----. 01904 |N4 |----->|N5 | 01905 | | | | 01906 .-----. .-----. 01907 01908 MonoOff 01909 01910 After moving node N2 to destination N3 as a first child:- 01911 01912 01913 MonoOn 01914 .-----. .-----. 01915 |N1 |----->| N3 | 01916 | | | | 01917 .-----. .-----. 01918 | 01919 V 01920 .-----. 01921 |N2 | 01922 | | 01923 .-----. 01924 | 01925 V 01926 .-----. .-----. 01927 |N4 |----->|N5 | 01928 | | | | 01929 .-----. .-----. 01930 01931 01932 MonoOff 01933 01934 Errors: An assertion error will occur if the DestinationNode is NULL 01935 01936 ***********************************************************************************************/ 01937 /* 01938 Technical notes: 01939 01940 The method makes calls to firstly unlink the node from its current position in the 01941 tree, and then to attach it to its new position in the tree. 01942 01943 ***********************************************************************************************/ 01944 01945 01946 void Node::MoveNode(Node* DestinationNode, 01947 AttachNodeDirection Direction) 01948 { 01949 ENSURE(DestinationNode != NULL,"Trying to copy a node to a node pointed to by a NULL pointer"); 01950 01951 UnlinkNodeFromTree(); // Remove the node from the tree 01952 AttachNode(DestinationNode, Direction); 01953 } 01954 01955 /******************************************************************************************** 01956 01957 > virtual UINT32 Node::GetNodeSize() const 01958 01959 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01960 Created: 6/10/93 01961 Inputs: - 01962 Outputs: - 01963 Returns: The size of the node in bytes 01964 Purpose: For finding the size of a node, in concrete classes derived from Node. 01965 Errors: If this function has not been overloaded in a non-abstract class then an 01966 ENSURE failure will occur. 01967 01968 01969 SeeAlso: - 01970 01971 ********************************************************************************************/ 01972 01973 UINT32 Node::GetNodeSize() const 01974 { 01975 //ENSURE(FALSE, "Pseudo pure virtual GetSize() function called"); 01976 //return (0); 01977 return sizeof(*this); 01978 } 01979 01980 /******************************************************************************************** 01981 01982 > UINT32 Node::GetSubtreeSize() const 01983 01984 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01985 Created: 6/10/93 01986 Inputs: - 01987 Outputs: - 01988 Returns: The size of the subtree in bytes 01989 Purpose: For finding the size of this subtree 01990 01991 SeeAlso: - 01992 01993 ********************************************************************************************/ 01994 01995 UINT32 Node::GetSubtreeSize() 01996 { 01997 UINT32 Total = 0; 01998 Node* Current = this->FindFirstDepthFirst(); 01999 while (Current != NULL) 02000 { 02001 Total += Current->GetNodeSize(); 02002 Current = Current->FindNextDepthFirst(this); 02003 } 02004 return Total; 02005 } 02006 02007 /********************************************************************************************* 02008 02009 > BOOL Node::IsChildOfSelected() const 02010 02011 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 02012 Created: 19/9/95 02013 Returns: TRUE if the node has a selected parent. 02014 FALSE otherwise 02015 Purpose: For finding out whether this node has a selected parent. 02016 Note: If a group (node) of a number of objects is selected then only the group 02017 node itself has the selected flag set. Any children of this group, i.e. objects 02018 in the group would also be deemed selected but would not have the selected bit set. 02019 This routine is based on the routine View::IsPrintableNodeSelected and just 02020 searches up until it finds a layer. If by then it has found a selected flag then 02021 its parent must be selected and hence it is. 02022 SeeAlso: View::IsPrintableNodeSelected; 02023 02024 **********************************************************************************************/ 02025 02026 BOOL Node::IsChildOfSelected() 02027 { 02028 // We must check the selected status of this node. 02029 // Even if this node is not selected, its parent might be, so we 02030 // scan upwards until we find a layer, or a selected node. 02031 Node *pTestNode = this; 02032 while ((pTestNode != NULL) && 02033 (!pTestNode->IsSelected()) && 02034 (!pTestNode->IsLayer())) 02035 { 02036 pTestNode = pTestNode->FindParent(); 02037 } 02038 02039 // Ok, what did we find? 02040 return ((pTestNode != NULL) && pTestNode->IsSelected()); 02041 } 02042 02043 /********************************************************************************************* 02044 02045 > BOOL Node::IsUnder(Node* pTestNode, bFirstCall = TRUE) const 02046 02047 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02048 Created: 02/08/2004 02049 Inputs: pTestNode - pointer to node to test against 02050 Outputs: - 02051 Returns: TRUE if this node is "under" the specified node. 02052 FALSE otherwise 02053 Purpose: For finding out whether this node is under another node. Where "under" is 02054 defined as being before it in rendering order. 02055 To find the answer quickly without scanning the entire tree, we will find 02056 the common root node of both this and pNode and find out whether the child 02057 links from that node lead down to this node first or pTestNode first. 02058 (Because if my parent is under the test node then so am I) 02059 Do this recursively so that state is held on the stack, not in the tree 02060 Clever, huh? 02061 There is some strictly unneccessary work done in finding the common 02062 ancestor in this implementation but it's the best compromise that is both 02063 reasonably fast and completely stateless. 02064 SeeAlso: - 02065 02066 **********************************************************************************************/ 02067 02068 BOOL Node::IsUnder(Node* pTestNode, BOOL bFirstCall) const 02069 { 02070 ENSURE(this, "IsUnder called on NULL"); 02071 if (this==NULL) 02072 return FALSE; 02073 02074 if (bFirstCall && this==pTestNode) 02075 return FALSE; 02076 02077 Node* pMyParent = FindParent(); 02078 Node* pTestParent = pTestNode->FindParent(); 02079 Node* pChild = pTestNode; 02080 02081 ENSURE(pTestNode, "IsUnder called with NULL pointer to test"); 02082 ENSURE(this!=pTestNode, "IsUnder called with pointer to this"); 02083 ENSURE(pMyParent, "IsUnder can't find parent of this"); 02084 02085 // ENSURE(HiddenRefCnt==0, "IsUnder called on hidden node(s)"); 02086 02087 if (pTestNode == pMyParent) // If the test node is one of my ancestors 02088 return TRUE; // Then I am under it (in render order) 02089 02090 // Scan up from the test node, checking for the common ancestor 02091 while (pTestParent) 02092 { 02093 // ENSURE(pTestParent->HiddenRefCnt==0, "IsUnder called on hidden node(s)"); 02094 02095 if (pTestParent == pMyParent) 02096 { 02097 // Found the common ancestor! 02098 // Now compare positions in the sibling list 02099 // This commented out code is the naive version 02100 // Node* pNode = (Node*)this; 02101 // while (pNode && pNode != pChild) 02102 // pNode = pNode->FindNext(); 02103 // 02104 // return (pNode!=NULL); // If we found the test node then we are under it 02105 // // If we didn't, then we are above it 02106 02107 // This is a more optimised version 02108 // We can quickly detect whether testnode is 02109 // first in sibling list 02110 if (pChild==pTestParent->FindFirstChild()) // If the test node is the first child 02111 return (pChild==this); // Then we're under it if we're the test node 02112 // And above it if we're not the test node 02113 02114 // Work in both directions at the same time because, typically 02115 // the test node is very close to this node, so we're likely to hit 02116 // it quickly in one direction or the other... 02117 Node* pNodeF = (Node*)this; // Forwards 02118 Node* pNodeB = (Node*)this; // Backwards 02119 while ((pNodeF || pNodeB) && pNodeF != pChild && pNodeB!=pChild) 02120 { 02121 pNodeF ? pNodeF = pNodeF->FindNext() : NULL; 02122 pNodeB ? pNodeB = pNodeB->FindPrevious() : NULL; 02123 } 02124 02125 return (pNodeF==pChild); // If we found the test node in the forward direction 02126 // Then we are underneath it, otherwise we are on top 02127 } 02128 02129 pChild = pTestParent; 02130 pTestParent = pTestParent->FindParent(); 02131 } 02132 02133 // If the common ancestor wasn't our immediate parent 02134 // Then test higher ancestors recursively 02135 // (If our ancestor is under the test node then we are too!) 02136 return pMyParent->IsUnder(pTestNode, FALSE); 02137 } 02138 02139 /********************************************************************************************* 02140 02141 > virtual BOOL Node::IsAnObject(void) const 02142 02143 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 02144 Created: 19/4/93 02145 Inputs: - 02146 Outputs: - 02147 Returns: TRUE if the node is an object i.e. a NodeRenderableInk, the base class returns 02148 FALSE. 02149 Purpose: For determining quickly if the node is an object 02150 Errors: 02151 02152 **********************************************************************************************/ 02153 02154 /*BOOL Node::IsAnObject() const 02155 { 02156 return FALSE; // Cos it's not (overridden in NodeRenderableInk) 02157 }*/ 02158 02159 /********************************************************************************************* 02160 02161 > BOOL Node::IsCompound(void) const 02162 02163 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 02164 Created: 19/4/93 02165 Inputs: - 02166 Outputs: - 02167 Returns: TRUE if the node can contain non NodeAttribute children, eg. NodeGroup, 02168 the base class returns FALSE. 02169 Purpose: For finding the status of the node's Compound flag 02170 Errors: 02171 02172 **********************************************************************************************/ 02173 02174 /*BOOL Node::IsCompound() const 02175 { 02176 return FALSE; 02177 }*/ 02178 02179 /********************************************************************************************* 02180 02181 > BOOL Node::IsAnAttribute(void) const 02182 02183 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 02184 Created: 19/4/93 02185 Inputs: - 02186 Outputs: - 02187 Returns: TRUE if the node is a NodeAttribute, the base class returns FALSE. 02188 Purpose: For finding the status of the node's Compound flag 02189 Errors: 02190 02191 **********************************************************************************************/ 02192 02193 /*BOOL Node::IsAnAttribute() const 02194 { 02195 return FALSE; 02196 }*/ 02197 02198 02199 /******************************************************************************************** 02200 02201 > virtual BOOL Node::IsOrHidesAnAttribute() const 02202 02203 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 02204 Created: 12/6/95 02205 Returns: FALSE 02206 Purpose: Allows you to see if this node is a NodeAttribute or is Hiding a NodeAttribute 02207 without having to use the expensive runtime checking 02208 02209 ********************************************************************************************/ 02210 02211 /*BOOL Node::IsOrHidesAnAttribute() const 02212 { 02213 return FALSE; 02214 }*/ 02215 02216 02217 02218 /********************************************************************************************* 02219 02220 > BOOL Node::IsPaper(void) const 02221 02222 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02223 Created: 30/11/94 02224 Inputs: - 02225 Outputs: - 02226 Returns: TRUE if the node is a paper node, the base class returns FALSE. 02227 Purpose: For finding if a node is a paper node. 02228 Errors: 02229 02230 **********************************************************************************************/ 02231 02232 /*BOOL Node::IsPaper() const 02233 { 02234 return FALSE; 02235 }*/ 02236 02237 /********************************************************************************************* 02238 02239 > BOOL Node::IsLayer(void) const 02240 02241 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02242 Created: 30/11/94 02243 Inputs: - 02244 Outputs: - 02245 Returns: TRUE if the node is a layer node, the base class returns FALSE. 02246 Purpose: For finding if a node is a layer node. 02247 Errors: 02248 02249 **********************************************************************************************/ 02250 02251 /*BOOL Node::IsLayer() const 02252 { 02253 return FALSE; 02254 }*/ 02255 02256 /********************************************************************************************* 02257 02258 > BOOL Node::IsSpread(void) const 02259 02260 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02261 Created: 15/02/95 02262 Returns: TRUE if the node is a spread node, the base class returns FALSE. 02263 Purpose: For finding if a node is a spread node. 02264 02265 **********************************************************************************************/ 02266 02267 /*BOOL Node::IsSpread() const 02268 { 02269 return FALSE; 02270 }*/ 02271 02272 02273 /********************************************************************************************* 02274 02275 > BOOL Node::IsChapter(void) const 02276 02277 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 02278 Created: 28/04/95 02279 Returns: TRUE if the node is a chapter node, the base class returns FALSE. 02280 Purpose: For finding if a node is a chapter node. 02281 02282 **********************************************************************************************/ 02283 02284 /*BOOL Node::IsChapter() const 02285 { 02286 return FALSE; 02287 }*/ 02288 02289 02290 /******************************************************************************************** 02291 02292 > BOOL Node::IsNodeRenderableClass() 02293 02294 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02295 Created: 27/01/95 02296 Returns: TRUE => This node is an instance of NodeRenderable or a derived class. 02297 FALSE => otherwise. 02298 Purpose: Determine if a node is *derived* from the NodeRenderable class. 02299 NB. This has nothing to do with the node's renderable flag! 02300 SeeAlso: Node::IsRenderable 02301 02302 ********************************************************************************************/ 02303 02304 /*BOOL Node::IsNodeRenderableClass() const 02305 { 02306 return FALSE; 02307 }*/ 02308 02309 02310 02311 /******************************************************************************************** 02312 02313 > BOOL Node::ShouldBeRendered() 02314 02315 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02316 Created: 03/07/95 02317 Returns: TRUE => This node should be rendered 02318 FALSE => this node should not be rendered. 02319 Purpose: Work out if the node should be rendered - basically all nodes except 02320 NodeRenderable nodes should be rendered. However, some NodeRenderable 02321 derived classes should not actually be rendered - for example NodeMouldGroup 02322 hides the original un-moulded objects, which should definitely *not* be 02323 rendered. 02324 This is mainly used during printing where due to complications to do with 02325 banding and transparency, we cannot use NeedsToRender() to filter out 02326 such nodes, so we use this function instead. 02327 NB. This has nothing to do with the node's renderable flag! 02328 SeeAlso: Node::IsNodeRenderable 02329 02330 ********************************************************************************************/ 02331 02332 BOOL Node::ShouldBeRendered() const 02333 { 02334 return FALSE; 02335 } 02336 02337 /******************************************************************************************** 02338 02339 > BOOL Node::IsNodeHidden() 02340 02341 Author: Will_Cowling (Xara Group Ltd) <camelotdev@xara.com> 02342 Created: 13/02/95 02343 Returns: TRUE => This node is an instance of NodeHidden or a derived class. 02344 FALSE => otherwise. 02345 Purpose: Determine if a node is *derived* from the NodeHidden class. 02346 02347 ********************************************************************************************/ 02348 02349 /*BOOL Node::IsNodeHidden() const 02350 { 02351 return FALSE; 02352 }*/ 02353 02354 /******************************************************************************************** 02355 02356 > BOOL Node::IsNodeDocument() 02357 02358 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02359 Created: 15/02/95 02360 Returns: TRUE => This node is an instance of NodeDocument. 02361 FALSE => otherwise. 02362 Purpose: Determine if a node is a NodeDocument object. 02363 02364 ********************************************************************************************/ 02365 02366 /*BOOL Node::IsNodeDocument() const 02367 { 02368 return FALSE; 02369 }*/ 02370 02371 02372 02373 /******************************************************************************************** 02374 02375 > BOOL Node::IsNodePath() 02376 02377 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 02378 Created: 20/03/95 02379 Returns: TRUE => This node is an instance of NodePath. 02380 FALSE => otherwise. 02381 Purpose: Determine if a node is a NodePath object. 02382 02383 ********************************************************************************************/ 02384 02385 /*BOOL Node::IsNodePath() const 02386 { 02387 return FALSE; 02388 }*/ 02389 02390 02391 02392 /******************************************************************************************** 02393 02394 > BOOL Node::IsARegularShape() 02395 02396 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 02397 Created: 24/04/95 02398 Returns: TRUE => This node is an instance of NodeRegularShape 02399 FALSE => otherwise. 02400 Purpose: Determine if a node is a QuickShape object. 02401 02402 ********************************************************************************************/ 02403 02404 /*BOOL Node::IsARegularShape() const 02405 { 02406 return FALSE; 02407 }*/ 02408 02409 02410 02411 /******************************************************************************************** 02412 02413 > BOOL Node::IsAVisibleTextNode() 02414 02415 Author: Will_Cowling (Xara Group Ltd) <camelotdev@xara.com> 02416 Created: 13/02/95 02417 Returns: TRUE => This node is a VisibleTextNode. 02418 FALSE => otherwise. 02419 Purpose: Determine if a node is a visible text node. 02420 02421 ********************************************************************************************/ 02422 02423 /*BOOL Node::IsAVisibleTextNode() const 02424 { 02425 return FALSE; 02426 }*/ 02427 02428 /******************************************************************************************** 02429 > BOOL Node::IsAnAbstractTextChar() 02430 02431 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 02432 Created: 14/02/95 02433 Returns: TRUE => This node is a AbstractTextChar node. 02434 FALSE => otherwise. 02435 Purpose: Determine if a node is an AbstractTextChar node. 02436 ********************************************************************************************/ 02437 02438 /*BOOL Node::IsAnAbstractTextChar() const 02439 { 02440 return FALSE; 02441 }*/ 02442 02443 /******************************************************************************************** 02444 > BOOL Node::IsATextChar() 02445 02446 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02447 Created: 14/8/96 02448 Returns: TRUE => This node is a kind of TextChar node. 02449 FALSE => otherwise. 02450 Purpose: Determine if a node is a (or is derived from) TextChar. 02451 ********************************************************************************************/ 02452 /*BOOL Node::IsATextChar() const 02453 { 02454 return FALSE; 02455 }*/ 02456 02457 /******************************************************************************************** 02458 > BOOL Node::IsABaseTextClass() 02459 02460 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 02461 Created: 04/04/95 02462 Returns: TRUE => This node is a kind of BaseTextClass node. 02463 FALSE => otherwise. 02464 Purpose: Determine if a node is a (or is derived from) BaseTextClass. 02465 ********************************************************************************************/ 02466 /*BOOL Node::IsABaseTextClass() const 02467 { 02468 return FALSE; 02469 }*/ 02470 02471 /******************************************************************************************** 02472 > BOOL Node::IsATypeface() 02473 02474 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 02475 Created: 04/04/95 02476 Returns: TRUE => This node is a kind of AttrTxtFontTypeface. 02477 FALSE => otherwise. 02478 Purpose: Determine if a node is a (or is derived from) AttrTxtFontTypeface. 02479 ********************************************************************************************/ 02480 /*BOOL Node::IsATypeface() const 02481 { 02482 return FALSE; 02483 }*/ 02484 02485 /******************************************************************************************** 02486 02487 > NodePath* Node::IsAnEditablePath() 02488 02489 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 02490 Created: 19/3/95 02491 Inputs: pSelected = A pointer to the selected node to check 02492 Outputs: - 02493 Returns: A pointer to an editable node path (or derived) object 02494 NULL if there isn't one. 02495 Purpose: Finds the node to edit (if it exists). This node could actually be 'this' 02496 node one of its children which the node wants to be editable. 02497 02498 ********************************************************************************************/ 02499 02500 NodePath* Node::IsAnEditablePath() 02501 { 02502 Node* pNode = this; 02503 if (pNode->IsNodePath()) 02504 return ((NodePath*)pNode); 02505 02506 return ((NodePath*) pNode->HasEditableChild(CC_RUNTIME_CLASS(NodePath), NULL)); 02507 } 02508 02509 02510 02511 /******************************************************************************************** 02512 > virtual BOOL Node::IsABitmap() const 02513 02514 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 02515 Created: 19/3/95 02516 Returns: TRUE if this node is a bitmap, FALSE if not (the default) 02517 Purpose: Quicker way to test if this node is a bitmap. 02518 ********************************************************************************************/ 02519 02520 /*BOOL Node::IsABitmap() const 02521 { 02522 return FALSE; 02523 }*/ 02524 02525 02526 02527 /********************************************************************************************* 02528 > BOOL Node::IsAFillAttr(void) const 02529 02530 Author: Will_Cowling (Xara Group Ltd) <camelotdev@xara.com> 02531 Created: 13/2/95 02532 Returns: TRUE if the node is an AttrFillGeometry, will return TRUE 02533 Purpose: Virtual function for determining if the node is a Fill attribute 02534 **********************************************************************************************/ 02535 02536 /*BOOL Node::IsAFillAttr() const 02537 { 02538 return FALSE; 02539 } */ 02540 02541 02542 02543 /********************************************************************************************* 02544 > BOOL Node::IsABitmapFill(void) const 02545 02546 Author: Will_Cowling (Xara Group Ltd) <camelotdev@xara.com> 02547 Created: 13/2/95 02548 Returns: TRUE if the node is an AttrBitmapFill, will return TRUE 02549 Purpose: Virtual function for determining if the node is a Fill attribute 02550 **********************************************************************************************/ 02551 02552 /*BOOL Node::IsABitmapFill() const 02553 { 02554 return FALSE; 02555 } */ 02556 02557 02558 /********************************************************************************************* 02559 > BOOL Node::IsABitmapColourFill(void) const 02560 02561 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 02562 Created: 01/06/2004 02563 Returns: TRUE if the node is an AttrBitmapFill, will return TRUE 02564 Purpose: Virtual function for determining if the node is a Fill attribute 02565 **********************************************************************************************/ 02566 02567 /*BOOL Node::IsABitmapColourFill() const 02568 { 02569 return FALSE; 02570 } */ 02571 02572 02573 02574 /********************************************************************************************* 02575 > BOOL Node::IsABitmapTranspFill(void) const 02576 02577 Author: Will_Cowling (Xara Group Ltd) <camelotdev@xara.com> 02578 Created: 13/2/95 02579 Returns: TRUE if the node is an AttrBitmapTranspFill, will return TRUE 02580 Purpose: Virtual function for determining if the node is a Fill attribute 02581 **********************************************************************************************/ 02582 02583 /*BOOL Node::IsABitmapTranspFill() const 02584 { 02585 return FALSE; 02586 } */ 02587 02588 02589 02590 /******************************************************************************************** 02591 > virtual BOOL Node::IsAnObjectName() const 02592 02593 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 02594 Created: 19/3/95 02595 Returns: TRUE if this node is an object-name attribute (ie. a Wix TemaplateAttribute 02596 with an 'ObjectName' key), FALSE if not (the default). 02597 Purpose: Quicker way to test if this node is an object-name attribute. 02598 SeeAlso: TemplateAttribute::IsAnObjectName 02599 ********************************************************************************************/ 02600 02601 /*BOOL Node::IsAnObjectName() const 02602 { 02603 return FALSE; 02604 }*/ 02605 02606 02607 02608 /******************************************************************************************** 02609 > virtual BOOL Node::IsUserAttribute() const 02610 02611 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 02612 Created: 19/3/95 02613 Returns: TRUE if this node is an AttrUser, FALSE if not (the default). 02614 Purpose: Quicker way to test if this node is an AttrUser. 02615 SeeAlso: AttrUser::IsUserAttribute 02616 ********************************************************************************************/ 02617 02618 /*BOOL Node::IsUserAttribute() const 02619 { 02620 return FALSE; 02621 }*/ 02622 02623 02624 02625 /******************************************************************************************** 02626 > virtual BOOL Node::IsSetCandidate() const 02627 02628 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 02629 Created: 19/3/95 02630 Returns: TRUE if this node is can be a member of a set in the Attribute gallery 02631 (by default FALSE). 02632 Purpose: Quicker way to test if this node is worth considering during Name gallery 02633 scans. 02634 SeeAlso: NodeSetSentinel::IsSetCandidate; NodeRenderableInk::IsSetCandidate 02635 ********************************************************************************************/ 02636 02637 /*BOOL Node::IsSetCandidate() const 02638 { 02639 return FALSE; 02640 }*/ 02641 02642 02643 02644 /******************************************************************************************** 02645 02646 > BOOL Node::IsANodeMould() const 02647 02648 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 02649 Created: 15/12/2000 02650 Purpose: Virtual function to determine whether this node is a NodeMould. 02651 02652 ********************************************************************************************/ 02653 /*BOOL Node::IsANodeMould() const 02654 { 02655 return FALSE; 02656 }*/ 02657 02658 02659 02660 /********************************************************************************************* 02661 02662 > virtual BOOL Node::IsABrush() 02663 02664 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 02665 Created: 29/11/99 02666 Inputs: - 02667 Outputs: - 02668 Returns: FALSE 02669 Purpose: Virtual function for determing whether this node is a brush attribute 02670 Errors: 02671 See Also; brshattr.cpp 02672 02673 **********************************************************************************************/ 02674 02675 /*BOOL Node::IsABrush() const 02676 { 02677 return FALSE; 02678 }*/ 02679 02680 02681 /********************************************************************************************* 02682 02683 > BOOL NodeAttribute::IsBrushed() 02684 02685 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 02686 Created: 29/11/99 02687 Inputs: - 02688 Outputs: - 02689 Returns: TRUE if this node has a brush attribute node as one of its children 02690 Purpose: as above 02691 Errors: 02692 See Also; brshattr.cpp 02693 02694 **********************************************************************************************/ 02695 02696 BOOL Node::IsBrushed() const 02697 { 02698 NodeAttribute* pAttr = FindFirstAttr( &Node::IsABrush ); 02699 return (pAttr != NULL); 02700 } 02701 02702 /******************************************************************************************** 02703 02704 > virtual BOOL Node::SupportsClipboardFormat(InternalClipboardFormat *Format) const 02705 02706 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02707 Created: 26/4/95 02708 02709 Returns: TRUE = This node supports the given format 02710 FALSE = This node does not support the format (or the format is unknown) 02711 02712 Purpose: Determine if a node supports a given internal data type. This is used 02713 by the clipboard when exporting to other applications in order to 02714 determine if certain data types can be supplied. 02715 02716 e.g. The basic formats include: 02717 Vector - this is ALWAYS assumed to be available (Vector format 02718 includes every Node, e.g. export in Camelot .art format) 02719 02720 Text - As well as paths, some objects can provide text chars 02721 02722 Bitmap - Bitmap fills can render a filled object or supply the 02723 bitmap used for filling with. 02724 02725 See InternalClipboardFormat (kernel\cliptype.h) for more details 02726 02727 Notes: The base class does not bother checking the format and just returns 02728 FALSE, as the only format supported by default is "Vector", which is 02729 02730 SeeAlso: InternalClipboardFormat 02731 02732 ********************************************************************************************/ 02733 02734 BOOL Node::SupportsClipboardFormat(InternalClipboardFormat *Format) const 02735 { 02736 // By default, nodes can supply Vector format export only 02737 return(FALSE); 02738 } 02739 02740 /******************************************************************************************** 02741 02742 > BOOL Node::DiscardsAttributeChildren() const 02743 02744 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 02745 Created: 27/4/95 02746 Returns: TRUE if the node discards its attribute children 02747 FALSE if it does not (default) 02748 02749 Purpose: This virtual was added because we need to know about nodes which can 02750 discard their child attributes, an example is the CaretNode. If an 02751 attribute gets applied to such a node then no undo info can be generated 02752 02753 scenario 02754 ~~~~~~~~ 02755 02756 Apply attribute to caret generating undo 02757 Move caret, so deleting all initial attrs 02758 undo 02759 02760 The undo tries to find the applied attribute so that it can hide it, but 02761 it does not exist anymore (BANG!) 02762 02763 This base class function returns FALSE 02764 02765 Notes: Phil, 24/09/2005 02766 The usage of this function has changed subtly today. It used to prevent 02767 both attribute optimisation and undo recording on Caret nodes. 02768 As of today it just prevents undo recording - attribute optimisation 02769 goes ahead like normal on Caret nodes so that they behave more consistently. 02770 02771 02772 ********************************************************************************************/ 02773 02774 BOOL Node::DiscardsAttributeChildren() const 02775 { 02776 return (FALSE); 02777 } 02778 02779 /******************************************************************************************** 02780 02781 > KernelBitmap *Node::EnumerateBitmaps(UINT32 Count) 02782 02783 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02784 Created: 02/17/95 02785 Inputs: Count - the bitmap to get (see Purpose). 02786 Returns: The KernelBitmap in use by the node, or NULL if no more are used. 02787 Purpose: Find out what bitmaps, if any, are used by this node. 02788 02789 The base class returns NULL always, so you over-ride this in any node classes 02790 that use bitmaps. 02791 02792 This function supports nodes that use more than one bitmap - you call this 02793 function repeatedly and keep incrementing the Count parameter that you pass 02794 in each time by 1. You should stop calling it when it returns NULL, as this 02795 indicates that no more bitmaps are used by this node. 02796 Count should start off as 0 for the first call. Note that this function 02797 can (and often will) return NULL for the first call, as many nodes don't 02798 use bitmaps, obviously. 02799 02800 SeeAlso: KernelBitmap 02801 02802 ********************************************************************************************/ 02803 02804 KernelBitmap *Node::EnumerateBitmaps(UINT32 Count) 02805 { 02806 return NULL; 02807 } 02808 02809 02810 02811 /********************************************************************************************* 02812 02813 > Node* Node::HasEditableChild(CCRuntimeClass* ChildClass, Node* pPreviousChild) 02814 02815 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 02816 Created: 20/3/95 02817 Inputs: ChildClass = the runtime class of the editable object 02818 pPreviousChild = a pointer to the previous editable child 02819 returned by 'this' node, NULL if this is the first 02820 call to this node. 02821 Outputs: - 02822 Returns: A node pointer, to an object which forms part of the editable surface of 02823 its parent (this node). 02824 Purpose: This function allows compound objects to provide editable children. 02825 It also allows tools to ask an object what other nodes form part of 02826 its editable surface if the node itself cannot be editable. This allows 02827 complex objects such as moulds and text objects, who have a single parent 02828 above many objects (some of which are editable), to provide a way for tools 02829 to get at them. 02830 A tool scanning the selection may be looking to edit certain objects. 02831 If a selected object it comes accross is not of the correct type, the tool 02832 can also ask it whether it contains any editable objects of type(ChildClass). 02833 If the node overrides this virtual function it can provide a strangly shapes 02834 editable surface. 02835 Note, do not confuse this with select inside, where objects have been 02836 explicitly selected by the user. In that case the parent would never be 02837 asked for editable children as it does not form part of the selection under 02838 a select inside action. 02839 Errors: - 02840 02841 **********************************************************************************************/ 02842 02843 Node* Node::HasEditableChild(CCRuntimeClass* ChildClass, Node* pPreviousChild) 02844 { 02845 return NULL; 02846 } 02847 02848 02849 02850 /********************************************************************************************* 02851 02852 > virtual void Node::SetSelected(BOOL Status) const 02853 02854 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 02855 Created: 19/4/93 02856 Inputs: Status: Status of node's selected flag 02857 Outputs: - 02858 Returns: - 02859 Purpose: To set Nodes selected status (TRUE/FALSE) 02860 This routine also deals with "select-inside" by making sure all the 02861 SelectedChildren flags are set appropriately. 02862 Note: Selecting a node prevents it from being a parent of selected nodes 02863 This routine therefore clears the selection of any children! 02864 Note2: Calling this routine clears any selection from children of this 02865 node and marks it to no longer be the parent of selected children. 02866 This is done because selected nodes can't have sel children and because 02867 unselecting a node implies that you thought it was selected in which case 02868 it shouldn't have selected children. 02869 Errors: - 02870 02871 **********************************************************************************************/ 02872 02873 void Node::SetSelected(BOOL fStatus) 02874 { 02875 // If selecting or deselecting a node which is currently the parent of selected nodes 02876 // then it can no longer have any selected children. The rules of select inside say 02877 // that selected nodes cannot have selected children. 02878 if (Flags.SelectedChildren) // If node was previously a parent of selected nodes 02879 DeSelectSubtree(); // Then clear any selected children 02880 02881 Flags.SelectedChildren = FALSE; // Flag that this node doesn't have selected children 02882 02883 if (Flags.Selected != fStatus) 02884 { 02885 Flags.Selected = fStatus; // Flag that this node is now selected 02886 02887 // Inform the Selection SelRange that the selection has changed 02888 // If selected, pass in 'this' to let it know that I am the most recently selected node, 02889 // else pass in NULL to leave things as they were 02890 SelRange* Selection = GetApplication()->FindSelection(); 02891 if (Selection != 0) Selection->Update(FALSE, fStatus ? this : 0); 02892 02893 /* 02894 Removed by Simon.M for Mark.N - the assumption made is invalid 02895 02896 #ifdef _DEBUG 02897 // This piece of code checks that if you are selecting a node, none of its ascendents are selected. 02898 // Debug builds will inform you of this, retail builds will ignore it as it is viewed as such 02899 // a highly illegal state that all bugs causing this to happen should have be ironed out (shyeh,right!) 02900 // (MarkN 27/10/94) 02901 if (Status) 02902 { 02903 Node* pNode = Parent; 02904 while (pNode) 02905 { 02906 ERROR3IF(pNode->Flags.Selected,"Selecting a node when an ascendent is selected"); 02907 pNode = pNode->Parent; 02908 } 02909 } 02910 #endif 02911 */ 02912 // Now that we've altered the Selected and SelectedChildren flags: 02913 // If this node is not in the normal selection surface (direct children of a layer) 02914 // then we must go and set the SelectedChildren flags properly... 02915 if (FindParent() == 0 || FindParent()->IsLayer()) 02916 return; // Is in the normal selection surface so exit quickly! 02917 02918 // Is NOT in the normal selection surface so go fix up the SelectedChildren flags... 02919 if (fStatus) 02920 { 02921 // This node has been selected while "inside" another one. 02922 // If this node is not in the top layer of normal selection then it must be inside 02923 // a compound node. So, we must go up the parent links setting their SelectedChildren 02924 // flags until we reach the normal selection layer (the child list of a Layer node). 02925 for (Node* pParent = FindParent(); 02926 pParent != 0 && !pParent->IsLayer(); 02927 pParent = pParent->FindParent()) 02928 { 02929 pParent->Flags.SelectedChildren = TRUE; // Flag that parent has selected children 02930 } 02931 02932 // This error check may be a bit over-zealous. I suspect that nodes can be deselected 02933 // while they are in subtrees which are temporarilly unlinked from the tree (hidden nodes???) 02934 // ERROR3IF(pParent==NULL,"Node doesn't seem to be in a layer!"); 02935 } 02936 else 02937 { 02938 // This node has been deselected while "inside" another one. 02939 // If there are any other selected of parentsofselected nodes in the sibling list 02940 // with this one then leave the parent marked as ParentOfSelected 02941 // Otherwise clear it. 02942 // And do the same test for it's parent, etc., etc... 02943 for (Node* pParent = FindParent(); 02944 pParent != 0 && !pParent->IsLayer(); 02945 pParent = pParent->FindParent()) 02946 { 02947 Node *p; 02948 for ( p = pParent->FindFirstChild(); p != 0; p = p->FindNext()) 02949 if (p->IsSelected() || p->HasSelectedChildren()) 02950 break; 02951 02952 pParent->Flags.SelectedChildren = (p != 0); 02953 02954 // if ( pParent->HasSelectedChildren() ) // If our parent still has selected children 02955 // break; // Then stop the loop NOW because we don't need 02956 // to alter this parent's flag, or any of it's parents. 02957 // Else 02958 // pParent->Flags.SelectedChildren = FALSE; // Flag that parent no longer has selected children. 02959 02960 } 02961 02962 // This error check may be a bit over-zealous. I suspect that nodes can be deselected 02963 // while they are in subtrees which are temporarilly unlinked from the tree (hidden nodes???) 02964 // ERROR3IF(pParent==NULL,"Node doesn't seem to be in a layer!"); 02965 } 02966 } 02967 } 02968 02969 02970 02971 02972 /********************************************************************************************* 02973 02974 > BOOL Node::DeSelectSubtree() 02975 02976 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02977 Created: 07/10/94 02978 Inputs: - 02979 Outputs: - 02980 Returns: TRUE if it succeeded 02981 FALSE otherwise 02982 Purpose: To deselect all selected nodes below this node. 02983 This function also ensures that the SelectedChildren flags are cleared properly. 02984 It is self-recursive! 02985 Helper function for SetSelected 02986 Scope: Private 02987 Errors: - 02988 SeeAlso: Node::SetSelected 02989 02990 **********************************************************************************************/ 02991 02992 BOOL Node::DeSelectSubtree() 02993 { 02994 ERROR2IF(this==NULL,FALSE,"DeSelectSubtree called on NULL node."); // Precondition 02995 02996 Node* pNode = Child; 02997 while (pNode) 02998 { 02999 pNode->Flags.Selected = FALSE; // Deselect this node directly 03000 03001 if (pNode->Flags.SelectedChildren) // If this node has selected children 03002 { 03003 pNode->DeSelectSubtree(); // Then deselect anything in its subtree 03004 } 03005 03006 pNode->Flags.SelectedChildren = FALSE; // Flag that this node no longer has sel children 03007 pNode = pNode->Next; 03008 } 03009 03010 return TRUE; 03011 } 03012 03013 03014 /********************************************************************************************* 03015 03016 > BOOL Node::HasSelectedChildren() const 03017 03018 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 03019 Created: 07/10/94 03020 Inputs: - 03021 Outputs: - 03022 Returns: TRUE if this node has selected or ParentOfSelected nodes in it's child list 03023 FALSE otherwise 03024 Purpose: To find out whether a node has got selected children or children that themselves 03025 have selected children... 03026 Helper function for SetSelected 03027 Scope: Private 03028 Errors: - 03029 SeeAlso: Node::SetSelected 03030 03031 **********************************************************************************************/ 03032 03033 BOOL Node::HasSelectedChildren() const 03034 { 03035 ERROR2IF(this==NULL,FALSE,"HasSelectedChildren called on NULL node."); // Precondition 03036 03037 // BOOL has = FALSE; 03038 Node* pNode = Child; 03039 while (pNode!=NULL) // While there are children to process 03040 { 03041 if (pNode->Flags.Selected || 03042 pNode->Flags.SelectedChildren) // See if this child is Sel or SelChildren 03043 return TRUE; // If so, then return TRUE immediately! 03044 pNode = pNode->Next; // Else go look for next child 03045 } 03046 03047 return FALSE; // If no children Sel or SelChildren then 03048 // Return FALSE. 03049 } 03050 03051 03052 /******************************************************************************************** 03053 03054 > virtual BOOL Node::IsBounded() const 03055 03056 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 03057 Created: 30/6/94 03058 Returns: FALSE 03059 Purpose: This function will return TRUE when called on NodeRenderableBounded nodes 03060 and those derived from it. This is the base class version that returns FALSE 03061 SeeAlso: NodeRenderableBounded::IsBounded 03062 03063 ********************************************************************************************/ 03064 03065 /*BOOL Node::IsBounded() 03066 { 03067 return FALSE; 03068 }*/ 03069 03070 03071 /********************************************************************************************* 03072 03073 > Node* Node::FindLastChild(BOOL ExcludeInsertionNode = FALSE) const 03074 03075 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03076 Created: 19/4/93 03077 Inputs: ExcludeInsertionNode: When TRUE we find the last child excluding the 03078 InsertionNode 03079 Outputs: - 03080 Returns: Pointer to the node's last child 03081 NULL if the node has no children 03082 Purpose: For finding a node's last child 03083 SeeAlso: InsertionNode 03084 Errors: 03085 03086 **********************************************************************************************/ 03087 03088 Node* Node::FindLastChild(BOOL ExcludeInsertionNode) const 03089 { 03090 Node* n = Child; // First child 03091 if (n != NULL) 03092 { 03093 while ((n->Next) != NULL) 03094 n = n->Next; 03095 03096 if ((ExcludeInsertionNode) && (IS_A(n, InsertionNode))) 03097 { 03098 n = n->Previous; 03099 } 03100 } 03101 return(n); 03102 } 03103 03104 /******************************************************************************************** 03105 03106 > Node* Node::FindParent(CCRuntimeClass* ParentClass) 03107 03108 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03109 Created: 1/3/94 03110 Inputs: ParentClass: The type of parent that you want to find 03111 Outputs: - 03112 Returns: The parent of the node with class ParentClass 03113 In the retail build NULL is returned if the parent could not be found 03114 03115 Purpose: This function follows the node's parent links until it finds a node 03116 of class ParentClass. If no such node is found then an ENSURE will 03117 occur. 03118 03119 Errors: If the parent node could not be found then ENSURE is called. 03120 SeeAlso: - 03121 03122 ********************************************************************************************/ 03123 Node* Node::FindParent(CCRuntimeClass* ParentClass) const 03124 { 03125 Node* Current = this->FindParent(); 03126 while (Current != NULL) 03127 { 03128 if (Current->GetRuntimeClass() == ParentClass) 03129 { 03130 return Current; 03131 } 03132 Current = Current->FindParent(); // Get the next parent 03133 } 03134 //ENSURE(FALSE, "Could not find parent of correct type"); 03135 return NULL; 03136 } 03137 03138 03139 /******************************************************************************************** 03140 03141 > Node* Node::FindNext(CCRuntimeClass* Class) 03142 03143 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03144 Created: 1/3/94 03145 Inputs: Class: The node class to look for 03146 Outputs: - 03147 Returns: The next of the node with class Class 03148 03149 Purpose: This function follows the node's next links until it finds a node 03150 derived from Class. NULL is returned if no node is found 03151 03152 SeeAlso: - 03153 03154 ********************************************************************************************/ 03155 Node* Node::FindNext(CCRuntimeClass* Class) const 03156 { 03157 Node* Current = this->FindNext(); 03158 while (Current != NULL) 03159 { 03160 if (Current->IsKindOf(Class)) 03161 { 03162 return Current; 03163 } 03164 Current = Current->FindNext(); 03165 } 03166 return NULL; 03167 } 03168 03169 /******************************************************************************************** 03170 03171 > Node* Node::FindPrevious(CCRuntimeClass* Class) 03172 03173 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03174 Created: 1/3/94 03175 Inputs: Class: The node class to look for 03176 Outputs: - 03177 Returns: The Previous of the node with class Class 03178 03179 Purpose: This function follows the node's Previous links until it finds a node 03180 derived from Class. NULL is returned if no node is found 03181 03182 SeeAlso: - 03183 03184 ********************************************************************************************/ 03185 Node* Node::FindPrevious(CCRuntimeClass* Class) const 03186 { 03187 Node* Current = this->FindPrevious(); 03188 while (Current != NULL) 03189 { 03190 if (Current->IsKindOf(Class)) 03191 { 03192 return Current; 03193 } 03194 Current = Current->FindPrevious(); 03195 } 03196 return NULL; 03197 } 03198 03199 03200 /******************************************************************************************** 03201 > Node* Node::FindFirstChild(CCRuntimeClass* Class) 03202 03203 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 03204 Created: 9/4/95 03205 Inputs: Class - class of first child to find 03206 Returns: pointer to first child of specified type else NULL 03207 Purpose: Find first child of specified type 03208 ********************************************************************************************/ 03209 Node* Node::FindFirstChild(CCRuntimeClass* Class) const 03210 { 03211 Node* pNode = FindFirstChild(); 03212 while (pNode) 03213 { 03214 if (pNode->IsKindOf(Class)) 03215 return pNode; 03216 pNode = pNode->FindNext(); 03217 } 03218 return NULL; 03219 } 03220 03221 03222 03223 /******************************************************************************************** 03224 > Node* Node::FindLastChild(CCRuntimeClass* Class) 03225 03226 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 03227 Created: 9/4/95 03228 Inputs: Class - class of first child to find 03229 Returns: pointer to last child of specified type else NULL 03230 Purpose: Find last child of specified type 03231 ********************************************************************************************/ 03232 Node* Node::FindLastChild(CCRuntimeClass* Class) const 03233 { 03234 Node* pNode = FindFirstChild(); 03235 Node* pNodeOfGivenClass = NULL; 03236 while (pNode) 03237 { 03238 if (pNode->IsKindOf(Class)) 03239 pNodeOfGivenClass = pNode; 03240 pNode = pNode->FindNext(); 03241 } 03242 return pNodeOfGivenClass; 03243 } 03244 03245 03246 /******************************************************************************************** 03247 > NodeRenderableInk* Node::FindNextInk() const 03248 03249 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 03250 Created: 04/08/2000 03251 Purpose: Find the next ink node. 03252 Notes: Analogous to FindNext(CC_RUNTIME_CLASS(NodeRenderableInk)), 03253 just faster and neater. 03254 03255 See also: FindNext(), IsAnObject(). 03256 ********************************************************************************************/ 03257 NodeRenderableInk* Node::FindNextInk() const 03258 { 03259 Node* pInk = FindNext(); 03260 while (pInk != NULL && !pInk->IsAnObject()) 03261 pInk = pInk->FindNext(); 03262 03263 return (NodeRenderableInk*)pInk; 03264 } 03265 03266 03267 /******************************************************************************************** 03268 > NodeRenderableInk* Node::FindPreviousInk() const 03269 03270 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 03271 Created: 04/08/2000 03272 Purpose: Find the previous ink node. 03273 Notes: Analogous to FindPrevious(CC_RUNTIME_CLASS(NodeRenderableInk)), 03274 just faster and neater. 03275 03276 See also: FindPrevious(), IsAnObject(). 03277 ********************************************************************************************/ 03278 NodeRenderableInk* Node::FindPreviousInk() const 03279 { 03280 Node* pInk = FindPrevious(); 03281 while (pInk != NULL && !pInk->IsAnObject()) 03282 pInk = pInk->FindPrevious(); 03283 03284 return (NodeRenderableInk*)pInk; 03285 } 03286 03287 03288 /******************************************************************************************** 03289 > NodeRenderableInk* Node::FindFirstChildInk() const 03290 03291 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 03292 Created: 04/08/2000 03293 Purpose: Find the first child ink-node. 03294 Notes: Analogous to FindFirstChild(CC_RUNTIME_CLASS(NodeRenderableInk)), 03295 just faster and neater. 03296 03297 See also: FindFirstChild(), IsAnObject(). 03298 ********************************************************************************************/ 03299 NodeRenderableInk* Node::FindFirstChildInk() const 03300 { 03301 Node* pInk = FindFirstChild(); 03302 while (pInk != NULL && !pInk->IsAnObject()) 03303 pInk = pInk->FindNext(); 03304 03305 return (NodeRenderableInk*)pInk; 03306 } 03307 03308 03309 /******************************************************************************************** 03310 > NodeRenderableInk* Node::FindLastChildInk() const 03311 03312 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 03313 Created: 04/08/2000 03314 Purpose: Find the last child ink-node. 03315 Notes: Analogous to FindLastChild(CC_RUNTIME_CLASS(NodeRenderableInk)), 03316 just faster and neater. 03317 03318 See also: FindLastChild(), IsAnObject(). 03319 ********************************************************************************************/ 03320 NodeRenderableInk* Node::FindLastChildInk() const 03321 { 03322 Node* pInk = FindLastChild(); 03323 while (pInk != NULL && !pInk->IsAnObject()) 03324 pInk = pInk->FindPrevious(); 03325 03326 return (NodeRenderableInk*)pInk; 03327 } 03328 03329 03330 /******************************************************************************************** 03331 03332 > BaseDocument *Node::FindOwnerDoc() 03333 03334 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 03335 Created: 02/15/95 03336 Returns: Pointer to the Document that owns this node, or 03337 NULL if the node is not in a document. 03338 Purpose: Find out which document this node is in. This is used to maintain an 03339 accurate node count for each document. 03340 03341 ********************************************************************************************/ 03342 03343 BaseDocument *Node::FindOwnerDoc() const 03344 { 03345 // Find the document this node is attached to - go up the tree until we reach the 03346 // NodeDocument object or we run out of parents (i.e. it's an orphan sub-tree waiting to 03347 // go into a document. 03348 const Node *pNode = this; 03349 while ((pNode != NULL) && (!pNode->IsNodeDocument())) 03350 pNode = pNode->FindParent(); 03351 03352 if (pNode != NULL) 03353 return ((NodeDocument *) pNode)->GetParentDoc(); 03354 else 03355 return NULL; 03356 } 03357 03358 03359 03360 /******************************************************************************************** 03361 03362 > BOOL Node::IsFamily(CCRuntimeClass* ccrcType, Node* pAncestor) const 03363 03364 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 03365 Created: 19 April 2000 03366 Inputs: ccrcType the type to test for. 03367 pAncestor the grandparent node we're looking for. 03368 Outputs: 03369 Returns: TRUE if one of our parent nodes is of the given type, and either _it_, or 03370 one of its parents, is the given ancestor node. 03371 FALSE otherwise. 03372 03373 Purpose: Basically, we're looking for a child-parent-grandparent relationship. 03374 We're the child and our parent can also be the grandparent. 03375 03376 Notes: If pAncestor points at us, then this fails the test, so you get FALSE. 03377 03378 Errors: In debug, we complain if any input parameter is NULL, 03379 in release we just return FALSE. 03380 03381 ********************************************************************************************/ 03382 BOOL Node::IsFamily(CCRuntimeClass* ccrcType, Node* pAncestor) const 03383 { 03384 // fairly naive algorithm - just get the next ccrcType node and check its parents against 03385 // pAncestor. could probably improve slightly by checking for ccrcType while we do the 03386 // grandparent check. 03387 03388 // input validation. 03389 if (ccrcType == NULL || pAncestor == NULL) 03390 { 03391 ERROR3("Node::IsFamily; NULL input parameters!"); 03392 return FALSE; 03393 } 03394 03395 // local variables. 03396 Node* pParent = NULL; 03397 Node* pGrandParent = NULL; 03398 03399 // loop on all our parents of type ccrcType. 03400 pParent = FindParent(ccrcType); 03401 while (pParent != NULL && pGrandParent != pAncestor) 03402 { 03403 // loop up the tree from pParent, looking for pAncestor. 03404 pGrandParent = pParent; 03405 while (pGrandParent != NULL && pGrandParent != pAncestor) 03406 pGrandParent = pGrandParent->FindParent(); 03407 03408 // if we haven't found a grandparent, then find the next parent of type ccrcTest. 03409 if (pGrandParent == NULL) 03410 pParent = pParent->FindParent(ccrcType); 03411 } 03412 03413 // we were successful if we found a grandparent. 03414 return (pGrandParent != NULL); 03415 } 03416 03417 03418 03419 // ------------------------------------------------------------------------------------------- 03420 // Find NonHidden methods 03421 03422 /********************************************************************************************* 03423 03424 > Node* Node::FindNextNonHidden(void) const 03425 03426 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03427 Created: 19/4/93 03428 Inputs: - 03429 Outputs: - 03430 Returns: Pointer to the first next sibling node which is not a NodeHidden 03431 Purpose: For finding the next sibling of a node (ignoring all NodeHidden nodes). 03432 03433 This routine should only be used if it is vital that a NodeHidden is 03434 not returned. It is much slower than Node::FindNext. 03435 03436 SeeAlso: Node::FindNext 03437 Errors: 03438 03439 **********************************************************************************************/ 03440 03441 Node* Node::FindNextNonHidden(void) const 03442 { 03443 Node* Current = Next; 03444 if (Current != NULL) 03445 { 03446 while (Current->IsNodeHidden()) 03447 { 03448 Current = Current->Next; 03449 if (Current == NULL) break; 03450 } 03451 } 03452 return (Current); 03453 } 03454 03455 /********************************************************************************************* 03456 03457 > Node* Node::FindPrevNonHidden(void) const 03458 03459 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03460 Created: 19/4/93 03461 Inputs: - 03462 Outputs: - 03463 Returns: Pointer to the first previous sibling node which is not a NodeHidden 03464 Purpose: For finding the previous sibling of a node (ignoring all NodeHidden nodes). 03465 03466 This routine should only be used if it is vital that a NodeHidden is 03467 not returned. It is much slower than Node::FindPrevious. 03468 03469 SeeAlso: Node::FindPrevious 03470 Errors: 03471 03472 **********************************************************************************************/ 03473 03474 Node* Node::FindPrevNonHidden(void) const 03475 { 03476 Node* Current = Previous; 03477 if (Current != NULL) 03478 { 03479 while (Current->IsNodeHidden()) 03480 { 03481 Current = Current->Previous; 03482 if (Current == NULL) break; 03483 } 03484 } 03485 return (Current); 03486 } 03487 03488 03489 03490 /********************************************************************************************* 03491 03492 > static Node* Node::DocFindFirstDepthFirst(BaseDocument *pDocToSearch) 03493 03494 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03495 Created: 13/5/93 03496 Inputs: pDocToSearch - the document to look in. 03497 Returns: The first node in a depth first traversal of the document tree 03498 or NULL if the tree is empty, except for the start node. 03499 Purpose: To find the first node in a depth first traversal of the document tree. 03500 SeeAlso: Node::DocFindNextDepthFirst 03501 Errors: If the document pointer is NULL => ERROR2 03502 03503 **********************************************************************************************/ 03504 /* 03505 Technical notes: 03506 03507 The document tree must always have a start node which is a previous sibling of the 03508 documents root. This will always be the first node to process in a depth first traversal 03509 of the tree. 03510 03511 ***********************************************************************************************/ 03512 03513 03514 Node* Node::DocFindFirstDepthFirst(BaseDocument *pDocToSearch) 03515 { 03516 // Make sure we have a document to search. 03517 ERROR2IF(pDocToSearch == NULL, NULL, "No document to search in DocFindFirstDepthFirst()"); 03518 03519 // Get the first node! 03520 return pDocToSearch->GetFirstNode(); 03521 } 03522 03523 /********************************************************************************************* 03524 03525 > Node* Node::DocFindNextDepthFirst(void) const 03526 03527 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03528 Created: 13/5/93 03529 Inputs: - 03530 Outputs: - 03531 Returns: The next node in the depth first traversal of the document tree or NULL 03532 if the traversal is complete. 03533 03534 Purpose: To find the next node in the depth first traversal of the current document 03535 tree. 03536 03537 SeeAlso: Node::DocFindFirstDepthFirst 03538 03539 Errors: - 03540 03541 03542 **********************************************************************************************/ 03543 03544 03545 Node* Node::DocFindNextDepthFirst(void) 03546 { 03547 Node* CurrentNode = this; 03548 03549 if (CurrentNode->Next != NULL) 03550 { 03551 CurrentNode = CurrentNode->Next; 03552 03553 // Find leftmost child node 03554 while(CurrentNode->Child != NULL) 03555 CurrentNode = CurrentNode->Child; 03556 03557 return (CurrentNode); 03558 03559 } 03560 else 03561 return (CurrentNode->Parent); 03562 } 03563 03564 03565 /********************************************************************************************* 03566 03567 > Node* Node::FindFirstDepthFirst(void) 03568 03569 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03570 Created: 13/5/93 03571 Inputs: None 03572 Outputs: - 03573 Returns: The first node in a depth first traversal of this subtree. 03574 03575 Purpose: To find the first node in a depth first traversal of this subtree 03576 03577 03578 SeeAlso: Node::FindNextDepthFirst 03579 03580 Errors: An assertion failure will occur if the current document is NULL 03581 03582 03583 03584 **********************************************************************************************/ 03585 03586 03587 Node* Node::FindFirstDepthFirst(void) 03588 { 03589 // Find the leftmost child node 03590 Node* Current = this; 03591 while (Current->FindFirstChild() != NULL) 03592 { 03593 Current = Current->FindFirstChild(); 03594 } 03595 return (Current); 03596 } 03597 03598 /********************************************************************************************* 03599 03600 > Node* Node::FindNextDepthFirst(Node* Subtree) const 03601 03602 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03603 Created: 13/5/93 03604 03605 Inputs: Subtree: The root of the subtree 03606 Outputs: - 03607 Returns: The next node in a depth-first traversal of the subtree, or NULL if there 03608 are no more nodes. 03609 03610 03611 Purpose: To find the next node in the depth first traversal of the subtree. 03612 03613 SeeAlso: Node::FindFirstDepthFirst 03614 03615 Errors: - 03616 03617 03618 **********************************************************************************************/ 03619 03620 03621 Node* Node::FindNextDepthFirst(Node* Subtree) 03622 { 03623 if (this != Subtree) // There are more nodes in the subtree 03624 { 03625 Node* CurrentNode = this; 03626 03627 if (CurrentNode->Next != NULL) // Has this node got any siblings 03628 { 03629 CurrentNode = CurrentNode->Next; 03630 03631 // Find leftmost child node 03632 while(CurrentNode->Child != NULL) 03633 { 03634 CurrentNode = CurrentNode->Child; 03635 } 03636 03637 return (CurrentNode); 03638 } 03639 else 03640 { 03641 return (CurrentNode->Parent); 03642 } 03643 } 03644 return (NULL); 03645 } 03646 03647 03648 03649 03650 /********************************************************************************************* 03651 03652 > Node* Node::FindFirstPreorder() 03653 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 03654 Created: 15/06/2005 03655 Inputs: - 03656 Outputs: - 03657 Returns: The First node in a preorder traversal of the subtree, or NULL if there 03658 are no more nodes. 03659 Purpose: To find the next node in a preorder traversal of the subtree. 03660 SeeAlso: Node::FindFirstDepthFirst 03661 03662 **********************************************************************************************/ 03663 03664 Node* Node::FindFirstPreorder() 03665 { 03666 return this; 03667 } 03668 03669 03670 03671 03672 /********************************************************************************************* 03673 03674 > Node* Node::FindNextPreorder(Node* pRoot = NULL, BOOL bSkipSubtree = FALSE) 03675 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 03676 Created: 15/06/2005 03677 Inputs: - 03678 Outputs: - 03679 Returns: The Next node in a preorder traversal of the subtree, or NULL if there 03680 are no more nodes. 03681 Purpose: To find the next node in a preorder traversal of the subtree. 03682 SeeAlso: Node::FindFirstDepthFirst 03683 03684 **********************************************************************************************/ 03685 03686 Node* Node::FindNextPreorder(Node* pRoot, BOOL bSkipSubtree) 03687 { 03688 Node* pNode = this; 03689 03690 // We have visited this, so visit its children, then visit siblings and finally parents siblings 03691 if (pNode->FindFirstChild() && !bSkipSubtree) 03692 return pNode->FindFirstChild(); 03693 03694 if (pNode==pRoot) 03695 return NULL; 03696 03697 if (pNode->FindNext()) 03698 return pNode->FindNext(); 03699 03700 do 03701 { 03702 pNode = pNode->FindParent(); 03703 if (pNode==NULL || pNode==pRoot) 03704 return NULL; 03705 } 03706 while (pNode->FindNext()==NULL); 03707 03708 return pNode->FindNext(); 03709 } 03710 03711 03712 03713 03714 /******************************************************************************************** 03715 03716 > Spread *Node::FindParentSpread() 03717 03718 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 03719 Created: 14/12/93 03720 Returns: Parent spread node, or NULL if no such parent can be found.. 03721 Purpose: Find the spread node to which this node is ultimately attached. 03722 Errors: ENSUREs if no parent spread is found. 03723 03724 ********************************************************************************************/ 03725 03726 Spread *Node::FindParentSpread() 03727 { 03728 ERROR2IF(this==NULL, NULL, "NULL node in Node::FindParentSpread"); 03729 ENSURE(!IsKindOf(CC_RUNTIME_CLASS(Spread)), "A spread cannot contain a spread"); 03730 03731 Node *pNode = this; 03732 03733 // Search up the tree for the parent spread 03734 while ((pNode != NULL) && !pNode->IsSpread()) 03735 pNode = pNode->Parent; 03736 03737 ENSURE(pNode != NULL, "No parent spread found in Node::FindParentSpread"); 03738 03739 return (Spread *) pNode; 03740 } 03741 03742 03743 03744 03745 /********************************************************************************************* 03746 03747 > static Chapter* Node::FindFirstChapter(BaseDocument *pDocToSearch) 03748 03749 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03750 Created: 18/5/93 03751 Inputs: pDocToSearch - the document that should be searched for the first chapter. 03752 Returns: If the document tree has any chapter nodes then a pointer to the first is 03753 returned, else NULL is returned. 03754 03755 Purpose: To find the first chapter in the document tree. 03756 03757 Errors: An assertion failure will occur if: 03758 03759 The current document has not been set in the Document class 03760 The document tree's first node is not a StartDocument 03761 The first sibling of the StartDocument is not a NodeDocument 03762 03763 SeeAlso: Node::FindNextChapter 03764 03765 Notes: This method requires that the current document has been set in the Document 03766 class. 03767 03768 **********************************************************************************************/ 03769 /* 03770 Technical notes: 03771 03772 ***********************************************************************************************/ 03773 03774 03775 Chapter* Node::FindFirstChapter(BaseDocument *pDocToSearch) 03776 { 03777 // Sanity check 03778 ERROR2IF(pDocToSearch == NULL, NULL, "NULL document in FindFirstChapter()"); 03779 03780 // Make sure that the document is not toast 03781 ERROR3IF(!pDocToSearch->GetFirstNode()->FindNext()->IsKindOf(CC_RUNTIME_CLASS(NodeDocument)), 03782 "A NodeDocument node was not found at the root of the document tree"); 03783 03784 // Get the start node 03785 Node* StartChapterList = pDocToSearch->GetFirstNode()->FindNext()->FindFirstChild(); 03786 if (StartChapterList == NULL) 03787 return NULL; 03788 else 03789 { 03790 if (StartChapterList->IsChapter()) 03791 return ((Chapter*) StartChapterList); 03792 else 03793 return(StartChapterList->FindNextChapter()); 03794 } 03795 } 03796 03797 /********************************************************************************************* 03798 03799 > Chapter* Node::FindNextChapter(void) const 03800 03801 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03802 Created: 25/5/93 03803 Inputs: - 03804 Outputs: - 03805 Returns: If the document tree has any more chapter nodes then a pointer to the next 03806 chapter node is returned, else NULL is returned. 03807 03808 Purpose: To find the next chapter in the document tree. 03809 03810 03811 **********************************************************************************************/ 03812 03813 Chapter* Node::FindNextChapter(void) 03814 { 03815 const Node* CurrentNode = this->FindNext(); 03816 03817 while (CurrentNode != NULL) 03818 { 03819 if (CurrentNode->IsChapter()) 03820 return ((Chapter*)CurrentNode); 03821 CurrentNode = CurrentNode->FindNext(); 03822 } 03823 03824 return (NULL); // No chapter found 03825 } 03826 03827 03828 03829 03830 /********************************************************************************************* 03831 03832 > NodeRenderablePaper* Node::FindNextForClippedPaperRender(void) const 03833 03834 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03835 Created: 18/5/93 03836 Returns: If the document tree has any more paper renderable nodes which require 03837 rendering then a pointer to the next to render is returned, else NULL is 03838 returned. 03839 03840 Purpose: To traverse the document tree to find the next paper renderable node which 03841 needs to be rendered, i.e. its pasteboard rectangle intersects with the current 03842 clipping rectangle. 03843 03844 The document tree is searched depth first, visiting parent paper renderables 03845 before their children. It is a sort of depth first preorder traversal. 03846 03847 SeeAlso: Node::FindFirstForClippedPaperRender 03848 03849 **********************************************************************************************/ 03850 03851 NodeRenderablePaper* Node::FindNextForClippedPaperRender(void) 03852 { 03853 Node *pNode = this; 03854 03855 // If the node is a spread, then search its children for a paper object 03856 if (pNode->IsSpread()) 03857 { 03858 pNode = pNode->FindFirstChild(); 03859 if (pNode->IsPaper()) 03860 return (NodeRenderablePaper *) pNode; // Found a paper object 03861 } 03862 03863 // Search this node's siblings for another paper object 03864 do 03865 { 03866 pNode = pNode->FindNext(); 03867 } 03868 while ((pNode != NULL) && !pNode->IsPaper()); 03869 03870 // Return pointer to next page, or NULL if no more paper objects left to render. 03871 return ((NodeRenderablePaper *) pNode); 03872 } 03873 03874 /********************************************************************************************* 03875 03876 > Node * Node::FindFirstForClippedInkRender( DocRect* pClipRect, 03877 RenderRegion* pRender, 03878 BOOL ExcludeLockedLayers) 03879 03880 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>, Modified by Tim & Rik for coordinate changes 03881 03882 Created: 18/5/93 03883 Inputs: pClipRect: The clipping rectangle 03884 pRender: The render region 03885 ExcludeLockedLayers: When true objects on locked layers do not get rendered 03886 (used for hit detection) 03887 03888 Outputs: 03889 Returns: If the document tree has any NoderRenderableInk or NodeAttribute nodes which 03890 require rendering then a pointer to the first is returned, else NULL is 03891 returned. 03892 03893 Purpose: To traverse the document tree depth first to find the first NodeRenderableInk 03894 or NodeAttribute node which needs to be rendered, i.e. in the case of a 03895 NodeRenderableInk node its bounding rectangle intersects with the current 03896 clipping rectangle (and it's not on a hidden layer). 03897 03898 This routine can only be called for a spread node 03899 03900 SeeAlso: Node::FindNextForClipperInkRender 03901 03902 Errors: An assertion failure will occur if the render region is NULL or if this node 03903 is not a spread. 03904 03905 03906 **********************************************************************************************/ 03907 // Note ExcludeLockedLayers should go when these routines are no longer used for hit detection ! 03908 03909 Node* Node::FindFirstForClippedInkRender( DocRect* pClipRect, 03910 RenderRegion* pRender, 03911 BOOL ExcludeLockedLayers, 03912 Node* pStopNode) 03913 { 03914 ENSURE(pRender != NULL, "Render region NULL in FindFirstForClippedInkRender"); 03915 ENSURE( IsKindOf(CC_RUNTIME_CLASS(Spread)), "Oh No, that's not a spread in FindFirstForClippedInkRender" ); 03916 // Let FindNextForClippedInkRender do all the work 03917 return FindNextForClippedInkRender(pClipRect, pRender, ExcludeLockedLayers, pStopNode); 03918 } 03919 03920 /******************************************************************************************** 03921 03922 > Node *Node::FindChildToRender(DocRect *const pClipRect, RenderRegion *const pRender) 03923 03924 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 03925 Created: 18/01/94 03926 Inputs: pClipRect - the clip rectangle to check against. 03927 pRender - the render region in question. 03928 Returns: The child node to render, or NULL if none are suitable. 03929 Purpose: Find the first child of this node that needs rendering. 03930 This follows the children (assuming they intersect with the clipping 03931 rectangle), and finds (via a depth first search) the first child that 03932 should be rendered according to our rules. 03933 The node should be either: 03934 03935 (a) a NodeAttrbute, OR 03936 (b) a NodeRenderable that intersects the clipping region. 03937 03938 All other nodes (e.g. NodeHidden) are not rendered. 03939 Errors: - 03940 SeeAlso: - 03941 03942 ********************************************************************************************/ 03943 // Note ExcludeLockedLayers should go when these routines are no longer used for hit detection ! 03944 03945 Node *Node::FindChildToRender(DocRect *const pClipRect, RenderRegion *const pRender, BOOL ExcludeLockedLayers, 03946 Node* pStopNode) 03947 { 03948 ENSURE(this != NULL, "FindChildToRender called on NULL pointer"); 03949 03950 Node *pNode = this; 03951 03952 SubtreeRenderState state = pNode->RenderSubtree(pRender); 03953 if (state!=SUBTREE_ROOTANDCHILDREN && !pNode->IsAnAttribute()) 03954 { 03955 pRender->SaveContext(); 03956 return pNode; 03957 } 03958 03959 // If this node has any children, save the context first. 03960 Node *pChild = pNode->Child; 03961 03962 if (pChild != NULL) 03963 pRender->SaveContext(); 03964 03965 do 03966 { 03967 if (pChild != NULL) 03968 { 03969 // Should it be rendered? 03970 if (pChild->NeedsToRender(pRender)) //(Flags.Required) 03971 { 03972 // See if this node has any suitable children to render. 03973 Node *pChildToRender = pChild->FindChildToRender(pClipRect, pRender, ExcludeLockedLayers); 03974 03975 if (pChildToRender != NULL) 03976 // This child has a child of its own to render so return it. 03977 return pChildToRender; 03978 else 03979 // This child has no children to render, so just render this child. 03980 return pChild; 03981 } 03982 03983 } 03984 else 03985 // This node has no children. 03986 return NULL; 03987 03988 // No luck - try the next child. 03989 pChild = pChild->Next; 03990 03991 } while (pChild != NULL);// && pChild != pStopNode ); 03992 03993 // No child nodes found to render 03994 ENSURE(pRender != NULL, "NULL Render region found !!"); 03995 return NULL; 03996 } 03997 03998 03999 04000 04001 /********************************************************************************************* 04002 04003 > Node* Node::FindNextForClippedInkRender( DocRect* pClipRect, 04004 RenderRegion *pRender, 04005 BOOL ExcludeLockedLayers) 04006 04007 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>, Modifioed by Tim & Rik for coordinate conversion 04008 Created: 18/5/93 04009 04010 Inputs: pClipRect: The clipping rectangle 04011 pRender: The render region 04012 ExcludeLockedLayers: When true objects on locked layers do not get rendered 04013 (used for hit detection) 04014 04015 Outputs: - 04016 Returns: If the document tree has any more NodeRenderableInk or NodeAttribute nodes 04017 which require rendering then a pointer to the next to render is returned, 04018 else NULL is returned. 04019 04020 Purpose: To traverse the document tree depth first to find the next NodeRenderableInk 04021 or NodeAttribute node which needs to be rendered, i.e. in the case of a 04022 NodeRenderableInk its bounding rectangle intersects with the current clipping 04023 rectangle. 04024 04025 SeeAlso:: Node::FindFirstForClippedInkRender 04026 04027 Errors: An assertion failure will occur if LastNode is NULL. 04028 04029 **********************************************************************************************/ 04030 // Note ExcludeLockedLayers should go when these routines are no longer used for hit detection ! 04031 04032 Node* Node::FindNextForClippedInkRender( DocRect* pClipRect, 04033 RenderRegion *pRender, 04034 BOOL ExcludeLockedLayers, 04035 Node* pStopNode) 04036 { 04037 ENSURE(pRender != NULL, "Render region NULL in FindNextForClippedInkRender"); 04038 Node* pNode = this; 04039 BOOL IsSpread = pNode->IsSpread(); 04040 04041 do 04042 { 04043 // If this node (which has been rendered) has any children, then those children have 04044 // also been rendered, but they have just gone out of scope, so restore the attribute 04045 // context. 04046 if (!IsSpread && (pNode->Child != NULL)) 04047 { 04048 pRender->RestoreContext(); 04049 } 04050 04051 04052 // If this Node is non-NULL 04053 while (IsSpread || (pNode->Next != NULL)) 04054 { 04055 // If this node is not a spread, move to the next sibling. 04056 if (!IsSpread) 04057 pNode = pNode->Next; 04058 04059 if (IsSpread || pNode->NeedsToRender(pRender)) //Flags.Required) 04060 { 04061 // Follow the child links (saving the context as we go) to the deepest child 04062 // of this node, and then return this node for rendering. 04063 // NB. If no children, then this code just returns the current node to render. 04064 Node *pChild = pNode->FindChildToRender(pClipRect, pRender, ExcludeLockedLayers, pStopNode); 04065 04066 if (pChild != NULL) 04067 return pChild; 04068 else if (!IsSpread) 04069 return pNode; 04070 else 04071 // Spread has nothing at all to render 04072 return NULL; 04073 } 04074 04075 // Definitely not rendering a spread anymore 04076 IsSpread = FALSE; 04077 ENSURE(!pNode->IsKindOf(CC_RUNTIME_CLASS(Spread)), 04078 "Node should not be a spread!"); 04079 } 04080 04081 // No siblings left to render (i.e. that intersect the clipping rectangle), so 04082 // return to the parent. 04083 pNode = pNode->Parent; 04084 04085 ENSURE(pNode != NULL, "NULL parent found in FindNextForClippedInkRender"); 04086 04087 // If the parent is NodeRenderableInk or a NodeAttribute (ie renderable), then return it. 04088 if (pNode->IsAnObject() || pNode->IsAnAttribute()) 04089 // We want to render this node. 04090 return pNode; 04091 04092 } while (!pNode->IsSpread()); 04093 04094 // We found no more renderable nodes in this spread, so stop looking. 04095 // If the spread had any children, then FindChildToRender would have called 04096 // SaveContext(), so we call RestoreContext() to balance it. 04097 if (pNode->Child != NULL) 04098 pRender->RestoreContext(); 04099 04100 // All done. 04101 return NULL; 04102 } 04103 04104 04105 /********************************************************************************************* 04106 04107 > Node *Node::FindFirstForUnclippedInkRender(RenderRegion* pRender) 04108 04109 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 04110 Created: 19/6/95 04111 Inputs: pRender: The render region 04112 Returns: If the document tree has any NoderRenderableInk or NodeAttribute nodes which 04113 require rendering then a pointer to the first is returned, else NULL is 04114 returned. 04115 Purpose: To traverse the document tree depth first to find the first NodeRenderableInk 04116 or NodeAttribute node which needs to be rendered, regardless of the clip 04117 rectangle of the render region (and it's not on a hidden layer). 04118 04119 This routine can only be called for a spread node 04120 SeeAlso: Node::FindNextForUnclippedInkRender 04121 Errors: An assertion failure will occur if the render region is NULL or if this node 04122 is not a spread. 04123 04124 04125 **********************************************************************************************/ 04126 04127 Node *Node::FindFirstForUnclippedInkRender(RenderRegion* pRender) 04128 { 04129 ENSURE(pRender != NULL, "Render region NULL in FindFirstForUnclippedInkRender"); 04130 ENSURE( IsKindOf(CC_RUNTIME_CLASS(Spread)), "Oh No, that's not a spread in FindFirstForUnclippedInkRender" ); 04131 // Let FindNextForUnclippedInkRender do all the work 04132 return FindNextForUnclippedInkRender(pRender); 04133 } 04134 04135 /******************************************************************************************** 04136 04137 > Node *Node::FindChildToRenderUnclipped(RenderRegion *const pRender) 04138 04139 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 04140 Created: 19/6/95 04141 Inputs: pRender - the render region in question. 04142 Returns: The child node to render, or NULL if none are suitable. 04143 Purpose: Find the first child of this node that needs rendering. 04144 This follows the children (assuming they intersect with the clipping 04145 rectangle), and finds (via a depth first search) the first child that 04146 should be rendered according to our rules. 04147 The node should be either: 04148 04149 (a) a NodeAttribute, OR 04150 (b) a NodeRenderableBounded. 04151 04152 All other nodes (e.g. NodeHidden) are not rendered. Hidden layers are 04153 bypassed. 04154 04155 ********************************************************************************************/ 04156 04157 Node *Node::FindChildToRenderUnclipped(RenderRegion *const pRender) 04158 { 04159 ENSURE(this != NULL, "FindChildToRenderUnclipped called on NULL pointer"); 04160 04161 Node *pNode = this; 04162 04163 // INT32 DoFindChildren = PRE_RENDER_CHILDREN; 04164 04165 SubtreeRenderState state = pNode->RenderSubtree(pRender, NULL, FALSE); // Don't clip! 04166 if (state!=SUBTREE_ROOTANDCHILDREN && !pNode->IsAnAttribute()) 04167 { 04168 pRender->SaveContext(); 04169 return pNode; 04170 } 04171 04172 // If this node has any children, save the context first. 04173 Node *pChild = pNode->Child; 04174 04175 if (pChild != NULL) 04176 { 04177 pRender->SaveContext(); 04178 } 04179 04180 do 04181 { 04182 if (pChild != NULL) 04183 { 04184 // Should it be rendered? 04185 BOOL NeedsToRender = pChild->ShouldBeRendered(); 04186 04187 // Special case for layers - don't do hidden layers! 04188 if (pChild->IsLayer()) 04189 { 04190 NeedsToRender = pChild->NeedsToRender(pRender); // Clipped! 04191 } 04192 04193 if (NeedsToRender) 04194 { 04195 // See if this node has any suitable children to render. 04196 Node *pChildToRender = pChild->FindChildToRenderUnclipped(pRender); 04197 04198 if (pChildToRender != NULL) 04199 // This child has a child of its own to render so return it. 04200 return pChildToRender; 04201 else 04202 // This child has no children to render, so just render this child. 04203 return pChild; 04204 } 04205 } 04206 else 04207 // This node has no children. 04208 return NULL; 04209 04210 // No luck - try the next child. 04211 pChild = pChild->Next; 04212 04213 } while (pChild != NULL); 04214 04215 // No child nodes found to render 04216 ENSURE(pRender != NULL, "NULL Render region found !!"); 04217 return NULL; 04218 } 04219 04220 04221 04222 04223 /********************************************************************************************* 04224 04225 > Node* Node::FindNextForUnclippedInkRender(RenderRegion *pRender) 04226 04227 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 04228 Created: 19/6/95 04229 Inputs: pRender: The render region 04230 Returns: If the document tree has any more NodeRenderableInk or NodeAttribute nodes 04231 which require rendering then a pointer to the next to render is returned, 04232 else NULL is returned. 04233 Purpose: To traverse the document tree depth first to find the next NodeRenderableInk 04234 or NodeAttribute node which needs to be rendered, ignoring the clipping 04235 rectangle of the clip region. (i.e. all renderable nodes except those on 04236 hidden layers). 04237 SeeAlso:: Node::FindFirstForUnclippedInkRender 04238 Errors: An assertion failure will occur if LastNode is NULL. 04239 04240 **********************************************************************************************/ 04241 04242 Node* Node::FindNextForUnclippedInkRender(RenderRegion *pRender) 04243 { 04244 ENSURE(pRender != NULL, "Render region NULL in FindNextForUnclippedInkRender"); 04245 Node* pNode = this; 04246 04247 BOOL IsSpread = pNode->IsSpread(); 04248 04249 do 04250 { 04251 // If this node (which has been rendered) has any children, then those children have 04252 // also been rendered, but they have just gone out of scope, so restore the attribute 04253 // context. 04254 if (!IsSpread && (pNode->Child != NULL)) 04255 pRender->RestoreContext(); 04256 04257 // If this Node is non-NULL 04258 while (IsSpread || (pNode->Next != NULL)) 04259 { 04260 // If this node is not a spread, move to the next sibling. 04261 if (!IsSpread) 04262 pNode = pNode->Next; 04263 04264 // Should it be rendered? 04265 BOOL NeedsToRender = IsSpread || pNode->ShouldBeRendered(); 04266 04267 // Special case for layers - don't do hidden layers! 04268 if (pNode->IsLayer()) 04269 NeedsToRender = pNode->NeedsToRender(pRender); // Clipped!!! 04270 04271 if (NeedsToRender) 04272 { 04273 // Follow the child links (saving the context as we go) to the deepest child 04274 // of this node, and then return this node for rendering. 04275 // NB. If no children, then this code just returns the current node to render. 04276 Node *pChild = pNode->FindChildToRenderUnclipped(pRender); 04277 04278 if (pChild != NULL) 04279 return pChild; 04280 else if (!IsSpread) 04281 return pNode; 04282 else 04283 // Spread has nothing at all to render 04284 return NULL; 04285 } 04286 04287 // Definitely not rendering a spread anymore 04288 IsSpread = FALSE; 04289 ENSURE(!pNode->IsKindOf(CC_RUNTIME_CLASS(Spread)), 04290 "Node should not be a spread!"); 04291 } 04292 04293 // No siblings left to render (i.e. that intersect the clipping rectangle), so 04294 // return to the parent. 04295 pNode = pNode->Parent; 04296 04297 ENSURE(pNode != NULL, "NULL parent found in FindNextForClippedInkRender"); 04298 04299 // If the parent is NodeRenderableInk or a NodeAttribute (ie renderable), then return it. 04300 if (pNode->IsAnObject() || pNode->IsAnAttribute()) 04301 // We want to render this node. 04302 return pNode; 04303 04304 } while (!pNode->IsSpread()); 04305 04306 // We found no more renderable nodes in this spread, so stop looking. 04307 // If the spread had any children, then FindChildToRender would have called 04308 // SaveContext(), so we call RestoreContext() to balance it. 04309 if (pNode->Child != NULL) 04310 pRender->RestoreContext(); 04311 04312 // All done. 04313 return NULL; 04314 } 04315 04316 04317 04318 /*********************************************************************************************** 04319 04320 > Chapter* Node::FindEnclosingChapter(DocCoord* ChapterPos, XLONG* ChapterDepth); 04321 04322 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04323 Created: 30/4/93 04324 Inputs: - 04325 Outputs: ChapterPos: The top left hand corner of the chapters pasteboard rectangle 04326 ChapterDepth: The Sum of the lengths of all preceding chapters 04327 04328 Returns: If this node is a chapter or a node contained within a chapter then 04329 the chapter node is returned. 04330 else 04331 NULL is returned (In the non DEBUG version). 04332 04333 Purpose: For finding the enclosing chapter of a node, the position of the start of the 04334 enclosing chapter, and the chapters depth. 04335 04336 Errors: An assertion failure will occur if the node is not a chapter itself, or if 04337 the node is not enclosed within a chapter. 04338 04339 ***********************************************************************************************/ 04340 04341 Chapter* Node::FindEnclosingChapter(DocCoord* ChapterPos, XLONG* ChapterDepth) 04342 { 04343 Node* CurrentNode = this; 04344 while (CurrentNode != NULL) 04345 { 04346 if (CurrentNode->IsChapter()) 04347 { 04348 // We have found the enclosing chapter 04349 Chapter* EnclosingChapter = (Chapter*)CurrentNode; 04350 04351 // Chapter position is the top left hand corner of the chapters pasteboard 04352 ChapterPos->x = (EnclosingChapter->GetPasteboardRect().LowCorner().x); 04353 ChapterPos->y = (EnclosingChapter->GetPasteboardRect().HighCorner().y); 04354 04355 // Calculate the ChapterDepth 04356 *ChapterDepth = 0; 04357 BaseDocument *pOwnerDoc = EnclosingChapter->FindOwnerDoc(); 04358 Chapter* CurrentChapter = Node::FindFirstChapter(pOwnerDoc); 04359 04360 while (CurrentChapter != EnclosingChapter) 04361 { 04362 ENSURE(CurrentChapter != NULL, ")CurrentChapter=NULL"); // This should always be true 04363 (*ChapterDepth) += CurrentChapter->GetPasteboardRect().Height(); 04364 CurrentChapter = CurrentChapter->FindNextChapter(); 04365 } 04366 return (EnclosingChapter); 04367 } 04368 else 04369 CurrentNode = CurrentNode->FindParent(); 04370 } 04371 ENSURE(FALSE,"Trying to find the enclosing chapter\nof a node which has no enclosing chapter"); 04372 return (NULL); 04373 } 04374 04375 04376 04377 /******************************************************************************************** 04378 04379 > Node* Node::FindParentOfSelected() 04380 04381 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 04382 Created: 07/10/94 04383 Inputs: - 04384 Outputs: - 04385 Returns: The root node of the subtree containing this "selected-inside" node. 04386 If this node is not "selected-inside" then NULL is returned. 04387 Purpose: To find the node at the normal selection surface from one of its 04388 selected-inside children. Note that this routine can be used to test whether 04389 a node is "selected-inside" or not by testing whether the Node* returned is 04390 NULL or not. (NULL means not selected-inside.) 04391 04392 ********************************************************************************************/ 04393 04394 Node* Node::FindParentOfSelected() 04395 { 04396 ERROR2IF(this==NULL,NULL,"FindParentOfSelected called on NULL node."); 04397 04398 Node* pParentOf = NULL; 04399 Node* pParent = Parent; 04400 while ( pParent!=NULL && !pParent->IsLayer() ) 04401 { 04402 pParentOf = pParent; // Record last parent before we reached the Layer 04403 pParent = pParent->Parent; // Find it's parent. 04404 } 04405 ERROR3IF(pParent==NULL,"Node doesn't seem to be in a layer!"); 04406 04407 return pParentOf; 04408 } 04409 04410 04411 /******************************************************************************************** 04412 > Node* Node::FindFirstGeometryLinkedAttr() 04413 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 04414 Created: 8/5/00 04415 Inputs: - 04416 Outputs: - 04417 Returns: NodeAttribute child of this node which is linked to this nodes geometry 04418 NULL if no geometry linked attributes are attached to this node 04419 Purpose: Used primarily to inform the geomoetry linked attribute that this node 04420 has had some operation performed on it - direclty (via op) or indirectly (via parent 04421 or child nodes) - which has altered its geometry (ie inkpath or shape onscreen) 04422 ********************************************************************************************/ 04423 NodeAttribute* Node::FindFirstGeometryLinkedAttr() 04424 { 04425 Node* pCurr = FindFirstChild(); 04426 while(pCurr) 04427 { 04428 if(pCurr->IsAnAttribute()) 04429 if(((NodeAttribute*)pCurr)->IsLinkedToNodeGeometry()) 04430 return (NodeAttribute*) pCurr; 04431 04432 pCurr = pCurr->FindNext(); 04433 } 04434 04435 return NULL; 04436 } 04437 04438 /******************************************************************************************** 04439 > Node* Node::FindNextGeometryLinkedAttr() 04440 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 04441 Created: 8/5/00 04442 Inputs: - 04443 Outputs: - 04444 Returns: NodeAttribute child of this node which is linked to this nodes geometry 04445 NULL if no geometry linked attributes are attached to this node 04446 Purpose: Used in conjunction with FindFirstGeometryLinkedAttr find all geometry 04447 linked attributesm in order to inform them of a change to this nodes shape 04448 ********************************************************************************************/ 04449 NodeAttribute* Node::FindNextGeometryLinkedAttr() 04450 { 04451 Node* pCurr = FindNext(); 04452 while(pCurr) 04453 { 04454 if(pCurr->IsAnAttribute()) 04455 if(((NodeAttribute*)pCurr)->IsLinkedToNodeGeometry()) 04456 return (NodeAttribute*) pCurr; 04457 04458 pCurr = pCurr->FindNext(); 04459 } 04460 04461 return NULL; 04462 } 04463 04464 #ifdef _DEBUG 04465 /********************************************************************************************* 04466 04467 > void Node::ShowDebugTree(void) const 04468 04469 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04470 Created: 19/4/93 04471 Inputs: - 04472 Outputs: - 04473 Returns: - 04474 Purpose: This method displays the camelot tree for debugging purposes, it should 04475 be called from the StartDocument node. 04476 04477 SeeAlso: Node::ShowDebugTreeDetails 04478 Errors: - 04479 04480 **********************************************************************************************/ 04481 04482 04483 void Node::ShowDebugTree(void) const 04484 { 04485 #if DEBUG_TREE 04486 enum {LevelIndentSpaces = 10}; 04487 BYTE IndentString[LevelIndentSpaces+1]; 04488 04489 // Initialize the Indent string 04490 for(INT32 i=0; i<LevelIndentSpaces; i++) 04491 IndentString[i] = ' '; 04492 IndentString[LevelIndentSpaces] = 0; 04493 04494 ShowDebugTreeHelper(this,0,IndentString); 04495 #endif 04496 } 04497 04498 /********************************************************************************************* 04499 04500 > void Node::ShowDebugTreeHelper(const Node* const Root, 04501 INT32 TreeLevel, 04502 BYTE* IndentString) const 04503 04504 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04505 Created: 19/4/93 04506 04507 Inputs: Root: Root node of the subtree to be output 04508 TreeLevel: Current level in the camelot tree 04509 IndentString: String containing number of spaces to indent for each level 04510 in the tree. 04511 04512 Outputs: - 04513 Returns: - 04514 Purpose: To show a subtree of the Camelot tree 04515 04516 Errors: - 04517 Scope: private 04518 04519 **********************************************************************************************/ 04520 04521 04522 void Node::ShowDebugTreeHelper(const Node* const Root, 04523 INT32 TreeLevel, 04524 BYTE* IndentString) const 04525 { 04526 #if DEBUG_TREE 04527 const Node* CurrentNode = Root; // The current node position in the tree 04528 04529 do 04530 { 04531 // Indent to the correct tree level 04532 for(INT32 i=0; i<TreeLevel;i++) 04533 TRACE( _T("%s"),(const char*)IndentString); 04534 04535 CurrentNode->ShowDebugTreeDetails(); 04536 TRACE( _T("\n")); // Move to next output line 04537 04538 // If the current node has children then show them 04539 if (CurrentNode->Child != NULL) 04540 ShowDebugTreeHelper(CurrentNode->Child, TreeLevel + 1, IndentString); 04541 04542 CurrentNode = CurrentNode->Next; // Next sibling 04543 } while (CurrentNode != NULL); 04544 #endif 04545 } 04546 04547 04548 /********************************************************************************************* 04549 04550 > void Node::ShowDebugTreeDetails() const 04551 04552 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04553 Created: 29/4/93 04554 04555 Inputs: - 04556 04557 Outputs: - 04558 Returns: - 04559 Purpose: This virtual function shows a line describing the node for use when displaying 04560 the debug tree. 04561 04562 Errors: - 04563 04564 **********************************************************************************************/ 04565 04566 04567 void Node::ShowDebugTreeDetails() const 04568 { 04569 #if DEBUG_TREE 04570 TRACE( _T("Tag = %lu, Flgs( "), Tag); 04571 if (Flags.Selected) 04572 TRACE( _T("SELECTED ")); 04573 if (Flags.Renderable) 04574 TRACE( _T("RENDERABLE ")); 04575 if (Flags.Locked) 04576 TRACE( _T("LOCKED ")); 04577 if (Flags.Mangled) 04578 TRACE( _T("MANGLED ")); 04579 if (Flags.Marked) 04580 TRACE( _T("MARKED ")); 04581 TRACE( _T(")")); 04582 #endif 04583 } 04584 04585 04586 04587 /******************************************************************************************** 04588 04589 > void* Node::GetDebugDetails(StringBase* Str) 04590 04591 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04592 Created: 21/9/93 04593 Inputs: - 04594 Outputs: Str: String giving debug info about the node 04595 Returns: - 04596 Purpose: For obtaining debug information about the Node 04597 Errors: - 04598 SeeAlso: - 04599 04600 ********************************************************************************************/ 04601 04602 04603 void Node::GetDebugDetails(StringBase* pStr) 04604 { 04605 #if DEBUG_TREE 04606 String_256 TempStr; 04607 TempStr._MakeMsg(TEXT("Tag = #1%lu\r\n"), (UINT32) GetTag()); 04608 04609 *pStr += TempStr; 04610 *pStr += TEXT("\r\n Node Flags ( "); 04611 04612 if (IsSelected()) *pStr += TEXT("SELECTED "); 04613 if (IsRenderable()) *pStr += TEXT("RENDERABLE "); 04614 if (IsLocked()) *pStr += TEXT("LOCKED "); 04615 if (IsMangled()) *pStr += TEXT("MANGLED "); 04616 if (IsMarked()) *pStr += TEXT("MARKED "); 04617 04618 *pStr += TEXT(")\r\nSelect-inside Flags ( "); 04619 04620 if (IsParentOfSelected()) *pStr += TEXT("PARENT "); 04621 if (IsChildOfSelected()) *pStr += TEXT("CHILD "); 04622 04623 *pStr += TEXT(")\r\n"); 04624 #endif 04625 } 04626 04627 #endif // _DEBUG 04628 04629 /******************************************************************************************** 04630 04631 > void Node::IncHiddenCnt(void) 04632 04633 04634 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04635 Created: 26/10/93 04636 Inputs: - 04637 Outputs: - 04638 Returns: - 04639 Purpose: Increments the count of the number of NodeHidden nodes which reffer to the 04640 node. This routine should only be called from the NodeHidden methods. 04641 Errors: - 04642 SeeAlso: - 04643 04644 ********************************************************************************************/ 04645 04646 void Node::IncHiddenCnt(void) 04647 { 04648 HiddenRefCnt++; 04649 } 04650 04651 /******************************************************************************************** 04652 04653 > void Node::DecHiddenCnt(void) 04654 04655 04656 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04657 Created: 26/10/93 04658 Inputs: - 04659 Outputs: - 04660 Returns: - 04661 Purpose: Decrements the count of the number of NodeHidden nodes which reffer to the 04662 node. This routine should only be called from the NodeHidden methods 04663 Errors: - 04664 SeeAlso: - 04665 04666 ********************************************************************************************/ 04667 04668 void Node::DecHiddenCnt(void) 04669 { 04670 ENSURE((HiddenRefCnt != 0), "Trying to decrement a zero Hidden Node refference count"); 04671 HiddenRefCnt--; 04672 } 04673 04674 /******************************************************************************************** 04675 04676 > UINT32 Node::GetHiddenCnt(void) 04677 04678 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04679 Created: 26/10/93 04680 Inputs: - 04681 Outputs: - 04682 Returns: The number of hidden nodes which refer to the node. 04683 Purpose: For finding out how many hidden nodes reffer to the node. 04684 Errors: - 04685 SeeAlso: - 04686 04687 ********************************************************************************************/ 04688 04689 UINT32 Node::GetHiddenCnt(void) 04690 { 04691 return (HiddenRefCnt); 04692 } 04693 04694 04695 04696 04697 /******************************************************************************************** 04698 04699 > const TCHAR* Node::Name() const 04700 04701 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 04702 Created: 7/6/94 04703 Returns: A character string which contains some text which names this node. 04704 Purpose: Useful for debugging - actually, it only exists in the debug build. 04705 04706 ********************************************************************************************/ 04707 04708 #ifdef _DEBUG 04709 04710 const TCHAR* Node::Name() const 04711 { 04712 return GetRuntimeClass()->GetClassName(); 04713 } 04714 04715 #endif 04716 04717 04718 04719 /*********************************************************************************************** 04720 04721 > virtual BOOL Node::HidingNode() 04722 04723 Author: Will_Cowling (Xara Group Ltd) <camelotdev@xara.com> 04724 Created: 9/11/94 04725 Returns: TRUE if all was ok. FALSE if an error occured. 04726 Purpose: This virtual function is called whenever the node is hidden. 04727 It allows the node do things like 'optimise' itself to use less memory or 04728 send a message to let others know it's is being hidden etc. 04729 04730 ALWAYS CALL THE BASE CLASS' FUNCTION FROM YOUR OVERRIDDEN FUNCTION. 04731 04732 ***********************************************************************************************/ 04733 04734 BOOL Node::HidingNode() 04735 { 04736 return TRUE; 04737 } 04738 04739 /*********************************************************************************************** 04740 04741 > virtual BOOL Node::ShowingNode() 04742 04743 Author: Will_Cowling (Xara Group Ltd) <camelotdev@xara.com> 04744 Created: 9/11/94 04745 Returns: TRUE if all was ok. FALSE if an error occured (eg Out of memory). 04746 Purpose: This virtual function is called whenever the node is re-shown after being 04747 Hidden. 04748 It allows the node to reconstruct itself if it was optimised or 04749 send a message to let others know it is back etc. 04750 04751 ALWAYS CALL THE BASE CLASS' FUNCTION FROM YOUR OVERRIDDEN FUNCTION. 04752 04753 ***********************************************************************************************/ 04754 04755 BOOL Node::ShowingNode() 04756 { 04757 return TRUE; 04758 } 04759 04760 04761 /******************************************************************************************** 04762 04763 > virtual INT32 Node::ComplexHide(UndoableOperation* pOp, Node* pNextInRange) 04764 04765 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 04766 Created: 3/5/95 04767 Inputs: pOp - a pointer to an undoable operation 04768 pNextInRange - a pointer to the next node in the range 04769 04770 Returns: -1 = The routine failed to hide this node. 04771 0 = Ignored, this object does not support complex hide operations, so 04772 carry on and hide the node as normal. 04773 +1 = The node and possibly various others have been hidden correctly. 04774 04775 Purpose: This function can be overridden by complex objects who wish to gain more 04776 control in what happens when they are hidden. For instance some nodes may 04777 not want to be hidden at all. If this function is not overridden, the normal 04778 action will be used, which is to use DoHideNode() on the node. It may be that 04779 some complex parents may wish to retain various sets of nodes within themselves 04780 and allow others to be hidden. To inherit this facility in your node, you 04781 simply need to override this virtual function and handle your own hiding of 04782 the node. 04783 04784 An example of the use of this function is inside the TextObject. 04785 TextCharacters can be hidden but EOLNodes and Carets cannot, although they regularly 04786 appear in the selection range. Hence the text objects members override this 04787 function and ask the textstory to perform the complex hide operation. It will be 04788 called on every selected child and should only hide itself when the last child 04789 is called. It can easily work this out by using the pNextInRange pointer which may 04790 be null or not a member of this text story. Only at this stage are nodes in the 04791 story hidden to avoid corrupting the external range scan. 04792 Hidding nodes which should appear next in range is never a good idea. 04793 04794 SeeAlso: VisibleTextStory::ComplexHide() 04795 04796 ********************************************************************************************/ 04797 04798 INT32 Node::ComplexHide(UndoableOperation* pOp, Node* pNextInRange) 04799 { 04800 // Always ignore this call in the base class 04801 return 0; 04802 } 04803 04804 04805 04806 /******************************************************************************************** 04807 04808 > void Node::SetParentDangerous(Node* NewParent) 04809 04810 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04811 Created: 5/12/94 04812 Inputs: NewParent: The node's new parent 04813 Outputs: - 04814 Returns: - 04815 Purpose: Sets the parent of the node to NewParent. 04816 04817 ***************************************************************************** 04818 This function has a very special purpose and is very Dangerous to use. 04819 So don't use it unless you are very sure what you are doing. 04820 ***************************************************************************** 04821 04822 Errors: - 04823 SeeAlso: - 04824 04825 ********************************************************************************************/ 04826 04827 04828 void Node::SetParentDangerous(Node* NewParent) 04829 { 04830 Parent = NewParent; 04831 } 04832 04833 void Node::SetNextDangerous(Node* NewNext) 04834 { 04835 Next = NewNext; 04836 } 04837 04838 void Node::SetPreviousDangerous(Node* NewPrev) 04839 { 04840 Previous = NewPrev; 04841 } 04842 04843 void Node::SetChildDangerous(Node* NewChild) 04844 { 04845 Child = NewChild; 04846 } 04847 04848 04849 /******************************************************************************************** 04850 > virtual BOOL Node::NeedsTransparency() const 04851 04852 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 04853 Created: 23/12/94 04854 Inputs: - 04855 Outputs: - 04856 Returns: TRUE if this Node requires transparency mode to render properly. By 04857 default this returns FALSE. 04858 Purpose: Can be overriden in derived classes to return TRUE, indicating that the 04859 user may be prompted concerning transparency mode when such a node is 04860 inserted in the tree. 04861 Errors: - 04862 SeeAlso: Node::AttachNode 04863 ********************************************************************************************/ 04864 04865 BOOL Node::NeedsTransparency() const 04866 { 04867 return FALSE; // by default we don't need to be in transparency mode 04868 } 04869 04870 04871 /******************************************************************************************** 04872 04873 > BOOL Node::ChildrenNeedTransparency() 04874 04875 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 04876 Created: 02/15/95 04877 Returns: TRUE if any of this node's descendants need transparency to be displayed; 04878 FALSE if not. 04879 Purpose: Used when adding sub-trees to a document (e.g. file load, import). It scans 04880 the node's children to determine if any of them need transparency in order 04881 to be displayed correctly. 04882 NB. The node itself is not checked; only its children. 04883 SeeAlso: Node::NeedsTransparency 04884 04885 ********************************************************************************************/ 04886 04887 BOOL Node::ChildrenNeedTransparency() 04888 { 04889 #ifdef RALPH 04890 // Can't scan children when progressively loading/rendering in ralph 04891 return TRUE; 04892 #else 04893 // Start with the first child of this node. 04894 Node *pChild = FindFirstChild(); 04895 04896 while (pChild != NULL) 04897 { 04898 // Does this child (or any of its children) need transparency? 04899 if (pChild->NeedsTransparency() || pChild->ChildrenNeedTransparency()) 04900 // Yes - found some transparency 04901 return TRUE; 04902 04903 // Try the next child. 04904 pChild = pChild->FindNext(); 04905 } 04906 04907 // No transparency found 04908 return FALSE; 04909 #endif 04910 } 04911 04912 04913 /******************************************************************************************** 04914 04915 > ChangeCode Node::WarnParentOfChange(ObjChangeParam* pParam, BOOL AllParents) 04916 04917 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 04918 Created: 09/01/95 04919 Inputs: pParam = pointer to a object change parameter class 04920 AllParents = if true then tell all parents of the change, else just tell 04921 the immediate parent. 04922 Defaults to TRUE 04923 Returns: CC_OK if all warned parents have verified the change 04924 CC_FAIL if unable to go on at all 04925 Purpose: When an object changes, this function should be used to inform its parent(s) 04926 of the change. If AllParents is TRUE it will call every parent, passing the 04927 object change parameter to their OnChildChange() virtual function. 04928 04929 ********************************************************************************************/ 04930 04931 ChangeCode Node::WarnParentOfChange(ObjChangeParam* pParam, BOOL AllParents) 04932 { 04933 ERROR1IF(pParam==NULL,CC_FAIL,"Node::WarnParentOfChange() called with a null change reason"); 04934 ERROR1IF(pParam->GetChangeType()==OBJCHANGE_UNDEFINED,CC_FAIL,"Node::WarnParentOfChange() passed an illegal Change block"); 04935 04936 // find the immediate parent 04937 Node* pParent = FindParent(); 04938 ChangeCode Code = CC_OK; 04939 while (pParent) 04940 { 04941 // call the parents 'child change' function 04942 Code = pParent->OnChildChange(pParam); 04943 if (Code == CC_FAIL) 04944 return Code; 04945 // now itterate up the tree if necessary 04946 if (AllParents) 04947 pParent=pParent->FindParent(); 04948 else 04949 pParent=NULL; 04950 } 04951 return Code; 04952 } 04953 04954 /******************************************************************************************** 04955 04956 > virtual ChangeCode Node::OnChildChange(ObjChangeParam* pParam) 04957 04958 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 04959 Created: 09/01/95 04960 Inputs: pParam = pointer to a object change parameter class 04961 Returns: CC_OK if we have successfully processed the change. 04962 CC_FAIL if we cannot handle this particular change and must prevent the 04963 child from continuing 04964 Purpose: This function should be overridden in derived object classes. 04965 Composite objects can use this function to respond to one of their children 04966 undergoing a change. They should return CC_FAIL whenever they are unable to 04967 cope with the change. 04968 SeeAlso: WarnParentOfChange(); 04969 04970 ********************************************************************************************/ 04971 04972 ChangeCode Node::OnChildChange(ObjChangeParam* pParam) 04973 { 04974 return CC_OK; 04975 } 04976 04977 /******************************************************************************************** 04978 04979 > virtual OpPermissionState Node::GetOpPermission() 04980 04981 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 04982 Created: 3/02/95 04983 Inputs: - 04984 Outputs: - 04985 Returns: Returns the op perission state for this node. 04986 Purpose: Use this to access the node's permission flags to find out if the current op 04987 is doable to this node. 04988 04989 PERMISSION_UNDEFINED means no op has explicitly asked this node for permission so go ahead 04990 PERMISSION_DENIED means the current op should not touch this node. 04991 PERMISSION_ALLOWED means the nice op asked and the node said YES! 04992 04993 Range uses this value to decide whether a node is in the range. A node is not in the range is its 04994 permission value is PERMISSION_DENIED, otherwise it is in the range (RangeControlFlags permitting that is) 04995 04996 This state should be set via the AllowOp() function, using the most appropriate out of Node and Range's 04997 varients. 04998 04999 SeeAlso: SetOpPermission(); 05000 05001 ********************************************************************************************/ 05002 05003 OpPermissionState Node::GetOpPermission() 05004 { 05005 if (!Flags.OpPermission1) 05006 { 05007 if (!Flags.OpPermission2) 05008 return PERMISSION_DENIED; 05009 else 05010 return PERMISSION_ALLOWED; 05011 } 05012 else 05013 return PERMISSION_UNDEFINED; 05014 } 05015 05016 /******************************************************************************************** 05017 05018 > virtual void Node::SetOpPermission(OpPermissionState NewState,BOOL AndParents = FALSE) 05019 05020 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 05021 Created: 3/02/95 05022 Inputs: NewState = the state to set the permission to 05023 AndParents = if TRUE, set the same permission for your parent, parent's parent, etc 05024 Outputs: - 05025 Returns: - 05026 Purpose: Use this to set the node's permission flags. 05027 05028 Note: Once you set a node's permission to PERMISION_ALLOWED, you can only subsequently set it to 05029 PERMISSION_UNDEFINED. i.e. if you set it to PERMISSION_ALLOWED, then try and set it to 05030 PERMISSION_DENIED, the node's permission state will stay as PERMISSION_ALLOWED. 05031 05032 SeeAlso: GetOpPermission(); 05033 05034 ********************************************************************************************/ 05035 05036 void Node::SetOpPermission(OpPermissionState NewState,BOOL AndParents) 05037 { 05038 OpPermissionState CurrentState = GetOpPermission(); 05039 05040 switch (NewState) 05041 { 05042 case PERMISSION_DENIED: 05043 if (CurrentState != PERMISSION_ALLOWED) 05044 { 05045 Flags.OpPermission1 = FALSE; 05046 Flags.OpPermission2 = FALSE; 05047 } 05048 break; 05049 05050 case PERMISSION_ALLOWED: 05051 Flags.OpPermission1 = FALSE; 05052 Flags.OpPermission2 = TRUE; 05053 break; 05054 05055 case PERMISSION_UNDEFINED: 05056 Flags.OpPermission1 = TRUE; 05057 Flags.OpPermission2 = FALSE; 05058 break; 05059 05060 default: 05061 ERROR3_PF(("Unknown OpPermissionState (%d)",NewState)); 05062 break; 05063 } 05064 05065 if (AndParents) 05066 { 05067 if (Parent != NULL) 05068 Parent->SetOpPermission(NewState,AndParents); 05069 } 05070 } 05071 05072 05073 05074 /******************************************************************************************** 05075 05076 > virtual BOOL Node::AllowOp(ObjChangeParam* pParam, BOOL SetOpPermissionState = TRUE, 05077 BOOL DoPreTriggerEdit = TRUE) 05078 05079 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 19/01/2000 05080 Created: 3/02/95 05081 Inputs: pParam = describes the way an op wants to change the node 05082 SetOpPermissionState = if TRUE the Op permission state of this node will be set according to 05083 the outcome of the call 05084 DoPreTriggerEdit = if TRUE then calls NameGallery::PreTriggerEdit. 05085 *Must* be TRUE if the calling Op may make any nodes 05086 change their bounds, eg move, line width, cut. 05087 Use TRUE if unsure. 05088 Outputs: - 05089 Returns: TRUE means the node and all its parents are happy with this op, FALSE means don't do it 05090 Purpose: This is the way to ask a node if you can do an op to it. 05091 05092 The ObjChangeParam class contains flags that describe how it will change the node 05093 05094 For example, the op could change the node's appearence (e.g. attr application, editing a path), 05095 replace the node with another node (e.g. because it uses hidden nodes to hide the original and put another 05096 node in its place, or "make shapes"), delete the node (e.g. the delete and cut ops), etc. 05097 05098 This function gives the node a chance to say NO. It also gives the parents a chance to say no too. 05099 E.g. a blend node will allow itself to be deleted, but it will NOT allow a child of itself to be deleted). 05100 05101 This call should only be made on selected, or parents of selected, nodes. It makes a decision as a 05102 straight node if it is selected. It makes a decision as a parent if it has selected children. 05103 05104 E.g. NodeBlend::AllowOp(...op delete...) 05105 if the node is selected, then it will return TRUE (parents permitting), i.e. I can be deleted 05106 if the node is a parent of selected it will return FALSE (i.e. can't delete children of blends). 05107 05108 So when the node is selected, you are asking the node if you can do the op to it. When the node is 05109 a parent of a selected node, you are asking if you can do the op to one of its children. 05110 05111 ******** 05112 05113 If the 'SetOpPermissionState' param is TRUE, the following indented lines applies: 05114 The node's op permission state is set according to the result of this function. 05115 05116 If TRUE is returned, then the node's op permission state will be left unchanged. 05117 AND the parent's op permission state will be set to PERMISSION_ALLOWED 05118 05119 if FALSE is returned, then the node's op permission state will be PERMISSION_DENIED, 05120 AND all it's parents (up to the layer) will be set to PERMISSION_DENIED 05121 05122 Also, all parents of this node are called via their AllowOp() func with the same state 05123 as this node. This means that after this call, you can guarantee that all of its parents will 05124 have either a PERMISSION_DENIED or PERMISSION_ALLOWED state. 05125 05126 Note: Even if this node tries to set all it's parents to have a PERMISSION_DENIED state, if any 05127 of its parents have previously been set to PERMISSION_ALLOWED they will remain in that state (see 05128 SetOpPermission()). Why? Well, it is possible for a parent node to have one child with a 05129 PERMISSION_DENIED and another child with a PERMISSION_ALLOWED. It this state the parent MUST be 05130 in state PERMISSION_ALLOWED, because at least one of its children will allow the op to happen to it. 05131 05132 So, after this call: 05133 The op permission state for this node will be either left unchanged (and 05134 therefore remain PERMISSION_UNDEFINED), or PERMISSION_DENIED. 05135 05136 The parent's op permission state will be either PERMISSION_ALLOWED, or PERMISSION_DENIED. 05137 05138 This is so UndoableOperation::UpdateChangedNodes() will only call OnChildChange() on parent nodes, 05139 because it only calls that func for nodes that have an op permission state of PERMISSION_ALLOWED. 05140 05141 ******** 05142 05143 SeeAlso: GetOpPermission(),SetOpPermission(); 05144 05145 ********************************************************************************************/ 05146 05147 BOOL Node::AllowOp(ObjChangeParam* pParam, BOOL SetOpPermissionState, BOOL DoPreTriggerEdit) 05148 { 05149 ERROR2IF(pParam==NULL,FALSE,"Node::AllowOp() - pParam==NULL"); 05150 05151 // if not called by a child AllowOp(), ensure AllowOp() called for all nodes in compound nodes, 05152 if (pParam->GetDirection()!=OBJCHANGE_CALLEDBYCHILD) 05153 { 05154 BOOL AnyAllowed=AllowOp_AccountForCompound( pParam, 05155 SetOpPermissionState, 05156 DoPreTriggerEdit ); 05157 // check for geometry linked attributes 05158 // NB this handles the passing of AllowOp messages to GeomLinkedAttrs on CALLEDBYPARENT 05159 // and CALLEDBYOP. 05160 // NB2 compounds which don't implement their own AllowOps will call 05161 // AccountForCompound from here so ensure that nodes don't inform 05162 // geom linked attrs of the change twice 05163 if(!IS_KIND_OF(NodeGroup)) 05164 { 05165 UndoableOperation* pChangeOp = pParam->GetOpPointer(); 05166 BOOL InformGeomLinkedAttrs = SetOpPermissionState && pChangeOp && pChangeOp->MayChangeNodeBounds(); 05167 if(InformGeomLinkedAttrs) 05168 { 05169 NodeAttribute* pNA = FindFirstGeometryLinkedAttr(); 05170 while(pNA) 05171 { 05172 pNA->LinkedNodeGeometryHasChanged(pChangeOp); 05173 pNA = pNA->FindNextGeometryLinkedAttr(); 05174 } 05175 } 05176 } 05177 05178 // if called by a parent, just pass this result back 05179 if (pParam->GetDirection()==OBJCHANGE_CALLEDBYPARENT) 05180 return AnyAllowed; 05181 } 05182 else 05183 { 05184 // clean out the calling-child ptr, so it doesn't get passed around unintentionally. 05185 pParam->SetCallingChild(NULL); 05186 } 05187 05188 05189 // at this point we must have been called directly by the op or via a child AllowOp() 05190 05191 // decide if we allow it ... err we do! 05192 BOOL allowed = TRUE; 05193 05194 // if we allowed it, see if our parents do ... 05195 if (Parent != NULL) 05196 { 05197 ObjChangeDirection OldDirection = pParam->GetDirection(); 05198 pParam->SetCallingChild(this); 05199 pParam->SetDirection(OBJCHANGE_CALLEDBYCHILD); 05200 allowed = Parent->AllowOp(pParam,SetOpPermissionState,DoPreTriggerEdit); 05201 pParam->SetDirection(OldDirection); 05202 } 05203 05204 // if setting permisions ... 05205 if (SetOpPermissionState) 05206 { 05207 // if allowed, mark parent accordingly, else mark child as denied and update parents 05208 if (!allowed) 05209 SetOpPermission(PERMISSION_DENIED,TRUE); 05210 else 05211 if (Parent != 0) Parent->SetOpPermission(PERMISSION_ALLOWED); 05212 } 05213 05214 if (allowed) 05215 { 05216 UndoableOperation* pChangeOp = pParam->GetOpPointer(); 05217 // check for geometry linked attributes (for CALLEDBYCHILD direction) 05218 if(IsCompound() && pParam->GetDirection()==OBJCHANGE_CALLEDBYCHILD) 05219 { 05220 BOOL InformGeomLinkedAttrs = SetOpPermissionState && pChangeOp && pChangeOp->MayChangeNodeBounds(); 05221 if(InformGeomLinkedAttrs) 05222 { 05223 NodeAttribute* pNA = FindFirstGeometryLinkedAttr(); 05224 while(pNA) 05225 { 05226 pNA->LinkedNodeGeometryHasChanged(pChangeOp); 05227 pNA = pNA->FindNextGeometryLinkedAttr(); 05228 } 05229 } 05230 } 05231 05232 // if we're ok so far and were asked to do a PreTriggerEdit, then 05233 // determine whether the Op may change the bounds of some nodes. 05234 // If it may, then call NameGallery::PreTriggerEdit. 05235 if(DoPreTriggerEdit) 05236 { 05237 // if the Op is non-NULL then query its MayChangeNodeBounds() method. 05238 if (pChangeOp != NULL && pChangeOp->MayChangeNodeBounds() && NameGallery::Instance()) 05239 { 05240 allowed = NameGallery::Instance()->PreTriggerEdit(pChangeOp, pParam, this); 05241 } 05242 } 05243 } 05244 05245 // return result (directly, or indirectly via a child AllowOp()) to op 05246 return allowed; 05247 } 05248 05249 /******************************************************************************************** 05250 > virtual BOOL Node::AllowOp_AccountForCompound( ObjChangeParam* pParam, 05251 BOOL SetOpPermissionState=TRUE, 05252 BOOL DoPreTriggerEdit = TRUE ) 05253 05254 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>; Karim 20/01/2000 05255 Created: 5/5/95 05256 Inputs: pParam = describes the way an op wants to change the node 05257 SetOpPermissionState = if TRUE the OpPermission of nodes should be set 05258 DoPreTriggerEdit = if TRUE then NameGallery::PreTriggerEdit is called. 05259 *Must* be TRUE if the calling Op may make any nodes 05260 change their bounds, eg move, line width, cut. 05261 Use TRUE if unsure. 05262 05263 Returns: TRUE if ANY of the objects in the coumpond node have allowed the op 05264 Purpose: if this is a compound node, ensures all child nodes have their AllowOp() called. 05265 05266 This ensures that any pre-op code in AllowOp()s will be done 05267 eg inserting insert dormat format action for TextStories 05268 05269 This also ensures post-op code in OnChildChange()s is called 05270 (if the OpPermission is set on affected nodes AND PARENTS) 05271 eg. format redraw for TextStories 05272 05273 This fixes the bug where attributes applied to a group/Mould/Blend containing 05274 a TextStory cause the text story to be formatted correctly 05275 05276 Note: Optimisation - currently only done for attribute changes and transformations. 05277 Karim 18/05/2000 - Also now done when Flags.RegenerateNode is set. 05278 ********************************************************************************************/ 05279 05280 BOOL Node::AllowOp_AccountForCompound(ObjChangeParam* pParam, BOOL SetOpPermissionState, 05281 BOOL DoPreTriggerEdit) 05282 { 05283 BOOL AnyAllowed=FALSE; 05284 05285 // 'optimised' to only do the biz if an attr changes, it's a transform or a regeneration. 05286 ObjChangeFlags Flags=pParam->GetChangeFlags(); 05287 if (IsCompound() && (Flags.Attribute || Flags.TransformNode || Flags.RegenerateNode) ) 05288 { 05289 ObjChangeDirection OldDirection=pParam->GetDirection(); 05290 pParam->SetDirection(OBJCHANGE_CALLEDBYPARENT); 05291 Node* pNode=FindFirstChild(); 05292 UndoableOperation* pChangeOp = pParam->GetOpPointer(); 05293 BOOL InformGeomLinkedAttrs = SetOpPermissionState && pChangeOp && pChangeOp->MayChangeNodeBounds(); 05294 05295 while (pNode!=NULL) 05296 { 05297 if (pNode->IsAnObject()) 05298 AnyAllowed |= pNode->AllowOp(pParam, SetOpPermissionState, DoPreTriggerEdit); 05299 else 05300 { 05301 if(pNode->IsAnAttribute() && ((NodeAttribute*)pNode)->IsLinkedToNodeGeometry()) 05302 if(InformGeomLinkedAttrs) 05303 ((NodeAttribute*)pNode)->LinkedNodeGeometryHasChanged(pChangeOp); 05304 } 05305 05306 pNode=pNode->FindNext(); 05307 } 05308 pParam->SetDirection(OldDirection); 05309 } 05310 05311 // if setting flags and any child allowed it, set this permission allowed 05312 if (AnyAllowed && SetOpPermissionState) 05313 SetOpPermission(PERMISSION_ALLOWED); 05314 05315 return AnyAllowed; 05316 } 05317 05318 05319 /******************************************************************************************** 05320 05321 > void Node::InsertChainSimple(Node* ContextNode, AttachNodeDirection Direction) 05322 05323 Author: Ben_Summers (Xara Group Ltd) <camelotdev@xara.com> 05324 Created: 29 03 95 05325 Inputs: ContextNode - the node to attach under or after 05326 Direction - where to attach it 05327 Outputs: - 05328 Returns: - 05329 Purpose: Inserts a chain of nodes at contextnode. A chain is an unconnected set of 05330 siblings. This function should be called from the first node (left most) in 05331 the chain. 05332 It doesn't do anything fancy - in fact, little more than changing a few 05333 pointers here and there. 05334 SeeAlso: AttachNode(); 05335 05336 ********************************************************************************************/ 05337 05338 void Node::InsertChainSimple(Node* ContextNode, AttachNodeDirection Direction) 05339 { 05340 ERROR3IF(Previous != 0, "Node is not first in the chain"); 05341 05342 if(Direction == FIRSTCHILD) 05343 { 05344 Node *N = this; // will be the last chain in node 05345 Node *Last = NULL; 05346 05347 // shoot though the chain setting parent pointers and find the last one 05348 while(N != 0) 05349 { 05350 N->Parent = ContextNode; 05351 Last = N; 05352 N = N->FindNext(); 05353 } 05354 05355 Last->Next = ContextNode->Child; 05356 ContextNode->Child = this; 05357 } else if(Direction == LASTCHILD) 05358 { 05359 if(ContextNode->Child != 0) 05360 { 05361 Node *End = ContextNode->FindLastChild(); 05362 05363 ERROR3IF(End->Next != 0, "Last child has next pointer"); 05364 05365 End->Next = this; 05366 Previous = End; 05367 } else { 05368 ContextNode->Child = this; 05369 } 05370 05371 Node *N = this; 05372 05373 // shoot though the chain setting parent pointers 05374 while(N != 0) 05375 { 05376 N->Parent = ContextNode; 05377 N = N->FindNext(); 05378 } 05379 } else { 05380 ERROR3("Direction not implemented yet in Node::InsertChainSimple"); 05381 } 05382 } 05383 05384 05385 05386 /******************************************************************************************** 05387 > virtual BOOL Node::PostImport() 05388 05389 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 05390 Created: 04/04/95 05391 Inputs: - 05392 Outputs: - 05393 Returns: TRUE/FALSE for success/failure 05394 Purpose: This function is called after a document is imported. Nodes should override 05395 this function to do any post-import processing. 05396 SeeAlso: Node::PostDuplicate 05397 ********************************************************************************************/ 05398 BOOL Node::PostImport() 05399 { 05400 return TRUE; 05401 } 05402 05403 05404 05405 /******************************************************************************************** 05406 > virtual BOOL Node::PostDuplicate(UndoableOperation* pOp) 05407 05408 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 05409 Created: 07/10/96 05410 Inputs: pOp - pointer to the operation that created the copy. 05411 Outputs: - 05412 Returns: TRUE/FALSE for success/failure 05413 Purpose: This function is called after this node has been created via a copy/duplicate 05414 type operation. Nodes should override this function to do any post-processing. 05415 SeeAlso: Node::PostImport 05416 ********************************************************************************************/ 05417 BOOL Node::PostDuplicate(UndoableOperation* pOp) 05418 { 05419 return TRUE; 05420 } 05421 05422 05423 05424 /******************************************************************************************** 05425 05426 void TextStory::MarkNodeAndChildren() 05427 05428 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 05429 Created: 3/5/95 05430 Inputs: - 05431 Purpose: Mark this node and all its children 05432 05433 ********************************************************************************************/ 05434 05435 void Node::MarkNodeAndChildren() 05436 { 05437 SetMarker(TRUE); 05438 MarkChildren(); 05439 } 05440 05441 /******************************************************************************************** 05442 05443 void TextStory::MarkChildren(Node* pNode) 05444 05445 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 05446 Created: 3/5/95 05447 Inputs: pNode = A pointer to a node 05448 Purpose: Mark all children of this node 05449 05450 ********************************************************************************************/ 05451 05452 void Node::MarkChildren() 05453 { 05454 Node* pNode = FindFirstChild(); 05455 while (pNode!=NULL) 05456 { 05457 pNode->SetMarker(TRUE); 05458 pNode->MarkChildren(); 05459 pNode=pNode->FindNext(); 05460 } 05461 } 05462 05463 05464 /******************************************************************************************** 05465 05466 > void Node::ClearMarks() 05467 05468 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 05469 Created: 3/5/95 05470 Inputs: - 05471 Purpose: Clear marks from this node and all its children 05472 05473 ********************************************************************************************/ 05474 05475 void Node::ClearMarks() 05476 { 05477 SetMarker(FALSE); 05478 ClearChildMarks(); 05479 } 05480 05481 05482 /******************************************************************************************** 05483 05484 > void Node::ClearChildMarks() 05485 05486 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 05487 Created: 3/5/95 05488 Inputs: - 05489 Purpose: Clear marks from all the children of this node 05490 05491 ********************************************************************************************/ 05492 05493 void Node::ClearChildMarks() 05494 { 05495 Node* pNode = FindFirstChild(); 05496 while (pNode!=NULL) 05497 { 05498 pNode->SetMarker(FALSE); 05499 pNode->ClearChildMarks(); 05500 pNode=pNode->FindNext(); 05501 } 05502 } 05503 05504 05505 05506 /******************************************************************************************** 05507 05508 > virtual BOOL Node::CanBecomeA(BecomeA* pBecomeA) 05509 05510 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 05511 Created: 7/10/94 05512 Inputs: pClass = runtime class to node you wish this node to become 05513 pNumObjects = ptr to place number of objects of type pClass that will be created (Note: can be NULL). 05514 *pNumObects in undefined on entry 05515 Outputs: - 05516 Returns: TRUE if it can, FALSE if it can't 05517 Always returns FALSE 05518 Purpose: Interrogation routine to see if a node can be changed into a different node type. 05519 05520 The number you put into pNumObjects (if it's not NULL) should exactly equal the total number 05521 of pClass objects you create. It should NOT contain any additional objects you may produce 05522 such as group objects for containing the pClass object, or attributes. 05523 05524 Also, the entry value of *pNumObjects cannot be assumed to be 0. 05525 05526 Errors: - 05527 SeeAlso: Node::DoBecomeA() 05528 05529 ********************************************************************************************/ 05530 05531 BOOL Node::CanBecomeA(BecomeA* pBecomeA) 05532 { 05533 return FALSE; 05534 } 05535 05536 05537 05538 /******************************************************************************************** 05539 05540 > virtual BOOL Node::DoBecomeA(BecomeA* pBecomeA) 05541 05542 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 05543 Created: 7/10/94 05544 Inputs: pBecomeA = ptr to info class containing everything a node needs to be able 05545 to become something else 05546 Outputs: - 05547 Returns: TRUE if successful, FALSE otherwise 05548 Always returns TRUE 05549 Purpose: Actually tries to change the node into a different node type. 05550 Errors: - 05551 SeeAlso: Node::CanBecomeA() 05552 05553 ********************************************************************************************/ 05554 05555 BOOL Node::DoBecomeA(BecomeA* pBecomeA) 05556 { 05557 // Always return TRUE so that this routine won't upset the caller. 05558 // Even though the CanBecomeA() function returns FALSE, this does NOT guarantee that DoBecomeA() 05559 // won't get called. 05560 05561 // E.g. Group::CanBecomeA() will return TRUE if ANY of its children return TRUE from their 05562 // CanBecomeA() virt func. When Group::DoBecomeA() is called, all the children's 05563 // DoBecomeA() funcs are called, so if they returned FALSE by default, the op will be aborted (this is bad). 05564 05565 return TRUE; 05566 } 05567 05568 05569 05570 /**************************************************************************** 05571 05572 > void Node::RemoveAttrTypeFromSubtree(CCRuntimeClass* AttrType, Node* pExceptThis) 05573 05574 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 05575 Created: 22/04/2005 05576 05577 Inputs: AttrType - pointer to a CCRuntimeClass 05578 pExceptThis - pointer to a Node 05579 Purpose: Searches the subtree and every attribute which has type AttrType 05580 is deleted. 05581 05582 ****************************************************************************/ 05583 05584 void Node::RemoveAttrTypeFromSubtree(CCRuntimeClass* AttrType, Node* pExceptThis) 05585 { 05586 // Traverse the subtree depth first 05587 Node* Current = FindFirstDepthFirst(); 05588 Node* Next; 05589 while (Current != NULL) 05590 { 05591 Next = Current->FindNextDepthFirst(this); 05592 // Determine if the Current node is to be hidden 05593 if (Current!=pExceptThis && Current->IsKindOf(CC_RUNTIME_CLASS(NodeAttribute))) 05594 { 05595 { 05596 if (((NodeAttribute*)Current)->GetAttributeType() == AttrType) 05597 { 05598 Current->CascadeDelete(); 05599 delete Current; 05600 } 05601 } 05602 } 05603 Current = Next; 05604 } 05605 } 05606 05607 05608 #ifdef _DEBUG 05609 /******************************************************************************************** 05610 > void Node::DT() 05611 05612 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 05613 Created: 7/2/96 05614 Purpose: Dump the document tree containing this node 05615 ********************************************************************************************/ 05616 05617 void Node::DT() 05618 { 05619 #if DEBUG_TREE 05620 Node* pNode = this; 05621 while (pNode->FindParent()) 05622 pNode = pNode->FindParent(); 05623 DebugTreeDlg::DumpSubTree(pNode); 05624 #endif 05625 } 05626 05627 /******************************************************************************************** 05628 > void Node::DST() 05629 05630 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 05631 Created: 7/2/96 05632 Purpose: Dump the subtree starting at this node in the output stream 05633 ********************************************************************************************/ 05634 05635 void Node::DST() 05636 { 05637 #if DEBUG_TREE 05638 DebugTreeDlg::DumpSubTree(this); 05639 #endif 05640 } 05641 05642 /******************************************************************************************** 05643 > void Node::DST1(INT32 FormParent=0) 05644 05645 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 05646 Created: 7/2/96 05647 Inputs: FromParent - levels to ascend before dumping sub tree 05648 Purpose: Dump the subtree starting at this node in the output stream 05649 ********************************************************************************************/ 05650 05651 void Node::DST1(INT32 FromParent) 05652 { 05653 #if DEBUG_TREE 05654 DebugTreeDlg::DumpSubTree(this,FromParent); 05655 #endif 05656 } 05657 05658 /******************************************************************************************** 05659 > void Node::DST2(INT32 FormParent=0, INT32 MaxDepth=9999) 05660 05661 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 05662 Created: 7/2/96 05663 Inputs: FromParent - levels to ascend before dumping sub tree 05664 MaxDepth - max depth to descend to 05665 Purpose: Dump the subtree starting at this node in the output stream 05666 ********************************************************************************************/ 05667 05668 void Node::DST2(INT32 FromParent, INT32 MaxDepth) 05669 { 05670 #if DEBUG_TREE 05671 DebugTreeDlg::DumpSubTree(this,FromParent,MaxDepth); 05672 #endif 05673 } 05674 #endif 05675 05676 /******************************************************************************************** 05677 > virtual SubtreeRenderState Node::RenderSubtree(RenderRegion* pRender, Node** ppNextNode, BOOL bClip = TRUE) 05678 05679 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 05680 Created: 22/06/2004 05681 Inputs: A Render Region to Render into. 05682 Returns: PRE_FAILED for something went wrong, 05683 PRE_RENDER_CHILDREN for continue to render children, 05684 PRE_NO_RENDER_CHILDREN for DO NOT Render any of my children!!!! 05685 05686 Purpose: Enables Nodes to be able to Do Pre Print time alterations or even take over 05687 the control of the current Printing of their children. 05688 05689 ********************************************************************************************/ 05690 SubtreeRenderState Node::RenderSubtree(RenderRegion* pRender, Node** ppNextNode, BOOL bClip) 05691 { 05692 return SUBTREE_ROOTANDCHILDREN; 05693 } 05694 05695 /******************************************************************************************** 05696 05697 > virtual BOOL Node::WritePreChildrenWeb(BaseCamelotFilter* pFilter) 05698 05699 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 05700 Created: 22/5/96 05701 Inputs: pFilter = ptr to filter to write to 05702 Returns: TRUE if the node has written out a record to the filter 05703 FALSE otherwise 05704 Purpose: Writes out a record that represents the node. 05705 05706 This function is called before any of the node's children are written to the filter. 05707 05708 If the node writes out a record successfully to the file, it should return TRUE. 05709 05710 If the node chooses not to write itself to the filter (e.g. because it is not appropriate 05711 for this filter), then this function should return FALSE. 05712 05713 If an error occurs, the function should call pFilter->GotError(), and return FALSE. 05714 05715 If the node does not want its child nodes to be written automatically, you should make 05716 sure you override CanWriteChildrenWeb() so it returns FALSE. 05717 05718 (e.g. this node may choose to save its sub tree itself, so it can choose which of its 05719 child nodes should be saved out) 05720 05721 SeeAlso: CanWriteChildrenWeb(), WritePostChildrenWeb() 05722 05723 ********************************************************************************************/ 05724 05725 BOOL Node::WritePreChildrenWeb(BaseCamelotFilter* pFilter) 05726 { 05727 return FALSE; 05728 } 05729 05730 // See header for WritePreChildrenWeb(). The same information applies 05731 BOOL Node::WritePreChildrenNative(BaseCamelotFilter* pFilter) 05732 { 05733 return FALSE; 05734 } 05735 05736 05737 /******************************************************************************************** 05738 05739 > virtual BOOL Node::WritePostChildrenWeb(BaseCamelotFilter* pFilter) 05740 05741 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 05742 Created: 22/5/96 05743 Inputs: pFilter = ptr to filter to write to 05744 Returns: TRUE if ok, FALSE otherwise 05745 Purpose: Gives the node a change to write data to the filter after its children 05746 have been automatically written out. 05747 05748 This function will get called even if CanWriteChildrenWeb() has returned FALSE 05749 05750 SeeAlso: CanWriteChildrenWeb(), WritePreChildrenWeb() 05751 05752 ********************************************************************************************/ 05753 05754 BOOL Node::WritePostChildrenWeb(BaseCamelotFilter* pFilter) 05755 { 05756 return TRUE; 05757 } 05758 05759 // See header for WritePostChildrenWeb(). The same information applies 05760 BOOL Node::WritePostChildrenNative(BaseCamelotFilter* pFilter) 05761 { 05762 return TRUE; 05763 } 05764 05765 /******************************************************************************************** 05766 05767 > virtual BOOL Node::CanWriteChildrenWeb(BaseCamelotFilter* pFilter) 05768 05769 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 05770 Created: 22/5/96 05771 Inputs: pFilter = ptr to filter to write to 05772 Returns: TRUE if ok to automatically write out the children, FALSE otherwise 05773 Purpose: If the node does not mind the filter automatically writing out its 05774 child nodes, then return TRUE. 05775 05776 If, however, you wish to prevent this (e.g. because you want to save out 05777 your child nodes yourself, in some selective fashion), then return FALSE 05778 05779 SeeAlso: WritePostChildrenWeb(), WritePreChildrenWeb() 05780 05781 ********************************************************************************************/ 05782 05783 BOOL Node::CanWriteChildrenWeb(BaseCamelotFilter* pFilter) 05784 { 05785 return TRUE; 05786 } 05787 05788 // See header for CanWriteChildrenWeb. The same information applies 05789 BOOL Node::CanWriteChildrenNative(BaseCamelotFilter* pFilter) 05790 { 05791 return TRUE; 05792 } 05793 05794 /******************************************************************************************** 05795 05796 > virtual BOOL Node::WriteBeginChildRecordsWeb(BaseCamelotFilter* pFilter) 05797 05798 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 05799 Created: 1/8/96 05800 Inputs: pFilter = ptr to filter to write to 05801 Returns: TRUE if ok, FALSE otherwise 05802 Purpose: Begin to write out you child records, in the web format 05803 05804 The base class will write out a TAG_DOWN record, but only if it has a child ptr 05805 05806 SeeAlso: WritePostChildrenWeb(), WritePreChildrenWeb() 05807 05808 ********************************************************************************************/ 05809 05810 BOOL Node::WriteBeginChildRecordsWeb(BaseCamelotFilter* pFilter) 05811 { 05812 Node* pChild = FindFirstChild(); 05813 if (pChild != NULL) 05814 { 05815 // The node is considered to have children ONLY if at least one child is not a hidden node. 05816 if (!pChild->IsNodeHidden() || (pChild->FindNextNonHidden() != NULL)) 05817 return pFilter->WriteZeroSizedRecord(TAG_DOWN); 05818 } 05819 05820 return TRUE; 05821 } 05822 05823 /******************************************************************************************** 05824 05825 > virtual BOOL Node::WriteBeginChildRecordsNative(BaseCamelotFilter* pFilter) 05826 05827 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 05828 Created: 1/8/96 05829 Inputs: pFilter = ptr to filter to write to 05830 Returns: TRUE if ok, FALSE otherwise 05831 Purpose: Begin to write out you child records, in the native format 05832 05833 The base class will write out a TAG_DOWN record, but only if it has a child ptr 05834 05835 SeeAlso: WritePostChildrenWeb(), WritePreChildrenWeb() 05836 05837 ********************************************************************************************/ 05838 05839 BOOL Node::WriteBeginChildRecordsNative(BaseCamelotFilter* pFilter) 05840 { 05841 Node* pChild = FindFirstChild(); 05842 if (pChild != NULL) 05843 { 05844 // The node is considered to have children ONLY if at least one child is not a hidden node. 05845 if (!pChild->IsNodeHidden() || (pChild->FindNextNonHidden() != NULL)) 05846 return pFilter->WriteZeroSizedRecord(TAG_DOWN); 05847 } 05848 05849 return TRUE; 05850 } 05851 05852 /******************************************************************************************** 05853 05854 > virtual BOOL Node::WriteEndChildRecordsWeb(BaseCamelotFilter* pFilter) 05855 05856 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 05857 Created: 1/8/96 05858 Inputs: pFilter = ptr to filter to write to 05859 Returns: TRUE if ok, FALSE otherwise 05860 Purpose: Finished writing out you child records, in the web format 05861 05862 The base class will write out a TAG_UP record, but only if it has a child ptr 05863 05864 SeeAlso: WritePostChildrenWeb(), WritePreChildrenWeb() 05865 05866 ********************************************************************************************/ 05867 05868 BOOL Node::WriteEndChildRecordsWeb(BaseCamelotFilter* pFilter) 05869 { 05870 Node* pChild = FindFirstChild(); 05871 if (pChild != NULL) 05872 { 05873 // The node is considered to have children ONLY if at least one child is not a hidden node. 05874 if (!pChild->IsNodeHidden() || (pChild->FindNextNonHidden() != NULL)) 05875 return pFilter->WriteZeroSizedRecord(TAG_UP); 05876 } 05877 05878 return TRUE; 05879 } 05880 05881 /******************************************************************************************** 05882 05883 > virtual BOOL Node::WriteEndChildRecordsNative(BaseCamelotFilter* pFilter) 05884 05885 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 05886 Created: 1/8/96 05887 Inputs: pFilter = ptr to filter to write to 05888 Returns: TRUE if ok, FALSE otherwise 05889 Purpose: Finished writing out you child records, in the native format 05890 05891 The base class will write out a TAG_UP record, but only if it has a child ptr 05892 05893 SeeAlso: WritePostChildrenWeb(), WritePreChildrenWeb() 05894 05895 ********************************************************************************************/ 05896 05897 BOOL Node::WriteEndChildRecordsNative(BaseCamelotFilter* pFilter) 05898 { 05899 Node* pChild = FindFirstChild(); 05900 if (pChild != NULL) 05901 { 05902 // The node is considered to have children ONLY if at least one child is not a hidden node. 05903 if (!pChild->IsNodeHidden() || (pChild->FindNextNonHidden() != NULL)) 05904 return pFilter->WriteZeroSizedRecord(TAG_UP); 05905 } 05906 05907 return TRUE; 05908 } 05909 05910 /******************************************************************************************** 05911 05912 > virtual BOOL Node::ReadPostChildrenWeb(BaseCamelotFilter* pFilter) 05913 05914 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 05915 Created: 19/7/96 05916 Inputs: pFilter = ptr to filter to write to 05917 Returns: TRUE if ok, FALSE otherwise 05918 Purpose: This function is called during the importing of the file. 05919 05920 A node gets called via this function after all its children have been imported. 05921 This allows complex nodes (such as moulds) to do some post-import work, which can 05922 only be done after all its children have been read in and created. 05923 05924 SeeAlso: CanWriteChildrenWeb(), WritePreChildrenWeb() 05925 05926 ********************************************************************************************/ 05927 05928 BOOL Node::ReadPostChildrenWeb(BaseCamelotFilter* pFilter) 05929 { 05930 #ifdef RALPH 05931 // We don't want to be rendering at the same time as doing this, because we get 05932 // blobby text problems - fun, but bad ! 05933 RalphCriticalSection RalphCS; 05934 #endif 05935 05936 return PostImport(); 05937 05938 //return TRUE; 05939 } 05940 05941 // See header for ReadPostChildrenWeb(). The same information applies 05942 BOOL Node::ReadPostChildrenNative(BaseCamelotFilter* pFilter) 05943 { 05944 #ifdef RALPH 05945 // We don't want to be rendering at the same time as doing this, because we get 05946 // blobby text problems - fun, but bad ! 05947 RalphCriticalSection RalphCS; 05948 #endif 05949 return PostImport(); 05950 05951 //return TRUE; 05952 } 05953 05954 05955 /******************************************************************************************** 05956 05957 > virtual BOOL Node::AreYouSafeToRender() 05958 05959 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 05960 Created: 17/9/96 05961 Inputs: - 05962 Returns: TRUE means yes, FALSE means no 05963 Purpose: This function is used by the progressive rendering system & the new file format 05964 to determine whether the node is renderable or not 05965 05966 The base class assumes that the node IS safe to render, as these are the most common 05967 05968 05969 SeeAlso: CanWriteChildrenWeb(), WritePreChildrenWeb() 05970 05971 ********************************************************************************************/ 05972 05973 BOOL Node::AreYouSafeToRender() 05974 { 05975 return TRUE; 05976 } 05977 05978 /******************************************************************************************** 05979 05980 > virtual void Node::CountChildNodes(UINT32* pChildCount, UINT32* pChildAttrCount); 05981 05982 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 05983 Created: 14/8/96 05984 Inputs: pChildCount = place to put the number of child nodes (can be NULL) 05985 pChildAttrCount = place to put the number of child attribute nodes (can be NULL) 05986 Returns: - 05987 Purpose: This scans the child sibling list of this node, counting the number of nodes 05988 it finds and the number of attributes 05989 05990 If does **not** do any extra tree traversal - only immediate children of this 05991 node are counted 05992 05993 NOTE: Hidden nodes are not counted 05994 05995 SeeAlso: - 05996 05997 ********************************************************************************************/ 05998 05999 void Node::CountChildNodes(UINT32* pChildCount, UINT32* pChildAttrCount) 06000 { 06001 UINT32 ChildCount = 0; 06002 UINT32 ChildAttrCount = 0; 06003 06004 Node* pNode = FindFirstChild(); 06005 while (pNode != NULL) 06006 { 06007 if (!pNode->IsNodeHidden()) 06008 { 06009 ChildCount++; 06010 if (pNode->IsAnAttribute()) 06011 ChildAttrCount++; 06012 } 06013 pNode = pNode->FindNext(); 06014 } 06015 06016 if (pChildCount != NULL) 06017 *pChildCount = ChildCount; 06018 06019 if (pChildAttrCount != NULL) 06020 *pChildAttrCount = ChildAttrCount; 06021 } 06022 06023 /******************************************************************************************** 06024 06025 > virtual BOOL Node::IsNodeInSubtree(Node* pChildNode) 06026 06027 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 06028 Created: 05/07/2000 06029 Inputs: pChildNode the node to test. 06030 06031 Returns: TRUE if the given node lies in the subtree beneath this node. 06032 FALSE otherwise or if the given node is NULL or if it *is* this node. 06033 06034 Purpose: Checks the parents of the given node, to see whether it lies within this 06035 node's subtree. 06036 06037 ********************************************************************************************/ 06038 BOOL Node::IsNodeInSubtree(Node* pChildNode) 06039 { 06040 // we return FALSE if pChildNode is this node, or is NULL. 06041 if (pChildNode == this || pChildNode == NULL) 06042 return FALSE; 06043 06044 // check each of pNode's parents. 06045 while (pChildNode != NULL && pChildNode != this) 06046 pChildNode = pChildNode->FindParent(); 06047 06048 // we only return TRUE if we hit this Node, travelling up from pChildNode. 06049 return (pChildNode == this); 06050 } 06051 06052 /******************************************************************************************** 06053 06054 > virtual BOOL Node::HasThisChildAttr(NodeAttribute* pAttr) 06055 06056 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 06057 Created: 14/8/96 06058 Inputs: pAttr = ptr to an attribute 06059 Returns: TRUE if it does contain an exact replica, FALSE otherwise 06060 Purpose: This scans the child sibling list of this node, to see if it contains an attribute 06061 that's exactly the same as the given one. 06062 06063 If does **not** do any extra tree traversal - only immediate child attrs of this 06064 node compared 06065 06066 SeeAlso: - 06067 06068 ********************************************************************************************/ 06069 06070 BOOL Node::HasThisChildAttr(NodeAttribute* pAttr) 06071 { 06072 ERROR2IF(pAttr == NULL,FALSE,"NULL attr ptr"); 06073 06074 Node* pNode = FindFirstChild(); 06075 while (pNode != NULL) 06076 { 06077 if (pNode->IsAnAttribute()) 06078 { 06079 NodeAttribute* pOtherAttr = (NodeAttribute*)pNode; 06080 06081 if (pAttr->GetAttributeType() == pOtherAttr->GetAttributeType()) 06082 { 06083 if (*pAttr == *pOtherAttr) 06084 return TRUE; 06085 } 06086 } 06087 06088 pNode = pNode->FindNext(); 06089 } 06090 06091 return FALSE; 06092 } 06093 06094 /******************************************************************************************** 06095 06096 > virtual BOOL Node::AreChildAttrsIdentical(Node* pOtherNode) 06097 06098 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 06099 Created: 14/8/96 06100 Inputs: pOtherNode = ptr to the node to compare against 06101 Returns: TRUE if attrs are identical, FALSE otherwise 06102 Purpose: This scans the child sibling list of this node, to see of it contains the same attributes 06103 as pOtherNode 06104 06105 If does **not** do any extra tree traversal - only immediate child attrs of this 06106 node and the other node compared 06107 06108 SeeAlso: - 06109 06110 ********************************************************************************************/ 06111 06112 BOOL Node::AreChildAttrsIdentical(Node* pOtherNode) 06113 { 06114 ERROR2IF(pOtherNode == NULL,FALSE,"NULL node ptr"); 06115 06116 // Count the number of child attrs in this and the other nodes. 06117 UINT32 ChildAttrCount,OtherChildAttrCount; 06118 CountChildNodes(NULL,&ChildAttrCount); 06119 pOtherNode->CountChildNodes(NULL,&OtherChildAttrCount); 06120 06121 // If they don't have the same number of child attrs, then they can't have an identical set 06122 if (ChildAttrCount != OtherChildAttrCount) 06123 return FALSE; 06124 06125 Node* pNode = FindFirstChild(); 06126 while (pNode != NULL) 06127 { 06128 if (pNode->IsAnAttribute()) 06129 { 06130 if (!pOtherNode->HasThisChildAttr((NodeAttribute*)pNode)) 06131 return FALSE; 06132 } 06133 06134 pNode = pNode->FindNext(); 06135 } 06136 06137 return TRUE; 06138 } 06139 06140 /******************************************************************************************** 06141 06142 > virtual BOOL Node::CopyChildAttrs(Node* pDestNode) 06143 06144 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 06145 Created: 14/8/96 06146 Inputs: pDestNode = ptr to node to copy attrs to 06147 Returns: TRUE if ok, FALSE otherwise 06148 Purpose: This scans the child sibling list of this node, and copies all the child attributes, 06149 applying the copy as a child to the destination node. 06150 06151 SeeAlso: - 06152 06153 ********************************************************************************************/ 06154 06155 BOOL Node::CopyChildAttrs(Node* pDestNode) 06156 { 06157 ERROR2IF(pDestNode == NULL,FALSE,"NULL dest node ptr"); 06158 06159 Node* pLastInsert = NULL; 06160 Node* pSrcNode = FindFirstChild(); 06161 while (pSrcNode != NULL) 06162 { 06163 if (pSrcNode->IsAnAttribute()) 06164 { 06165 Node* pCopy = pSrcNode->SimpleCopy(); 06166 if (pCopy == NULL) 06167 return(FALSE); 06168 06169 if (pLastInsert == NULL) 06170 { 06171 pCopy->AttachNode(pDestNode,FIRSTCHILD); 06172 } 06173 else 06174 { 06175 pCopy->AttachNode(pLastInsert,NEXT); 06176 } 06177 pLastInsert = pCopy; 06178 } 06179 06180 pSrcNode = pSrcNode->FindNext(); 06181 } 06182 06183 return TRUE; 06184 } 06185 06186 06187 06188 /******************************************************************************************** 06189 06190 > virtual BOOL Node::IsDifferent(Node *pOther) 06191 06192 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 06193 Created: 28/2/97 06194 06195 Inputs: pOther - The node to compare this one to 06196 06197 Returns: TRUE if this is considered different from pOther, 06198 FALSE if they are the same 06199 06200 Purpose: Determine if 2 nodes are considered different. 06201 06202 Notes: **** IMPORTANT - May not function well enough for your needs! **** 06203 06204 This was written to allow the StrokeComponent class to merge stroke 06205 definitions which share identical clipart subtrees. Stroke subtrees 06206 are special in that they have had Make Shapes applied to them, and 06207 so only contain paths. Hence, I have only defined functions in 06208 Node, NodeRenderableBounded, and NodePath - most objects in the tree 06209 thus use base class functionality (are they of the same class, and 06210 do they have identical bounding boxes). This suffices for my needs, 06211 but you may need to implement this function for a lot more node 06212 types before it's of use to you. 06213 06214 ********************************************************************************************/ 06215 06216 BOOL Node::IsDifferent(Node *pOther) 06217 { 06218 // The base class merely checks that the 2 objects are of the same class 06219 if (GetRuntimeClass() != pOther->GetRuntimeClass()) 06220 return(TRUE); 06221 06222 // If they're the same type, then as far as we know, they're the same. 06223 // Derived classes will override this function to do a better check. 06224 return(FALSE); 06225 } 06226 06227 06228 /******************************************************************************************** 06229 06230 > virtual BOOL Node::SetParentLayerAsEdited() 06231 06232 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 06233 Created: 31/7/97 06234 Returns: True if worked ok, False otherwise 06235 Purpose: Mark parent layer as edited. If an ink object as something done to it which 06236 changes its appearance then we need to mark the parent layer as edited. 06237 In this baseclass version do nothing. 06238 06239 ********************************************************************************************/ 06240 06241 BOOL Node::SetParentLayerAsEdited() 06242 { 06243 return TRUE; 06244 } 06245 06246 06247 06248 06250 // Attribute scanning for the Attribute gallery. 06251 06252 06253 /******************************************************************************************** 06254 > NodeAttribute* Node::FindFirstAttr(TypeFunc pfnTest) const 06255 06256 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 06257 Created: 27/1/95 06258 Inputs: pfnTest --- pointer to a member-function of Node:- 06259 typedef BOOL (Node::*TypeFunc)() const; 06260 that returns TRUE for the attribute being 06261 searched for and FALSE otherwise 06262 Returns: The first attribute of the given type that applies to pInk, or null 06263 if there isn't one. Call NodeAttribute::FindNextAttr on the returned 06264 attribute to find the next attribute in scope and so on. 06265 SeeAlso: NodeAttribute::FindNextAttrClass 06266 ********************************************************************************************/ 06267 06268 NodeAttribute* Node::FindFirstAttr(TypeFunc pfnTest) const 06269 { 06270 // Begin searching from the last child of pInk, or if there isn't one, from pInk itself. 06271 const Node* pNode = FindLastChild(); 06272 if (pNode == 0) pNode = this; 06273 06274 // Search for the class in the previous sibling nodes, then the parent's siblings, 06275 // then the parent siblings of the parent of ... etc. 06276 while (!(pNode->*pfnTest)()) 06277 { 06278 // Work out the next node in the search order. 06279 if (pNode->FindPrevious() != 0) 06280 { 06281 // The next node is the previous sibling. 06282 pNode = pNode->FindPrevious(); 06283 } 06284 else 06285 { 06286 // The next node is the parent, if there is one. 06287 pNode = pNode->FindParent(); 06288 if (pNode == 0) break; 06289 } 06290 } 06291 06292 // Return the attribute, or null if none was found. 06293 return (NodeAttribute*) pNode; 06294 } 06295 06296 06297 06298 /******************************************************************************************** 06299 06300 > virtual DocRect Node::ValidateExtend(const ExtendParams& ExtParams) 06301 06302 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 06303 Created: 26/11/1999 06304 Inputs: ExtParams description parameters for the extension. 06305 Outputs: 06306 Returns: TRUE if extending this Node would be a valid operation, ie by passing 06307 appropriate inverse extend parameters, the Node could be un-extended 06308 back to its original state. 06309 FALSE if the operation would be irreversible. 06310 Purpose: Tests the reversibility of an Extend operation applied to this node. 06311 06312 Note that where appropriate, this function asks the Node's children if they 06313 may validly extend, only returning TRUE if the extension is completely ok 06314 with everyone. 06315 06316 Also note that if a node is of a non-extending type, it should normally 06317 consider itself a 'valid extender', as doing nothing is completely reversible 06318 (it should of course still check its children). 06319 Errors: 06320 See also: Node::IsTypeExtendible(), Node::Extend(). 06321 06322 ********************************************************************************************/ 06323 DocRect Node::ValidateExtend(const ExtendParams& ExtParams) 06324 { 06325 DocRect drMinExtend(INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX), drThisMinExtend; 06326 for ( Node* pChildNode = FindFirstChild(); 06327 pChildNode != NULL; 06328 pChildNode = pChildNode->FindNext() ) 06329 { 06330 drThisMinExtend = pChildNode->ValidateExtend(ExtParams); 06331 if (drMinExtend.lo.x > drThisMinExtend.lo.x) drMinExtend.lo.x = drThisMinExtend.lo.x; 06332 if (drMinExtend.lo.y > drThisMinExtend.lo.y) drMinExtend.lo.y = drThisMinExtend.lo.y; 06333 if (drMinExtend.hi.x > drThisMinExtend.hi.x) drMinExtend.hi.x = drThisMinExtend.hi.x; 06334 if (drMinExtend.hi.y > drThisMinExtend.hi.y) drMinExtend.hi.y = drThisMinExtend.hi.y; 06335 } 06336 return drMinExtend; 06337 } 06338 06339 06340 06341 /******************************************************************************************** 06342 06343 > virtual void Node::Extend(const ExtendParams& ExtParams) 06344 06345 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 06346 Created: 26/11/1999 06347 Inputs: ExtParams description parameters for the extension. 06348 Outputs: This node and some of its children may have their dimensions altered. 06349 Returns: 06350 Purpose: Perform an Extend operation on this Node, and its children if appropriate. 06351 Default implementation just calls Extend() on its children. 06352 Errors: 06353 See also: 06354 06355 ********************************************************************************************/ 06356 void Node::Extend(const ExtendParams& ExtParams) 06357 { 06358 for ( Node* pChildNode = FindFirstChild(); 06359 pChildNode != NULL; 06360 pChildNode = pChildNode->FindNext() ) 06361 { 06362 pChildNode->Extend(ExtParams); 06363 } 06364 } 06365 06366 06367 06369 // AttrTypeSet methods 06370 06371 06372 /******************************************************************************************** 06373 06374 > BOOL AttrTypeSet::AddToSet(CCRuntimeClass* AttrType) 06375 06376 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 06377 Created: 12/5/95 06378 Returns: FALSE if we run out of memory 06379 Purpose: Adds AttrType to the set 06380 SeeAlso: AttrTypeSet::InSet 06381 SeeAlso: AttrTypeSet::CopySet 06382 06383 06384 ********************************************************************************************/ 06385 06386 BOOL AttrTypeSet::AddToSet(CCRuntimeClass* AttrType) 06387 { 06388 ERROR3IF(AttrType == NULL, "AddToSet: AttrType is NULL"); 06389 // Determine if the AttrType is already in the set 06390 AttrTypeItem* pAttrType = (AttrTypeItem*) GetHead(); 06391 while (pAttrType != NULL) 06392 { 06393 if (pAttrType->AttributeType == AttrType) 06394 { 06395 return TRUE; // Already in set so return 06396 } 06397 pAttrType = (AttrTypeItem*) GetNext(pAttrType); 06398 } 06399 06400 // The attribute type is not in the set so let's add it 06401 pAttrType = new AttrTypeItem; 06402 if (!pAttrType) 06403 return FALSE; // out of memory (error has been set) 06404 06405 pAttrType->AttributeType = AttrType; 06406 06407 AddHead(pAttrType); // Add attribute to the head of the list 06408 06409 return TRUE; 06410 } 06411 06412 /******************************************************************************************** 06413 06414 > BOOL AttrTypeSet::AddToSet(List& Attributes) 06415 06416 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 06417 Created: 12/5/95 06418 Inputs: A list of attributes (each item must be a NodeAttributePtrItem) 06419 Returns: FALSE if we run out of memory. 06420 Purpose: Adds the Types of all attributes in the Attributes list 06421 SeeAlso: AttrTypeSet::InSet 06422 SeeAlso: AttrTypeSet::CopySet 06423 06424 06425 ********************************************************************************************/ 06426 06427 BOOL AttrTypeSet::AddToSet(List& Attributes) 06428 { 06429 NodeAttributePtrItem* pAttrItem = (NodeAttributePtrItem*)(Attributes.GetHead()); 06430 NodeAttribute* pAttr; 06431 while (pAttrItem) 06432 { 06433 pAttr = pAttrItem->NodeAttribPtr; 06434 ERROR3IF(!pAttr, "Should be an attribute"); 06435 if (!AddToSet(pAttr->GetAttributeType())) 06436 { 06437 return FALSE; 06438 } 06439 pAttrItem = (NodeAttributePtrItem*)(Attributes.GetNext(pAttrItem)); 06440 } 06441 return TRUE; 06442 } 06443 06444 /******************************************************************************************** 06445 06446 > BOOL AttrTypeSet::CopySet() 06447 06448 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 06449 Created: 15/5/95 06450 Inputs: - 06451 Outputs: - 06452 Returns: A copy of the set, or NULL if we run out of memory 06453 Purpose: Makes a copy of the attribute type set 06454 Errors: - 06455 SeeAlso: AttrTypeSet::AddToSet 06456 SeeAlso: AttrTypeSet::InSet 06457 06458 ********************************************************************************************/ 06459 06460 AttrTypeSet* AttrTypeSet::CopySet() 06461 { 06462 AttrTypeSet* pSetCopy; 06463 pSetCopy = new AttrTypeSet; 06464 if (!pSetCopy) 06465 return NULL; // Out of memory 06466 06467 // Copy each item in turn 06468 AttrTypeItem* pItemCopy; 06469 AttrTypeItem* pCurrent = (AttrTypeItem*)GetHead(); 06470 while (pCurrent) 06471 { 06472 pItemCopy = new AttrTypeItem; 06473 if (!pItemCopy) 06474 { 06475 // Tidyup 06476 pSetCopy->DeleteAll(); 06477 delete pSetCopy; 06478 return NULL; 06479 } 06480 pItemCopy->AttributeType = pCurrent->AttributeType; 06481 pSetCopy->AddTail(pItemCopy); 06482 pCurrent = (AttrTypeItem*)GetNext(pCurrent); 06483 } 06484 return pSetCopy; 06485 } 06486 06487 06488 /******************************************************************************************** 06489 > BOOL AttrTypeSet::InSet(CCRuntimeClass* AttrType) 06490 06491 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 06492 Created: 15/5/95 06493 Inputs: AttrType: The type of an attribute 06494 Outputs: - 06495 Returns: TRUE if AttrType is in the set 06496 Purpose: To determine if AttrType is in the set 06497 Errors: - 06498 SeeAlso: AttrTypeSet::CopySet 06499 SeeAlso: AttrTypeSet::AddToSet 06500 ********************************************************************************************/ 06501 06502 BOOL AttrTypeSet::InSet(CCRuntimeClass* AttrType) 06503 { 06504 AttrTypeItem* pCurrent = (AttrTypeItem*)GetHead(); 06505 while (pCurrent) 06506 { 06507 if (pCurrent->AttributeType == AttrType) 06508 return TRUE; 06509 pCurrent = (AttrTypeItem*)GetNext(pCurrent); 06510 } 06511 return FALSE; 06512 } 06513