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 =