range.cpp

Go to the documentation of this file.
00001 // $Id: range.cpp 1744 2006-09-06 15:58:54Z luke $
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 /* Implementation of class Range */     
00100     
00101 /*
00102 */ 
00103  
00104 #include "camtypes.h" 
00105 
00106 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 //#include "docmsgs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "ensure.h"  - in camtypes.h [AUTOMATICALLY REMOVED]
00111 //#include "node.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 //#include "range.h"    - in camtypes.h [AUTOMATICALLY REMOVED]
00113 //#include "rndrgn.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 //#include "simon.h"
00115 //#include "ink.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00116 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00117 //#include "dlgbar.h"
00118 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00119 #include "sprdmsg.h"
00120 #include "layer.h"
00121 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00122 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00123 //#include "peter.h"
00124 #include "nodetext.h"
00125 //#include "undoop.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00126 #include "nodetxtl.h"
00127 #include "nodetxts.h"
00128 #include "nodecont.h"
00129 #include "nodeshad.h"
00130 #include "objreg.h"
00131 #include "attrmap.h"
00132 #include "toolmsg.h"
00133 #include "comattrmsg.h"
00134 #include "qualattr.h"
00135 #include "ngcore.h"     // NameGallery, for stretching functionality
00136 #include "objchge.h"    // for ues of ObjChangeParam
00137 //#include "scrvw.h"
00138 //#include "will2.h"
00139 //#include "justin2.h"
00140 //#include "resimmap.h" //For _R(IDS_SINGLELAYER_INSIDE)
00141 //#include "bmpsdlgr.h" // _R(IDS_ON_FRAME_OUTSIDE_NOREF)
00142 #include "effects_stack.h"
00143 //#include "bars.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00144 #include "fillattr2.h"
00145 
00146 DECLARE_SOURCE( "$Revision: 1744 $" );    
00147 
00148 CC_IMPLEMENT_DYNAMIC(Range, CCObject)   
00149 CC_IMPLEMENT_DYNAMIC(NodeListItem, ListItem)
00150 
00151 CC_IMPLEMENT_DYNAMIC(SelRange, Range)   
00152 CC_IMPLEMENT_DYNAMIC(SelChangingMsg, Msg)
00153 
00154 CC_IMPLEMENT_DYNAMIC(ListRange, Range)   
00155 
00156 CC_IMPLEMENT_DYNAMIC(SelRangeMessageHandler, MessageHandler)
00157 
00158 CC_IMPLEMENT_DYNAMIC(CommonAttrsChangedMsg, Msg);
00159 
00160 
00161 // This line MUST occur after all CC_IMPLEMENT lines
00162 // Declare smart memory handling in Debug builds
00163 #define new CAM_DEBUG_NEW
00164 
00165 
00166 // Enable Fast XOR drag blob rendering - see below
00167 // Set this value to 0 (FALSE) to disable, or 1 (TRUE) to enable fast XORing
00168 #define ENABLE_FAST_XOR 1
00169 
00170 
00171 // Define _DEBUG_LISTCHECKS to enable list checking in ListRange
00172 #ifdef _DEBUG
00173 //  #define _DEBUG_LISTCHECKS
00174 #endif
00175 
00176 
00177 /*****************************************************************************************
00178 
00179 >   RangeControl::RangeControl( BOOL Sel                = FALSE,
00180                                 BOOL Unsel              = FALSE,
00181                                 BOOL Cross              = FALSE,
00182                                 BOOL IgLock             = FALSE,
00183                                 BOOL Rendr              = FALSE,
00184                                 BOOL IgInvisible        = FALSE,
00185                                 BOOL SibsOnly           = FALSE,
00186                                 BOOL Promot             = FALSE )
00187     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00188     Created:    26/01/95
00189 
00190     Inputs:     -
00191     Outputs:    -
00192     Returns:    -
00193     Purpose:    RangeControl constructor. Sets the flags to safe defaults!
00194                 See RangeControl definition for details of flags.
00195 
00196     Errors:     -
00197 
00198 ******************************************************************************************/
00199 
00200 RangeControl::RangeControl( BOOL Sel, BOOL Unsel, BOOL Cross,
00201                             BOOL IgLock, BOOL Rendr, BOOL IgInvisible, BOOL SibsOnly,
00202                             BOOL Promot )
00203 {
00204     Selected = Sel;
00205     Unselected = Unsel;
00206     CrossLayer = Cross;
00207     IgnoreLockedLayers = IgLock;
00208     IgnoreNoneRenderable = Rendr;
00209     IgnoreInvisibleLayers = IgInvisible;
00210     SiblingsOnly = SibsOnly;
00211     PromoteToParent = Promot;
00212 }
00213 
00214 
00215 
00216 
00217 /********************************************************************************************
00218 
00219 >   Range::Range(Node* First, Node* Last, RangeControl RangeControlFlgs)
00220 
00221     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00222     Created:    28/6/93
00223     Inputs:     RangeControlFlags: Specifies the selected status of the nodes to be included
00224                                    in the range.
00225                                    
00226                                    If RangeControlFlgs.Selected = TRUE
00227                                         All nodes with a selected status are included as 
00228                                         members of the range. 
00229                                         
00230                                    If RangeControlFlgs.Unselected = TRUE
00231                                         All nodes with an unselected status are included as
00232                                         members in the range. 
00233                                         
00234                                    If both these flags are TRUE then all nodes from First to Last
00235                                    are included in the range. 
00236 
00237                                    If RangeControlFlgs.CrossLayer = TRUE
00238                                         The range may cross several layers; when the end of a layer
00239                                         is reached, the search will continue at the start of the
00240                                         following layer.
00241 
00242                                    If RangeControlFlgs.IgnoreLockedLayers = TRUE
00243                                         locked layers are included in the search.
00244                                         Defaults to FALSE so locked layers ignored.
00245                                    
00246                                    If RangeControlFlgs.IgnoreNoneRenderable = TRUE
00247                                         non-renderable nodes are included in the search.
00248                                         Defaults to FALSE so non-redenderable nodes ignored.
00249                                    
00250                                    If RangeControlFlgs.IgnoreInvisibleLayers = TRUE
00251                                         Invisable layers are included in the search.
00252                                         Defaults to FALSE so invisible layers ignored.
00253                                    
00254                 First:  The node from which to commence searching for members of a range.  
00255                 Last:   The final node to search (must be a right sibling of First, or NULL). 
00256                         NULL specifies that all nodes from First to the end of First's sibling 
00257                         list (or end of the tree, if CrossLayer is TRUE) are to be searched for
00258                         members of the range. 
00259                             
00260                                     
00261     Outputs:    -
00262     Returns:    -
00263     Purpose:    The purpose of this function is to create a node range. 
00264     Errors:     -
00265 
00266 ********************************************************************************************/
00267   
00268 Range::Range(Node* First, Node* Last, RangeControl RangeControlFlgs)
00269 {
00270     // When the First node in a range is NULL the range is assumed to lie directly under
00271     // the surface of layers...
00272 /*
00273     if (First!=NULL)
00274     {
00275         ERROR3IF( RangeControlFlgs.Unselected
00276                     && !First->FindParent()->IsLayer()
00277                     && First != Last,
00278                     "Attempt to create an illegal range!"
00279                  );
00280     }
00281 */
00282 
00283     RangeControlFlags = RangeControlFlgs; 
00284     FirstNode = First; 
00285     LastNode = Last;
00286     pCommonAttribCache = NULL;             // The common attribute cache only comes into
00287                                            // existance if the FindCommonAttribute functions
00288                                            // are called on the range.
00289  
00290     // Initialise the XOR rendering stuff
00291     NodeToRender = NULL;
00292     ResetXOROutlineRenderer(TRUE);
00293 } 
00294 
00295 
00296 
00297 
00298 /********************************************************************************************
00299 
00300 >   Range::Range()
00301 
00302 
00303     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00304     Created:    2/3/94
00305     Inputs:     -
00306     Outputs:    -
00307     Returns:    -
00308     Purpose:    Creates an uninitialised range 
00309     Errors:     -
00310     SeeAlso:    -
00311 
00312 ********************************************************************************************/
00313 
00314 Range::Range()
00315 {
00316     FirstNode = LastNode = NULL;
00317     pCommonAttribCache = NULL;             // The common attribute cache only comes into
00318                                            // existance if the FindCommonAttribute functions
00319 }
00320 
00321 
00322 
00323 
00324 Range::~Range()
00325 {
00326     // Destroy the CommonAttribSet if one exists
00327     if (pCommonAttribCache)
00328     {
00329         delete pCommonAttribCache; 
00330     }
00331 }
00332 
00333 
00334 
00335 
00336 /********************************************************************************************
00337 
00338 >   Range::Range(const Range& Range);   
00339 
00340     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00341     Created:    2/3/94
00342     Inputs:     Rng:    The Range to copy 
00343     Outputs:    -
00344     Returns:    -
00345     Purpose:    Range copy constructor 
00346     Errors:     -
00347     SeeAlso:    -
00348 
00349 ********************************************************************************************/
00350 
00351 Range::Range(Range& Rng)
00352 {
00353     // If the range is a sel range we must be sure that the range has been cached 
00354     Rng.FreshenCache();
00355 
00356     RangeControlFlags = Rng.RangeControlFlags;  
00357     FirstNode = Rng.FirstNode; 
00358     LastNode = Rng.LastNode;
00359     pCommonAttribCache = NULL;      
00360 }      
00361 
00362 
00363 
00364 
00365 /********************************************************************************************
00366 
00367 >   Range& Range::operator=(Range& Range)              
00368 
00369     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00370     Created:    2/3/94
00371     Inputs:     Range: The range to copy 
00372     Outputs:    
00373     Returns:    The Range
00374     Purpose:    Range = operator
00375     Errors:     -
00376     SeeAlso:    -
00377 
00378 ********************************************************************************************/
00379 
00380 Range& Range::operator=(Range& Rng)
00381 {
00382     // If the range is a sel range we must be sure that the range has been cached 
00383     Rng.FreshenCache(); 
00384 
00385     RangeControlFlags = Rng.RangeControlFlags;  
00386     FirstNode = Rng.FirstNode; 
00387     LastNode = Rng.LastNode; 
00388     pCommonAttribCache = NULL;      
00389     return *this;       
00390 }
00391 
00392 
00393 
00394 
00395 /********************************************************************************************
00396 
00397 >   void Range::SetRangeControl(RangeControl RangeControlFlgs)
00398 
00399     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00400     Created:    29/6/93 
00401     
00402     Inputs:     RangeControlFlags: Specifies the selected status of the nodes to be included
00403                                    in the range.
00404     Outputs:    -
00405     Returns:    -
00406     Purpose:    To set the range control for the range.  
00407     Errors:     -
00408     SeeAlso:    -
00409 
00410 ********************************************************************************************/
00411                             
00412 void Range::SetRangeControl(RangeControl RangeControlFlgs)
00413 {
00414     RangeControlFlags = RangeControlFlgs;
00415 }   
00416 
00417 
00418 
00419 
00420 /*********************************************************************************************
00421 
00422 >    Node* Range::FindFirst(BOOL AndChildren = FALSE)
00423 
00424      Author:    Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> (Changed by Phil, 30/11/94)
00425      Created:   25/6/93
00426      
00427      Returns:   If the range contains any members then
00428                     A pointer to the first node in the range is returned
00429                 Else
00430                     NULL is returned 
00431             
00432      Purpose:   The purpose of this function is to find the first node in a range. 
00433 
00434      SeeAlso:   Range::FindNext    
00435      
00436      Errors:    An assertion failure will occur if:
00437 
00438                 There are no more nodes to search and the last node to search was not found.
00439 
00440 **********************************************************************************************/
00441                                     
00442 Node* Range::FindFirst(BOOL AndChildren)
00443 {
00444     // Preconditions...
00445     ERROR2IF(this==NULL,NULL,"FindFirst called on NULL range");
00446 
00447     // Locals...
00448     Node* pNode = FirstNode;
00449 
00450 
00451 // **** !!!! BODGE - Traps bug in message broadcast from document.cpp to try to
00452 // keep the program stable.
00453     if (Document::GetSelectedSpread() != NULL)
00454     {
00455         if (!Document::SpreadBelongsToDoc(Document::GetSelected(),
00456                                             Document::GetSelectedSpread()))
00457         {
00458             TRACE( _T("SelRange: Selected Spread is NOT in the Selected Document!\n"));
00459             return(NULL);
00460         }
00461     }
00462 // **** !!!! BODGE
00463 
00464     // Implementation...
00465     // If First is NULL then the caller expects to get a range of nodes
00466     // in the child lists of layers. So find the first layer on the
00467     // current spread.
00468     if (pNode == NULL)
00469     {
00470         Spread* pSelectedSpread = Document::GetSelectedSpread();
00471         if (pSelectedSpread==NULL)
00472         {
00473             // The range does not have a FirstNode. Normally it would find one
00474             // automatically based on the SelectedSpread but there is no SelectedSpread
00475             // so we have no choice but to return an empty range to the caller...
00476             TRACEUSER( "Phil", _T("Warning! Range is NULL because there's no selected spread\n"));
00477             return NULL;
00478         }
00479         
00480         // Oh well, we will use the first layer instead
00481         pNode = pSelectedSpread->FindFirstLayer();
00482 
00483         // If there is no layer, then give up and return NULL
00484         if (pNode==NULL)
00485             return NULL;
00486     }
00487 
00488     // The first node might be a valid member of the range so test for that...
00489     // (Set the special FirstNode flag TRUE so that the logic treats this node is
00490     //  if it hasn't yet been met in the scan.)
00491     pNode = SmartFindNext(pNode, AndChildren, TRUE);
00492     return pNode;
00493 }                       
00494 
00495 
00496      
00497 
00498 /*********************************************************************************************
00499 
00500 >    Node* Range::FindNext(Node* Prev, BOOL AndChildren = FALSE)
00501      Author:    Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>  (Changed by Phil, 30/11/94)
00502      Created:   25/6/93
00503      Inputs:    Prev: The previous node in the range (usually returned from a 
00504                        Range::FindFirst, or a previous Range::FindNext call). 
00505      Outputs:    - 
00506      Returns:   If the range contains any more members then
00507                     A pointer to the next node in the range is returned
00508                 Else
00509                     NULL is returned 
00510      Purpose:   The purpose of this function is to find the next node in the range after Prev 
00511      SeeAlso:   Range::FindFirst    
00512      Errors:    An assertion failure will occur if:
00513                 There are no more nodes to search and the last node to search was not found.
00514 
00515 **********************************************************************************************/
00516 
00517 Node* Range::FindNext(Node* pPrevious, BOOL AndChildren)
00518 {
00519     // Preconditions
00520     // No need to check that "this" is NULL because that's already been done
00521     // in FindFirst.
00522     ERROR2IF(pPrevious == NULL, NULL, "NULL pointer passed to Range::FindNext");
00523 
00524     Node* pNode = SmartFindNext(pPrevious, AndChildren);
00525 
00526     // DMc
00527     // if the output is the same as the input, and promote to parent is set,
00528     // the this should never happen !
00529     if (pNode == pPrevious && RangeControlFlags.PromoteToParent)
00530     {
00531         return NULL;
00532     }
00533         
00534     return pNode;
00535 }
00536 
00537 
00538 
00539 /*********************************************************************************************
00540 
00541 >    Node* Range::FindPrev(Node* pNode, BOOL AndChildren = FALSE)
00542      Author:    Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00543      Created:   19/01/95
00544      Inputs:    pNode: The node which you want the previous one in the range to... 
00545      Outputs:    - 
00546      Returns:   If the range contains any members before the input node then
00547                     A pointer to the prev node in the range is returned
00548                 Else
00549                     NULL is returned (Note NULL returned if input node was not in the range)
00550      Purpose:   The purpose of this function is to find the previous node in the range before
00551                 the input node.
00552                 NOTE! THIS ROUTINE IS SLOW! It scans through the range in forwards order
00553                 until it meets the input node, then returns the previous node to that!!!
00554      SeeAlso:   Range::FindFirst; Range::FindNext    
00555      Errors:    -
00556 
00557 **********************************************************************************************/
00558 
00559 Node* Range::FindPrev(Node* pNode, BOOL AndChildren)
00560 {
00561     // Preconditions
00562     // No need to check that "this" is NULL because that's already been done
00563     // in FindFirst.
00564     ERROR2IF(pNode == NULL, NULL, "NULL pointer passed to Range::FindNext");
00565 
00566     Node* pPrev = NULL;
00567     Node* pCurrent = FindFirst(AndChildren);
00568     while (pCurrent)                                // While there's a node to check
00569     {
00570         if (pCurrent == pNode)                      // See if it's the one we're looking for
00571             return pPrev;                           // If it is return the previous node!
00572 
00573         pPrev = pCurrent;                           // Else, remember this node
00574         pCurrent = FindNext(pCurrent, AndChildren); // and find the next one in the range
00575     }
00576 
00577     return NULL;
00578 }
00579 
00580 
00581 
00582 /*********************************************************************************************
00583 
00584 >    Node* Range::FindLast()
00585 
00586      Author:    Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00587      Created:   25/6/93
00588      
00589      Returns:   If the range contains any members then
00590                     A pointer to the last node in the range is returned
00591                 Else
00592                     NULL is returned 
00593             
00594      Purpose:   The purpose of this function is to find the last node in a range. 
00595                 If the range was constructed with a NULL last node specifier then
00596                 the range is scanned until the last node is found. If a non NULL last node
00597                 was specified however the value of last is simply returned. It's existance
00598                 is not verified !. 
00599 
00600      SeeAlso:   Range::FindFirst
00601                 Range::FindNext    
00602      
00603      Errors:    An assertion failure will occur if:
00604 
00605                 There are no more nodes to search and the last node to search was not found.
00606 
00607 **********************************************************************************************/
00608 
00609 Node* Range::FindLast()
00610 {
00611     if (LastNode == NULL)
00612     {
00613         // We need to search for the last node in the range
00614         Node* Scout = FindFirst();
00615         Node* n = NULL; 
00616         while (Scout != NULL)
00617         {
00618             n = Scout;
00619             Scout = FindNext(Scout); // Get the next value in the range
00620         }
00621         return n; // If the range is empty NULL will be returned
00622     }
00623     else
00624     {
00625         // get the parent of the last node (if necessary to promote)
00626         Node * pContext = LastNode;
00627 
00628         if (pContext != NULL)
00629         {
00630             Node *pParent = pContext->FindParent();
00631         
00632             if (RangeControlFlags.PromoteToParent)
00633             {
00634                 while (pParent)
00635                 {
00636                     if (pParent->ShouldITransformWithChildren())
00637                     {
00638                         pContext = pParent;
00639                     }
00640                 
00641                     pParent = pParent->FindParent();
00642                 }
00643             }
00644         }
00645 
00646         return pContext; 
00647     }
00648 }
00649 
00650 
00651 
00652 
00653 /******************************************************************************************
00654 
00655 >   void Range::Update(BOOL TellWorld = FALSE)
00656 
00657      Author:    Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00658      Created:   03/10/94    (Was an inline function prior to this)
00659 
00660      Inputs:    BOOL TellWorld: When TRUE the function will inform the world that the 
00661                 selection has changed. Normally the selection is changed in an operation
00662                 and it is unneccesary to broadcast a SelChangingMsg at this point because
00663                 this will occur at the end of the operation. However If the selection is
00664                 changed outside of an operation then the flag should be set to TRUE.  
00665      Outputs:   -
00666      Returns:   -
00667 
00668      Purpose:   To inform the SelRange that the selection has changed
00669                 This invalidates the SelRange's selection-info cache so it will be
00670                 recached when info is next requested.
00671 
00672 ******************************************************************************************/
00673 
00674 void  Range::Update(BOOL TellWorld)
00675 {
00676     Camelot.FindSelection()->Update(TellWorld);     
00677 }   
00678 
00679 
00680 
00681 
00682 /*********************************************************************************************
00683 
00684 >    UINT32 Range::Count()
00685      Author:    Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00686      Created:   15/2/94
00687      Inputs:    -
00688      Outputs:   -
00689      Returns:   The number of nodes described by the Range.
00690      Purpose:   To count the number of nodes in a range. Currently this routine always scans
00691                 the range to count the number of nodes. In some future incarnation it may 
00692                 keep the count cached for quicker access.
00693      SeeAlso:   Range::FindFirst
00694      SeeAlso:   Node::FindNextInRange
00695      Errors:    -
00696 
00697 **********************************************************************************************/
00698 
00699 UINT32 Range::Count()
00700 {
00701     UINT32 count = 0;
00702     Node* pNode;
00703 
00704     pNode = FindFirst();
00705     while (pNode)
00706     {
00707         count++;
00708         pNode = FindNext(pNode);
00709     }
00710 
00711     return(count); 
00712 }
00713 
00714 
00715 /*********************************************************************************************
00716 
00717 >    BOOL Range::Contains(Node* pLookFor, BOOL bAndChildren)
00718 
00719      Author:    Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00720      Created:   3/5/95
00721      Inputs:    pLookFor = a pointer to a node to look for.
00722                 bAndChildren - Test for node being in subtree of member of range
00723      Outputs:   -
00724      Returns:   TRUE if the range contains this particular node
00725                 FALSE if the node is not held within this range
00726      Purpose:   To determin whether a particular node is actually in the range list.
00727      Errors:    -
00728 
00729 **********************************************************************************************/
00730 
00731 BOOL Range::Contains(Node* pLookFor, BOOL bAndChildren)
00732 {
00733     Node* pNode=FindFirst();
00734     while (pNode)
00735     {
00736         if (pNode==pLookFor)
00737             return TRUE;
00738 
00739         if (bAndChildren && pNode->IsNodeInSubtree(pLookFor))
00740             return TRUE;
00741 
00742         pNode=FindNext(pNode);
00743     }
00744     return FALSE;
00745 }
00746 
00747 
00748 
00749 /*********************************************************************************************
00750 
00751 >   BOOL Range::ContainsSelectInside()
00752     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00753     Created:    28/11/94
00754     Inputs:     -
00755     Outputs:    -
00756     Returns:    TRUE if Selection inside occurs in this range one or more times.
00757                 FALSE otherwise.
00758                 (Also returns FALSE when the Range is empty)
00759     Purpose:    To find out whether Select-inside is going on in this range. I.e. are any
00760                 members of this range children of nodes which would normally be selected.
00761     Errors:     -
00762 
00763 **********************************************************************************************/
00764 
00765 BOOL Range::ContainsSelectInside()
00766 {
00767 #if !defined(EXCLUDE_FROM_RALPH)
00768     // Preconditions
00769     ERROR2IF(this==NULL,FALSE,"ContainsSelectInside called on NULL pointer");
00770 
00771     // Implementation
00772     Node* pNodeInRange = FindFirst();
00773     Node* pParent;
00774     while (pNodeInRange)                                // While there's a node in the range
00775     {
00776         pParent = pNodeInRange->FindParent();           // Look at it's parent node
00777         
00778         // DMc - added promotehittestonchildrentome test to eliminate the 'inside' setting
00779         // for nodes should as shadows, contours, bevels etc
00780         while (pParent)
00781         {
00782             if (pParent->IsAnObject() && pParent->IsParentOfSelected() &&
00783                 pParent->PromoteHitTestOnChildrenToMe())    // If that's marked parent of sel
00784                 return TRUE;                                // Then this node is "inside" so return TRUE
00785 
00786             pParent = pParent->FindParent();
00787         }
00788 
00789         pNodeInRange = FindNext(pNodeInRange);          // Else, keep scanning members of range
00790     }
00791 #endif
00792     return FALSE;                                       // If no more in range, none were "inside"
00793 }
00794 
00795 
00796 
00797 
00798 /*********************************************************************************************
00799 
00800 >    Node* Range::SmartFindNext(Node* pContext, BOOL AndChildren = FALSE, BOOL FirstCall = FALSE) const
00801      Author:    Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00802      Created:   24/11/94
00803      Inputs:    pContext    Pointer to node in range to find next range member from
00804                             NOTE! pContext MUST be in the range!!!
00805                 AndChildren Flag specifying whether to return children of nodes in
00806                             the range.
00807                 Last        A pointer to the final node to search or NULL if all possible
00808                             members of the range are to be searched.   
00809                 Flags       Define the nodes which are to be members of the range 
00810                      Flags.Selected   : Selected nodes in the range
00811                      Flags.Unselected : Unselected nodes in the range
00812                      Flags.CrossLayer : Crossing into the next layer is allowed
00813                 If Flags.Selected and Flags.Unselected are both set, then all nodes from
00814                 this node to the Last node (or end of the layer, whichever comes first,
00815                 if CrossLayer is clear) are included in the range.
00816      Returns:   If the range contains any members following pContext then
00817                     A pointer to the next node in the range is returned
00818                 Else
00819                     A NULL is returned 
00820                 If no flags are set then there can be no members in the range
00821                 and NULL is returned.
00822      Purpose:   This function looks for the next node in a range following this node
00823                 and ending at the node specified by Last (or the last node in this layer
00824                 if the CrossLayer flag is clear).
00825                 Last must be a right sibling of this node, or NULL if all siblings are
00826                 to be searched.                 
00827      SeeAlso:   Node::FindFirstInRange; Node::FindNextInRange    
00828      Errors:    There are no more nodes to search and Last was not found
00829      Scope:     Protected
00830 
00831 **********************************************************************************************/
00832 /*  Technical Notes:
00833 
00834     This routine is just a souped up depth-first traversal of the whole tree with subtrees
00835     carefully pruned off to make the routine efficient.
00836 
00837 **********************************************************************************************/
00838 Node* Range::SmartFindNext(Node* pContext, BOOL AndChildren, BOOL FirstCall) const
00839 {
00840     // Preconditions
00841     ERROR2IF(this==NULL,NULL,"SmartFindNext called on NULL range");
00842     ERROR2IF(pContext==NULL,NULL,"SmartFindNext not given a context node to start from");
00843     ERROR2IF(RangeControlFlags.Unselected && AndChildren,NULL,"Range can't cope with unsel and children");
00844     ERROR2IF(pContext->IsPaper() && !pContext->IsLayer(),NULL,"SmartFindNext called above layers surface");
00845 
00846     // If the PromoteToParent flag is set then the context node might be a "promoted parent"
00847     if (RangeControlFlags.PromoteToParent && !FirstCall && !AndChildren)
00848     {
00849         // Using PromoteToParent, it is possible for the context node to jump *above* the
00850         // last node in the Range, causing us to iterate outside of it. We must therefore
00851         // check whether the context node is a parent of the last node, in which case
00852         // we have finished iteration.
00853         if (pContext->IsNodeInSubtree(LastNode))
00854             return NULL;
00855 
00856         // If the context node's parents wish to do so, then switch them in instead of it.
00857         // Go up the tree until this is no longer the case.
00858         Node* pParent = pContext->FindParent();
00859         while (pParent != NULL && pParent->ShouldITransformWithChildren())
00860         {
00861             pContext = pParent;
00862             pParent = pContext->FindParent();
00863         }
00864     }
00865 
00866     // Implementation
00867     // Loop, looking for suitable nodes and testing whether they're in the range or not.
00868     // Traverses the tree in basically depth-first order...
00869     do
00870     {
00871         // If context node from previous findnext was last node then there can be no more...
00872         if (!FirstCall && LastNode!=NULL && pContext==LastNode) return NULL;
00873 
00874         // Do the normal depth-first thing; assume subtree we're given has already been
00875         // met and so try to find lowest leaf of next subtree...
00876         // (If this is the first call, from FindFirst, then treat the node we've got
00877         //  as if it hasn't been scanned yet. 'Cos it hasn't!)
00878         if (pContext->FindNext() || FirstCall)
00879         {
00880             // Here, either have a sibling or FirstCall is TRUE
00881             // So, if firstcall is NOT TRUE, must be here due to sibling...
00882             if (!FirstCall)
00883                 pContext = pContext->FindNext();                    // Find top of next subtree
00884             FirstCall = FALSE;
00885 
00886             // In a normal depth-first traversal of the tree we would find the deepest first child
00887             // in the subtree. However, by choosing not to go down certain child links
00888             // we can omit whole subtrees from the scan.
00889             // The following tests optimise away much of the work of a true depth-first
00890             // search by pruning subtrees that don't need to be traversed.
00891 
00892             //---------------------------------------------------------------------------//
00893             // If above layers, skip on down towards one...
00894             while (pContext->FindFirstChild() && !pContext->IsLayer() && pContext->IsPaper())
00895                 pContext = pContext->FindFirstChild();
00896             // If we've not made it to a layer and we're still in paper then prune whatever
00897             // subtree we have because this routine is interested in children of layers and
00898             // their subtrees.
00899             if (pContext->IsPaper() && !pContext->IsLayer())
00900                 goto PruneSubtree;
00901 
00902             //---------------------------------------------------------------------------//
00903             // We know now we're either at a layer node or underneath one...
00904             // If this layer has children go down to that level because that surface has
00905             // a special meaning to this routine. Most ranges are found in the child lists
00906             // of Layers.
00907             if (pContext->IsLayer())
00908             {
00909                 // Don't allow Ranges into invisible layers at all!
00910                 // New range control flag allows this to be overriden, defaults to FALSE
00911                 if ( !RangeControlFlags.IgnoreInvisibleLayers && !((Layer*)pContext)->IsVisible() )
00912                     goto PruneSubtree;
00913 
00914                 // Don't allow SelRanges into locked layers at all!
00915                 // New range control flag allows this to be overriden, defaults to FALSE
00916                 if ( RangeControlFlags.IgnoreLockedLayers && ((Layer*)pContext)->IsLocked() )
00917                     goto PruneSubtree;
00918 
00919                 // If layer has children go find first child and continue pruning tests
00920                 if (pContext->FindFirstChild())
00921                     pContext = pContext->FindFirstChild();
00922                 // Otherwise don't try to process empty layers at all!
00923                 else
00924                     goto PruneSubtree;
00925             }
00926 
00927             //---------------------------------------------------------------------------//
00928             // Descend subtree further if we come across select-inside (flagged by ParentOfSelected)
00929             // If looking for selected nodes (and not unselected nodes - Ed 1/5/95)
00930             // AND this node is the parent of selected nodes
00931             // Then go down this subtree as far as the parent of selected
00932             // flags last out...
00933             if (pContext->IsParentOfSelected() && RangeControlFlags.Selected && !RangeControlFlags.Unselected)
00934             {
00935                 while (pContext->IsParentOfSelected() && pContext->FindFirstChild())
00936                 {
00937                     pContext = pContext->FindFirstChild();
00938                 }
00939                 ERROR3IF(pContext->IsParentOfSelected(),"Parent of selected has no children!");
00940             }
00941 
00942 // Logically, if promotetoparent is not set we shouldn't return any node which would
00943 // be the target of promotetoparent activities...
00944 if (!RangeControlFlags.PromoteToParent && RangeControlFlags.Selected && RangeControlFlags.Unselected)
00945 {
00946     while (pContext->ShouldITransformWithChildren() && pContext->FindFirstChild())
00947     {
00948         pContext = pContext->FindFirstChild();
00949     }
00950     ERROR3IF(pContext->ShouldITransformWithChildren(), "Parent of selected has no children!");
00951 }
00952 
00953             //---------------------------------------------------------------------------//
00954             // Finally, there's no choice any more, we've got to descend into the subtree IF
00955             // the AndChildren flag is set and the node is a Primary member of the range
00956             // Then we are either already scanning a subtree and so we must continue
00957             // or else we're starting to scan a subtree because it meets the range
00958             // criteria and the range specifies that all child nodes of primary nodes
00959             // should be returned.
00960             // So, look for lowest leaf of subtree...
00961             if (!RangeControlFlags.SiblingsOnly && AndChildren)
00962             {
00963                 Node* pChild = pContext->FindFirstChild();
00964                 while (pChild)
00965                 {
00966                     if (InRange(pChild, AndChildren))
00967                     {
00968                         pContext=pChild;
00969                         pChild=pChild->FindFirstChild();
00970                     }
00971                     else
00972                         pChild=pChild->FindNext();
00973                 }
00974             }
00975 
00976             //---------------------------------------------------------------------------//
00977             // If control gets here then the root of the "next" subtree is being returned for
00978             // consideration because we have judged that its subtree doesn't need scanning!
00979 PruneSubtree:;
00980 
00981         }
00982         else
00983         {
00984             // No next subtree, so go up to parent...
00985             // If no parent then we must have scanned the entire tree (by definition of
00986             // depth-first traversal) so return NULL to caller.
00987             pContext = pContext->FindParent();
00988 
00989             // If we're not promoting to parent and we find our parent is the type of object we would normally
00990             // promote to, DON'T return it, keep going up!
00991             // (It doesn't make sense to return a node and it's parent controller)
00992             // This change made so that a shadowed node on the clipboard will return a set of sensible
00993             // common attributes when FindCommonAttributes is called on the clipboard range.
00994             // Test by using Paste Attributes
00995 // NOPE, THIS DOESN'T WORK!
00996 //          while (pContext && !AndChildren && !RangeControlFlags.PromoteToParent && pContext->ShouldITransformWithChildren())
00997 //          {
00998 //              pContext = pContext->FindParent();
00999 //          }
01000 
01001             if (pContext==NULL)
01002                 return NULL;
01003 
01004             // Ranges cannot exist across spreads so if we reach a Spread node we can stop...
01005             if (pContext->IsSpread())
01006                 return NULL;
01007 
01008             if (pContext->IsLayer() && !RangeControlFlags.CrossLayer)
01009                 // Can't cross layers so signal end of Range...
01010                 return NULL;
01011         }
01012     }
01013     while (pContext!=NULL && (pContext->IsLayer() || pContext->IsPaper() || !InRange(pContext, AndChildren)));
01014 
01015     // Finally, check for parents wanting to be included instead of the children
01016     if (pContext != NULL && RangeControlFlags.PromoteToParent && !AndChildren)
01017     {
01018         Node *pParent = pContext->FindParent();
01019         while (pParent != NULL && pParent->ShouldITransformWithChildren())
01020         {
01021             pContext = pParent;
01022             pParent = pContext->FindParent();
01023         }
01024     }
01025 
01026     return pContext;
01027 }
01028 
01029 
01030 
01031 
01032 /******************************************************************************************
01033 
01034 >   BOOL Range::InRange(Node* pNode, BOOL AndChildren) const
01035 
01036      Author:    Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01037      Created:   24/11/94
01038      Rewritten: 08/12/2004
01039      Inputs:    pNode           Pointer to node to test for inclusion in the range
01040                 AndChildren     Children of the primary range are allowed to be returned
01041      Outputs:   -
01042      Returns:   TRUE if node is in this range (ignoring CrossLayer flag)
01043                 FALSE if not
01044      Purpose:   Private helper function for SmartFindNext.
01045                 Tests whether the presented node is in the range according to the
01046                 RangeControlFlags and two other locally presented flags.
01047 
01048                 Version 2, 08/12/2004
01049                 Simplified and adjusted to deal with selection inside Compound Parents
01050                 Controllers and PostProcessors
01051 
01052                 This function should ONLY be called on nodes that /could/ be members of Range
01053                 Not Layers or Paper nodes!
01054 
01055      Scope:     Protected
01056      SeeAlso:   Range::SmartFindNext
01057      Errors:    When attempting to return children and finds no parent link.
01058 
01059 ******************************************************************************************/
01060 
01061 BOOL Range::InRange(Node* pNode, BOOL AndChildren) const
01062 {
01063     // Preconditions
01064     ERROR2IF(this==NULL, FALSE, "InRange called on NULL range");
01065     ERROR2IF(pNode==NULL, FALSE, "InRange given a NULL node");
01066     ERROR2IF(pNode->IsPaper(), FALSE, "InRange asked to decide on Paper");
01067     ERROR2IF(pNode->IsLayer(), FALSE, "InRange asked to decide on Layer");
01068     ERROR2IF(RangeControlFlags.Unselected && !RangeControlFlags.Selected && FirstNode==NULL, FALSE, "InRange can't detect unselected nodes without a FirstNode");
01069 
01070     //------------------------------------------------------------------------------------
01071     // Test for Primary members of the range...
01072     //
01073     // If an op has asked this node for permission to apply the op to it, and the node said no, return.
01074     if (pNode->GetOpPermission() == PERMISSION_DENIED)
01075         return FALSE;
01076 
01077     // if trying to ignore none renderable nodes then check the node
01078     SubtreeRenderState state = pNode->RenderSubtree(NULL);
01079     if (RangeControlFlags.IgnoreNoneRenderable && !(state==SUBTREE_ROOTONLY || state==SUBTREE_ROOTANDCHILDREN))
01080         return FALSE;
01081 
01082     // If looking for selected nodes and node is selected, OK
01083     if (RangeControlFlags.Selected && pNode->IsSelected())
01084         return TRUE;
01085 
01086 // If we're not promoting to parents but we seem to have found one such parent
01087 // Then deny this node
01088 if (!AndChildren && !RangeControlFlags.PromoteToParent && pNode->ShouldITransformWithChildren())
01089     return FALSE;
01090 
01091     // If looking for all nodes but not going into child subtrees, OK whether node is selected or not
01092     if (!AndChildren && RangeControlFlags.Selected && RangeControlFlags.Unselected)
01093         return TRUE;
01094 
01095     // If node isn't paper then it ought to have a parent node which we will need later...
01096     Node* pParent = pNode->FindParent();
01097     ERROR2IF_PF(pParent==NULL, FALSE, ("OOER! Range found an ink node %lx without any parents!",pNode));
01098 
01099     Node* pFirstParent = NULL;
01100     if (FirstNode)
01101         pFirstParent = FirstNode->FindParent();
01102 
01103     // If looking for immediate siblings only then check that this ndoe has the same parent as
01104     // the first node (we've already checked pParent to be non-NULL)
01105     if (RangeControlFlags.SiblingsOnly)
01106     {
01107         if (pFirstParent!=pParent)
01108             return FALSE;
01109     }
01110     
01111     // If looking for unselected nodes then we need to check whether this node is unselected
01112     // and in the same level of the tree as the first node...
01113     while (!pNode->IsSelected() && RangeControlFlags.Unselected && pFirstParent && pParent)
01114     {
01115         if (pFirstParent == pParent)
01116             return TRUE;
01117 
01118         pFirstParent = pFirstParent->FindParent();
01119         pParent = pParent->FindParent();
01120     }
01121 
01122     //------------------------------------------------------------------------------------
01123     // Test for Secondary members of the range by recursion...
01124     //
01125     // If looking for children of nodes in the primary range specification
01126     // or looking for selected nodes (which may be "selected-inside")
01127     // Then we must check that our parent is in the range. If he is then we are!
01128     if (AndChildren && !pParent->IsLayer() && !pParent->IsPaper())
01129         return InRange(pParent, AndChildren);
01130 
01131     return FALSE;
01132 }
01133 
01134 
01135 
01136 
01137 
01138 
01139 
01140 
01141 /*****************************************************************************************/
01142 
01143 /********************************************************************************************
01144 
01145 >   List* Range::MakeListOfNodes(BOOL AndChildren = FALSE)
01146 
01147     Author:     Jim_Lynn (Xara Group Ltd) <camelotdev@xara.com>
01148     Created:    22/7/94
01149     Inputs:     -
01150     Outputs:    -
01151     Returns:    Pointer to a list of NodeListItems representing the current range
01152     Purpose:    This function will create and return a pointer to a list representing
01153                 the objects in the range. It will return NULL if it couldn't create the
01154                 list due to lack of memory.
01155                 WARNING! This function creates objects which must be deleted by the calling
01156                 routine. The last thing we need right now is another bunch of listitems
01157                 appearing on shutdown.
01158     Errors:     -
01159     SeeAlso:    -
01160 
01161 ********************************************************************************************/
01162 
01163 List* Range::MakeListOfNodes(BOOL AndChildren)
01164 {
01165     // Create the list object first
01166     List* RangeList = new List;
01167     
01168     // only build the list if we found enough memory
01169     if (RangeList)
01170     {
01171         // Get the first object in the range to start the loop
01172         Node* pNode = FindFirst(AndChildren);
01173         BOOL Failed = FALSE;            // Will be TRUE if we ran out of memory
01174 
01175         // loop round all the objects in the range
01176         while (pNode)
01177         {
01178             if (!pNode->IsNodeHidden()) // DON'T record hidden nodes because they might be deleted!
01179             {
01180                 // Mark Howitt 13/12/00 - This is a bodge fix for the release version. As the ClipViewAttribute is
01181                 // only used by the new bevel code, it`s safe (Bodge) to make it not includable in any selections.
01182                 // This will need to be fix for future versions if we decide to start using the attribute correctly!
01183                 if(!pNode->IsAClipViewAttr())
01184                 {
01185                     NodeListItem* pItem;
01186                     if ((pItem = new NodeListItem(pNode))!=NULL)
01187                     {
01188                         // Creation successful, so add it to the list
01189                         RangeList->AddTail(pItem);
01190                     }
01191                     else
01192                     {
01193                         // Creation failed, so flag an error and break the loop
01194                         Failed = TRUE;
01195                         break;
01196                     }
01197                 }
01198             }
01199 
01200             // Go to the next node in the range
01201             pNode = FindNext(pNode, AndChildren);
01202         }
01203         // Handle an error if it occurred
01204         if (Failed)
01205         {
01206             while (!RangeList->IsEmpty())
01207             {
01208                 NodeListItem* pItem = (NodeListItem*)(RangeList->RemoveHead());
01209                 delete pItem;
01210             }
01211             delete RangeList;
01212             return NULL;
01213         }
01214 
01215     }
01216     return RangeList;
01217 }
01218 
01219 
01220 /********************************************************************************************
01221 
01222 >   void Range::UpdateParentBoundsOfSelection(BOOL AndChildren = FALSE)
01223 
01224     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01225     Created:    15/7/94
01226     Purpose:    This function updates the parent bounds of all selected objects. It is a 
01227                 lot more efficient than calling ChangeBounds on every node in the selection
01228                 (cos it uses an algorithm!)
01229     SeeAlso:    NodeRenderableBounded::ChangeBounds
01230 
01231 ********************************************************************************************/
01232 
01233 void Range::UpdateParentBoundsOfSelection(BOOL AndChildren)
01234 {
01235     // Find the first node in the selection
01236     Node* pNode = FindFirst(AndChildren);
01237     
01238     // loop through the selection, invalidating all the bounding rects
01239     while (pNode!=NULL)
01240     {
01241         // If the node was bounded, then invalidate its bounding rect
01242         if (pNode->IsBounded())
01243             ((NodeRenderableBounded*)pNode)->InvalidateBoundingRect();
01244 
01245         // Get the next node in the selection
01246         pNode = FindNext(pNode,