node.cpp

Go to the documentation of this file.
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 

Generated on Sat Nov 10 03:45:53 2007 for Camelot by  doxygen 1.4.4