ndoptmz.cpp

Go to the documentation of this file.
00001 // $Id: ndoptmz.cpp 1282 2006-06-09 09:46:49Z alex $
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 
00101 // The implementation of the NodeRenderableInk attribute optimisation routines 
00102 
00103 #include "camtypes.h"
00104 //#include "node.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00105 //#include "nodeattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 //#include "list.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "listitem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 #include "objreg.h"
00111 #include "ndoptmz.h"
00112 //#include "ink.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 #include "nodetext.h"
00114 #include "nodedoc.h"
00115 #include "ndmldgrp.h"
00116 #include "nodemldr.h"
00117 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00118 
00119 // for the template attribute
00120 //#include "cxfrech.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00121 //#include "attrval.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00122 #include "userattr.h"
00123 #include "tmpltatr.h" 
00124 
00125 #include "brshattr.h"
00126 #include "dbugtree.h"
00127 
00128 
00129 DECLARE_SOURCE("$Revision: 1282 $");
00130 CC_IMPLEMENT_DYNCREATE( FactorOutCommonChildAttrAct, Action )
00131 CC_IMPLEMENT_DYNCREATE( LocaliseCommonAttrAct, Action )
00132 
00133 // Declare smart memory handling in Debug builds
00134 #define new CAM_DEBUG_NEW
00135 
00136 
00137 
00138 
00139 /********************************************************************************************
00140 
00141 >   BOOL NodeRenderableInk::MakeAttributeComplete(Node* Root = NULL,
00142                                                   BOOL CheckForDuplicates = TRUE,
00143                                                   AttrTypeSet* pAffectedAttrTypes = NULL, 
00144                                                   BOOL IncludeDefaults = FALSE,
00145                                                   BOOL bIncludeEffectAttrs = FALSE)
00146 
00147     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00148     Created:    7/2/94
00149 
00150     Inputs:     Root:               The search for attributes will stop at this node. The 
00151                                     NULL default value means 'don't stop until we reach the top'.
00152                 CheckForDuplicates: When TRUE a check is made to ensure that duplicate
00153                                     attribiutes are not added to the subtree (this is the
00154                                     default). When localising a groups attributes this 
00155                                     check will be unneccessary.
00156                 pAffectedAttrTypes: An optional set of attribute types. If this is specified
00157                                     then we only add attributes which have a type
00158                                     in this set.
00159                 IncludeDefaults:    When TRUE default attributes will be added.
00160                 bIncludeEffectAttrs Only used when forcing effect attrs to become normal attrs
00161                                     (see Ungroup) TRUE to force attr scanning to find effect
00162                                     attrs as well as normal ones...
00163                     
00164     Outputs:    -
00165     Returns:    TRUE if successful
00166                 FALSE if we run out of memory, the children of the node will remain unchanged
00167 
00168     Purpose:    This function should be called on a subtree prior to it being moved, either
00169                 to a new position in the document, or to another document. It is also used 
00170                 to localise attributes; during an ungroup for example.  
00171                  
00172                 It finds ALL attributes which are required by the subtree and adds 
00173                 them as first children. 
00174                   
00175                 After the subtree has been moved to its new position, the function 
00176                 NodeRenderableInk::NormaliseAttributes should be called.
00177 
00178     SeeAlso:    NodeRenderableInk::NormaliseAttributes
00179     SeeAlso:    Range::MakeAttributeComplete
00180 
00181 ********************************************************************************************/
00182 
00183 BOOL NodeRenderableInk::MakeAttributeComplete(Node* Root, 
00184                                               BOOL CheckForDuplicates,        /* = TRUE */
00185                                               AttrTypeSet* pAffectedAttrTypes, /* = NULL */ 
00186                                               BOOL IncludeDefaults, /* = FALSE */
00187                                               BOOL bIncludeEffectAttrs /* = FALSE */)
00188 {
00189     Node* Current = NULL;  // Pointer to the current node in the tree 
00190 
00191     NodeAttribute* CurAttr;
00192     CCRuntimeClass* AttrType;
00193     BOOL Exists; 
00194 
00195     Node* PreFirstChild = FindFirstChild(); // Remember the FirstChild of the node before we add
00196                                             // any new attributes, this will come in handy if we
00197                                             // need to abort.
00198 
00199     // Loop until all attributes are copied, we are not interested in the defaults cos these are the
00200     // same for all docs !.
00201     if (bIncludeEffectAttrs)
00202         Current = NodeAttribute::FindFirstAppliedAttr(this, Root);
00203     else
00204         Current = NodeAttribute::FindPrevAppliedAttr(this, Root);
00205 
00206     while (Current && (IncludeDefaults || (!(IS_A(Current->FindParent(), NodeDocument)))) )
00207     {
00208         // Find the next node, snaking up the tree
00209         if (Current->IsAnAttribute())
00210         {
00211             CurAttr = (NodeAttribute*)Current;
00212             if (CurAttr->CanBeAppliedToObject() && CurAttr->ShouldBeOptimized())
00213             {
00214                 AttrType = CurAttr->GetAttributeType();
00215 
00216                 BOOL Required = RequiresAttrib(AttrType) || this->IsCompound();
00217                 // Is the attribute required ?
00218                 if (Required && (!pAffectedAttrTypes || pAffectedAttrTypes->InSet(AttrType)))
00219                 {
00220                     Exists = FALSE; 
00221                     if (CheckForDuplicates)
00222                     {
00223                         // triggers can have duplicates
00224                         if(!CurAttr->CanBeMultiplyApplied())
00225                         {
00226                             // Does the node already have this child attribute
00227                             Exists = (GetChildAttrOfType(AttrType) != NULL);
00228                         }
00229                     }
00230 
00231                     #ifdef _DEBUG
00232                     if (!CheckForDuplicates)
00233                     {
00234                         // If we feel there is no need to check for duplicates then there shouldn't be any !
00235                         if (!CurAttr->CanBeMultiplyApplied())
00236                         {
00237                             NodeAttribute* pChildAttr = GetChildAttrOfType(AttrType);
00238                             if ((pChildAttr != NULL))
00239                             {
00240 #if DEBUG_TREE
00241                                 DebugTreeDlg::DumpSubTree(this, 4);
00242 #endif
00243                                 TRACE(_T("Duplicate Attr found at %x %s\n"), pChildAttr, pChildAttr->GetRuntimeClass()->m_lpszClassName);
00244                             }
00245 //                          ERROR3IF((pChildAttr != NULL), "MakeAttributeComplete: Duplicate attr found !"); 
00246                         }
00247                     }
00248                     #endif
00249 
00250                     if (!Exists)
00251                     {
00252                         // Make a copy of the attribute
00253                         NodeAttribute* NewAttr = (NodeAttribute*)CurAttr->SimpleCopy();
00254 
00255                         if (NewAttr == NULL)
00256                         {
00257                             goto OutOfMemory; 
00258                         }
00259 
00260                         // Now add the attribute to this node
00261                         NewAttr->AttachNode(this, FIRSTCHILD, TRUE, FALSE);
00262                     }
00263                 }
00264             }
00265         }
00266         Current = NodeAttribute::FindPrevAppliedAttr(Current, Root);
00267 
00268         // in order to copy brush ink nodes we need to break if the parent is NULL, else is violates
00269         if (Current!=NULL && Current->FindParent() == NULL)
00270             break;
00271     } 
00272 
00273     return TRUE;
00274 
00275 OutOfMemory:
00276     
00277     // Delete any new attributes added to the node
00278     Current = FindFirstChild(); 
00279     Node* Next; 
00280 
00281     while (Current != PreFirstChild)
00282     {
00283         ENSURE(Current != NULL, "PreFirstChild could not be found");
00284         ENSURE(Current->IsAnAttribute(), "Should be a NodeAttribute"); 
00285         
00286         Next = Current->FindNext();
00287         // Delete the attribute
00288         Current->CascadeDelete(); 
00289         delete Current;             
00290 
00291         Current = Next; 
00292     }
00293 
00294     return FALSE; 
00295 }
00296 
00297 /********************************************************************************************
00298 
00299 >   void NodeRenderableInk::NormaliseAttributes()
00300 
00301     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00302     Created:    9/2/94
00303     Inputs:     -
00304     Outputs:    -
00305     Returns:    -
00306     Purpose:    This function should be called whenever an attribute-complete node is inserted
00307                 into the tree (whether it's a new node, or a node which has been moved 
00308                 from elsewhere). 
00309                 
00310                 It removes all child attributes of the node which are the same type and value 
00311                 as attributes defined further up the tree eg. the defaults
00312             
00313     Errors:     -
00314     SeeAlso:    NodeRenderableInk::MakeAttributeComplete
00315 
00316 ********************************************************************************************/
00317 
00318 void NodeRenderableInk::NormaliseAttributes()
00319 {
00320 
00321     NodeAttribute* ChildAttribute;     
00322     NodeAttribute* GlobalAttribute;
00323 
00324     Node* LocalScan;
00325     Node* NextLocal;  
00326     
00327     // Scan the child attribute block
00328     LocalScan = FindFirstChild();
00329     // Stop if we hit an object or if there are no more children 
00330     // NOTE: Stopping scanning when we find the first RendereblInk node prevents
00331     // Effect attributes being Normalised. THIS IS DELIBERATE!
00332     while((LocalScan != NULL) && (!LocalScan->IsAnObject())) 
00333     {
00334         // Hand over hand (LocalScan may get deleted)
00335         NextLocal = LocalScan->FindNext();
00336         if(LocalScan->IsAnAttribute() && ((NodeAttribute*)LocalScan)->ShouldBeOptimized())  // cos it could be a NodeHidden
00337         {
00338             ChildAttribute = (NodeAttribute*)LocalScan;  
00339             // We now need to search up the tree to see if ChildAttribute is redundant
00340 //          Node* GlobalScan = FindPreviousEffectiveNode();
00341             Node* GlobalScan = NodeAttribute::FindPrevAppliedAttr(this);
00342             // Search until we can go no higher
00343             while (GlobalScan != NULL)
00344             {
00345                 if (GlobalScan->IsAnAttribute())
00346                 {
00347                     GlobalAttribute = (NodeAttribute*)GlobalScan; 
00348                     // An attribute has been found, is it the same class as ChildAttribute ?
00349                     if(GlobalAttribute->GetRuntimeClass() ==
00350                        ChildAttribute->GetRuntimeClass())
00351                     {
00352                         // Yes it is, so let's check if they are equal
00353                         if ((*GlobalAttribute)==(*ChildAttribute))
00354                         {
00355                             // They are equal so we can nuke the child object because it's 
00356                             // redundant
00357                             ChildAttribute->CascadeDelete();
00358                             delete ChildAttribute;
00359                         }
00360                         break;   // don't search any further
00361                     }
00362 
00363                 }
00364 //              GlobalScan = GlobalScan->FindPreviousEffectiveNode(); // climb higher
00365                 GlobalScan = NodeAttribute::FindPrevAppliedAttr(GlobalScan);
00366             } 
00367         }
00368         LocalScan = NextLocal; // Get the next child 
00369     }    
00370 
00371 }
00372 
00373 /********************************************************************************************
00374 
00375 >   void NodeRenderableInk::RemoveSuperfluousAttribs()
00376 
00377     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00378     Created:    9/2/94
00379     Inputs:     -
00380     Outputs:    -
00381     Returns:    -
00382     Purpose:    This fn does not exist.
00383     
00384     
00385                 This function removes attributes from the subtree that we consider to
00386                 be superfluous. An attribute is classed as superfluous if -
00387 
00388                 a. It is overridden by an attribute of the same class before any ink object
00389                    has been rendered. 
00390 
00391                    e.g. Select a red pen, select a green pen, draw a circle
00392 
00393                    Here picking up the red pen is a waste of effort and so can be removed.
00394 
00395                    A subtree which has had the MakeAttributeComplete method called on it
00396                    will probably have attributes like these.
00397 
00398                 b. The attribute (i.e. same class, same value) has already been defined 
00399                    
00400                    e.g. Select a red pen, draw a circle, select a red pen, draw a square
00401 
00402                    Again the default attributes which will be added by the MakeAttributeComplete
00403                    method will fall into this category.
00404                  
00405     Scope:      protected
00406     Errors:     -
00407     SeeAlso:    NodeRenderableInk::NormaliseAttributes
00408     SeeAlso:    NodeRenderableInk::MakeAttributeComplete
00409 
00410 ********************************************************************************************/
00411 /*
00412 void NodeRenderableInk::RemoveSuperfluousAttribs()
00413 {
00414     // Local Scan is used to perform a depth first traversal of the subtree
00415     Node* LocalScan = FindFirstDepthFirst(); 
00416 
00417     // Global Scan is used to find attributes defined in and above the subtree
00418     Node* GlobalScan; 
00419 
00420     Node* ToDie = NULL; 
00421     
00422     // Attribute override flag. This gets set to true when we start processing each 
00423     // local attribute. 
00424     BOOL AttribOver;  
00425     
00426     // Traverse the tree in render order
00427     while (LocalScan != NULL)
00428     {
00429         if (LocalScan->IsKindOf(CC_RUNTIME_CLASS(NodeAttribute)))
00430         {
00431             // Ok weve found a node attribute, lets see if it's superfluous
00432             // We need to search back up the tree in reverse render order to determine this
00433 
00434             GlobalScan = LocalScan;
00435             
00436             // This flag gets set to FALSE as soon as we find an ink node or we move 
00437             // to a parent node.
00438             AttribOver = TRUE;  
00439 
00440             while (GlobalScan != NULL)
00441             {
00442                 // Find the next node 
00443                 if (GlobalScan->FindPrevious() != NULL)
00444                 {
00445                     GlobalScan = GlobalScan->FindPrevious();    // Search leftmost siblings of 
00446                                                                 // the subtree first
00447                 }
00448                 else 
00449                 {
00450                     GlobalScan = GlobalScan->FindParent();   // then move to the parent
00451                     AttribOver = FALSE;
00452                 }
00453 
00454                 if (ToDie != NULL)
00455                 {
00456                     // Set at (a)
00457                     ToDie->UnlinkNodeFromTree(); 
00458                     delete ToDie;
00459                     ToDie = NULL;
00460                 }
00461 
00462                 if (GlobalScan != NULL)
00463                 {
00464                     if (AttribOver)
00465                     {
00466                         if (GlobalScan->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableInk)))
00467                         {
00468                             AttribOver = FALSE; 
00469                         }
00470                     }
00471                     else if (GlobalScan->GetRuntimeClass() == LocalScan->GetRuntimeClass())
00472                     {
00473                     #if _DEBUG
00474                         if (IsUserName("Simon"))
00475                         {
00476                             TRACE( _T("Local attrib = %s, Global = %s"), LocalScan->Name(), GlobalScan->Name()); 
00477                         }
00478                     #endif
00479 
00480                         if (AttribOver)
00481                         {
00482                             // The GlobalScan Attribute is redundant
00483                             // (a)
00484                             ToDie = GlobalScan;
00485                             // continue the search
00486                         }
00487 
00488                         // An attribute of the same class is found, do they have the 
00489                         // same value
00490 
00491                         else if ( (*((NodeAttribute*)LocalScan)) == (*((NodeAttribute*)GlobalScan)))
00492                         {
00493                             // The attribute is superfluous so kill it 
00494                             //(b)
00495                             ToDie = LocalScan; 
00496                             break;// Terminate the global scan  
00497                         }
00498                     
00499                     }
00500                 }
00501             }
00502         }
00503         // Get the next node in the subtree
00504         LocalScan = LocalScan->FindNextDepthFirst(this); 
00505 
00506         if (ToDie != NULL)
00507         {
00508             // Set at (b)
00509             ToDie->UnlinkNodeFromTree(); 
00510             delete ToDie;
00511             ToDie = NULL;
00512         } 
00513     }   
00514 } 
00515 */
00516 
00517 
00518 /********************************************************************************************
00519 
00520 >   static BOOL NodeRenderableInk::FindCommonAttributesToFactorOut(CommonAttrSet* CommonAttributeSet)
00521 
00522     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00523     Created:    3/8/94
00524     Inputs:     -
00525     Outputs:    All items in the CommonAttributeSet are attributes common to all objects
00526                 within the group. The attributes applied to objects which can discard their
00527                 attributes (like the caret) are ignored
00528 
00529     Returns:    TRUE if successful, FALSE otherwise (out of memory) 
00530     Purpose:    Finds all attributes common to the compound node
00531     Errors:     -
00532     Scope:      private
00533     SeeAlso:    -
00534 
00535 ********************************************************************************************/
00536 /*
00537 Technical Notes:
00538 
00539 (Method)
00540 
00541 CommonAttributeSet = the set of all attributes 
00542 Each attribute in the set has a NULL value.
00543 
00544 Scan all grouped objects (Current)
00545     Scan each attribute in the common attribute set in turn (CommonA)
00546         If Current requires the attribute
00547             If Current has an attribute with the same type as CommonA then
00548                 If CommonA == NULL
00549                     CommonA = Currents attribute
00550                 Else if (CommonA != Currents attribute)
00551                     The attribute is not common so remove it from the common attribute set.
00552             else
00553                 The attribute is not common so remove it from the common attribute set. 
00554     EndScan
00555     Current = Next object in group
00556 EndScan
00557 */
00558 
00559 BOOL NodeRenderableInk::FindCommonAttributesToFactorOut(CommonAttrSet* CommonAttributeSet)
00560 {
00561     CommonAttributeItem* CommonAttrItem;
00562     CommonAttributeItem* NextCommonAttrItem;
00563 
00564     // Place all attributes in the CommonAttributeSet
00565     if (!CommonAttributeSet->AddAllTypesToSet())
00566     {
00567         return FALSE; // ERROR already called 
00568     }
00569 
00570     // Scan all grouped objects
00571     for (Node* CurrentObject = FindFirstChild();  
00572          CurrentObject != NULL;
00573          CurrentObject = CurrentObject->FindNext())
00574     {
00575         if (CurrentObject->IsAnObject())
00576         {
00577             
00578             // Scan all attributes in the CommonAttributeSet in turn
00579             CommonAttrItem = (CommonAttributeItem*)CommonAttributeSet->GetHead();
00580 
00581             while(CommonAttrItem != NULL)
00582             {
00583                 // Hand over hand cos we may well delete the CommonAttrItem
00584                 NextCommonAttrItem = (CommonAttributeItem*)(CommonAttributeSet->GetNext(CommonAttrItem));
00585 
00586                 // Does CurrentObject require the attribute to render
00587                 if ( (((NodeRenderableInk*)CurrentObject)->RequiresAttrib(CommonAttrItem->AttrType)) || CurrentObject->IsCompound())
00588                 {
00589                     BOOL DeleteCommonAttr = FALSE; // Until we know better
00590             
00591                     // Ok the current object requires the attribute
00592                     // Does the CurrentObject have a child attribute of this type ?
00593                     NodeAttribute* pAttrNode = 
00594                         ((NodeRenderableInk*)CurrentObject)->GetChildAttrOfType(CommonAttrItem->AttrType);
00595                     if (pAttrNode != NULL && pAttrNode->ShouldBeOptimized())
00596                     {
00597                         // Ok it has an attribute of this type
00598                         if (CommonAttrItem->pAttr == NULL)
00599                         {
00600                             // The attribute becomes a common attribute
00601                             CommonAttrItem->pAttr = pAttrNode;
00602                             CommonAttrItem->Status = Range::ATTR_COMMON; 
00603                         }
00604                         else if(CommonAttrItem->pAttr->GetRuntimeClass() ==
00605                                 pAttrNode->GetRuntimeClass())
00606                         {
00607                             // Ok they are the same runtime class but are they equal
00608                             if (!((*pAttrNode)==(*(CommonAttrItem->pAttr))))
00609                             {
00610                                 // They are not equal so remove CommonAttrItem from the
00611                                 // common attribute set.
00612                                 DeleteCommonAttr = TRUE; 
00613                             }
00614                             // DY 12/5/2000 AttrBrushTypes cannot be factored because they 
00615                             // may contain caches of pressure or timestamp data which apply
00616                             // to a specific node only.
00617                             // They no longer contain this data so factor them like normal!
00618                             //if (pAttrNode->IsKindOf(CC_RUNTIME_CLASS(AttrBrushType)))
00619                             //  DeleteCommonAttr = TRUE;
00620                         }
00621                         else 
00622                         {
00623                             // They cannot be the same value cos they are different runtime types
00624                             DeleteCommonAttr = TRUE; 
00625                         }
00626                     }
00627                     else 
00628                     {
00629                         // The CurrentObject does not have an attribute of this type so it
00630                         // cannot be common
00631                         DeleteCommonAttr = TRUE; 
00632                     }
00633 
00634                     if (DeleteCommonAttr)
00635                     {
00636                         delete(CommonAttributeSet->RemoveItem(CommonAttrItem)); 
00637                     }
00638                 }
00639 
00640                 CommonAttrItem = NextCommonAttrItem;
00641             }
00642         }
00643         // Removed because there are circumstances where certain attributes have 
00644         // already been factored out eg. Corel filter
00645         //else 
00646         //{
00647         //  ENSURE(CurrentObject->GetRuntimeClass() == CC_RUNTIME_CLASS(NodeHidden), 
00648         //              "It's not an object, it's not a hidden node, so what is it ??");
00649         //}
00650     }   
00651     // Delete all NULL items in the CommonAttributeSet
00652     CommonAttrItem = (CommonAttributeItem*)CommonAttributeSet->GetHead();
00653     while (CommonAttrItem != NULL)
00654     {
00655         CommonAttributeItem* Next = (CommonAttributeItem*)CommonAttributeSet->GetNext(CommonAttrItem);
00656         if (CommonAttrItem->pAttr == NULL)
00657         {
00658             // Item is a non required attribute so zap it
00659             delete (CommonAttributeSet->RemoveItem(CommonAttrItem)); 
00660         }
00661         CommonAttrItem = Next; 
00662     }
00663     
00664     return TRUE; // Job done
00665 }
00666 
00667 
00668 
00669 
00670 /********************************************************************************************
00671 
00672 >   static BOOL NodeRenderableInk::FactorOutCommonChildAttributes(BOOL Global = FALSE, 
00673                                                                   AttrTypeSet* pAffectedAttrTypes = NULL)
00674 
00675     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00676     Created:    2/8/94
00677 
00678     Inputs:     Global: When TRUE we recursively factor out attributes in all parent compounds 
00679                         of the CompoundObject (Bottom up)
00680                                     
00681                 pAffectedAttrTypes: An optional set of attribute types. If this is specified
00682                                     then we only consider factoring out  those attributes
00683                                     which have a type which is in this set. 
00684 
00685     Outputs:    TRUE if successful, FALSE otherwise (out of memory)
00686 
00687     Returns:    This function finds all attributes which are common to all children
00688                 of this compound object, adds the common attributes to this node and
00689                 deletes them from its children. 
00690 
00691                 If the compound contains a node which can discard its attributes (like the caret)
00692                 then its attributes are not considered when factoring out.
00693 
00694 
00695     Purpose:    
00696     Scope:      public
00697     Errors:     -
00698     Document:   atroptmz.doc
00699     SeeAlso:    -
00700 
00701 ********************************************************************************************/
00702 
00703 BOOL NodeRenderableInk::FactorOutCommonChildAttributes(BOOL Global, AttrTypeSet* pAffectedAttrTypes)
00704 {
00705     // This function should only ever get called on a compound object
00706     ENSURE(IsCompound(), "FactorOutCommonChildAttributes called on a non compound object"); 
00707     
00708 
00709     // Try to factor out the neccessary attributes
00710     if (!FactorOutCommonChildAttrHelper(Global, pAffectedAttrTypes))
00711     {
00712         // Tidyup then return FAIL
00713         DeleteLocalisedAttributes(Global, pAffectedAttrTypes); // tidyup
00714         return FALSE; // Failed
00715     }
00716     else
00717     {
00718         // The only thing that remains now is to delete all remaining factored out attributes
00719         DeleteFactoredOutAttribs(Global, pAffectedAttrTypes); 
00720     }
00721 
00722     return TRUE; // Success
00723 }
00724 
00725 /********************************************************************************************
00726 
00727 >   BOOL NodeRenderableInk::FactorOutCommonChildAttributesHelper(BOOL Global, 
00728                                                                  AttrTypeSet* pAffectedAttrTypes)
00729 
00730 
00731     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00732     Created:    17/5/95
00733     Inputs:     Global: When TRUE we recursively factor out attributes in all parent compounds 
00734                         of the CompoundObject (Bottom up)
00735                                     
00736                 pAffectedAttrTypes: An optional set of attribute types. If this is specified
00737                                     then we only consider factoring out  those attributes
00738                                     which have a type which is in this set. 
00739     Outputs:    -
00740     Returns:    -
00741     Purpose:    This is a helper function for FactorOutCommonChildAttributes. It finds all 
00742                 attributes which are common to all children of this compound object and 
00743                 adds the common attributes to this node. If Global is TRUE then it recursivly
00744                 tries to factor out the attributes on all parent compounds. This function
00745                 does not delete the attributes which are factored out, This is left to
00746                 the calling function.
00747 
00748     Errors:     -
00749     SeeAlso:    -
00750 
00751 ********************************************************************************************/
00752 
00753 BOOL NodeRenderableInk::FactorOutCommonChildAttrHelper(BOOL Global, AttrTypeSet* pAffectedAttrTypes)
00754 {
00755     // This function should only ever get called on a compound object
00756     ENSURE(IsCompound(), "FactorOutCommonChildAttributes called on a non compound object"); 
00757 
00758     CommonAttrSet CommonAttributeSet; // A list of CommonAttributeItems
00759     
00760     if (!FindCommonAttributesToFactorOut(&CommonAttributeSet))   // Ignores attr discard nodes
00761     {
00762         return FALSE;  
00763     } 
00764     
00765     NodeAttribute* pFactoredOutAttr;
00766 
00767     // Ok let's add the common attributes to the first child of the group 
00768     CommonAttributeItem* pCommonAttr; 
00769     for (pCommonAttr = (CommonAttributeItem*)CommonAttributeSet.GetHead();
00770          pCommonAttr != NULL;
00771          pCommonAttr = (CommonAttributeItem*)CommonAttributeSet.GetNext(pCommonAttr)) 
00772     {
00773         // Is the common attribute an attribute which should be factored out ?
00774         if (!pAffectedAttrTypes || (pAffectedAttrTypes->InSet(pCommonAttr->pAttr->GetAttributeType())) )
00775         {
00776             //pCommonAttr->pAttr->MoveNode(this, FIRSTCHILD);    
00777             // Take a copy of the node and insert it as a first child
00778             pFactoredOutAttr = (NodeAttribute*)(pCommonAttr->pAttr->SimpleCopy());
00779             if (!pFactoredOutAttr)
00780                 return FALSE; 
00781             pFactoredOutAttr->AttachNode(this, FIRSTCHILD, TRUE, FALSE);
00782         }  
00783     }
00784 
00785     // The CommonAttributeSet is no longer required
00786     CommonAttributeSet.DeleteAll(); 
00787 
00788     // Do we need to factor out the parents attributes ?
00789     if (Global)
00790     {
00791         Node* pParent = FindParent();
00792         if (pParent && (pParent->IsCompound()))
00793         {
00794             // We need to localise the parent's attributes first  (Recursive bit)
00795             if (!(((NodeRenderableInk*)pParent)->FactorOutCommonChildAttrHelper(TRUE, pAffectedAttrTypes)))
00796             {
00797                 return FALSE; // Failed
00798             } 
00799         }
00800     }
00801     return TRUE; // Success
00802 }
00803 
00804 
00805 /********************************************************************************************
00806 
00807 >   BOOL NodeRenderableInk::LocaliseCommonAttributes(BOOL CheckForDuplicates = FALSE, 
00808                                                      BOOL Global = FALSE, 
00809                                                      AttrTypeSet* pAffectedAttrTypes = NULL,
00810                                                      BOOL RecursiveForChildren = FALSE); 
00811 
00812     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00813     Created:    4/8/94
00814     
00815     Inputs:     CheckForDuplicates: This should be TRUE if the children of this compound 
00816                                     node could have child attributes with the same
00817                                     type as the compound's attributes. This should never
00818                                     be the case.
00819 
00820                 Global: TRUE indicates that we should localise the attributes on all
00821                         parent compound nodes (top down), before localising the attributes for
00822                         this compound.
00823 
00824     
00825                 pAffectedAttrTypes: An optional set of attribute types. If this is specified
00826                                     then we only consider localising  those attributes
00827                                     which have a type which is in this set. 
00828                 RecursiveForChildren: Passed onto the helper function, means that if we have children
00829                                      who are compound then they will have LocaliseCommonAttrs called on
00830                                      them also
00831     Outputs:    -
00832     Returns:    TRUE if successful
00833                 FALSE if we run out of memory, in this situation the NodeRenderableInk is left unchanged
00834 
00835     Purpose:    This function is the opposite of the FactorOutCommonChildAttributes function
00836                 it copies all attributes common to the compound to each child object within the
00837                 compound which requires each attribute. The groups common attributes are deleted.
00838 
00839                 The routine does not localise attributes on objects which can discard their child
00840                 attributes (like the caret)
00841             
00842     Errors:     -
00843     SeeAlso:    NodeRenderableInk::FactorOutCommonChildAttributes
00844 
00845 ********************************************************************************************/
00846 
00847 BOOL NodeRenderableInk::LocaliseCommonAttributes(BOOL CheckForDuplicates,  
00848                                                  BOOL Global,
00849                                                  AttrTypeSet* pAffectedAttrTypes,
00850                                                  BOOL RecursiveForChildren) 
00851 {
00852     // This function should only ever get called on a compound object
00853     ENSURE(IsCompound(), "LocaliseCommonAttributes called on a non compound object"); 
00854     
00855     // First of all let's try and localise the attributes. This is the bit that can fail
00856     if (!LocaliseCommonAttrHelper(CheckForDuplicates, Global, pAffectedAttrTypes, RecursiveForChildren))
00857     {
00858         // We ran out of memory so we must, delete all attributes which were localised
00859         DeleteFactoredOutAttribs(Global, pAffectedAttrTypes); 
00860         return FALSE; 
00861     }
00862     else
00863     {
00864         // We managed to localise all the attributes so it is now safe to delete
00865         // them from the compounds.
00866         DeleteLocalisedAttributes(Global, pAffectedAttrTypes); 
00867         return TRUE;
00868     }
00869 }
00870 
00871 /********************************************************************************************
00872 
00873 >   BOOL NodeRenderableInk::LocaliseCommonAttrHelper(BOOL CheckForDuplicates, 
00874                                                      BOOL Global, 
00875                                                      AttrTypeSet* pAffectedAttrTypes,
00876                                                      BOOL RecursiveDownwards)
00877 
00878 
00879     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00880     Created:    16/5/95
00881     
00882     Inputs:     CheckForDuplicates: This should be TRUE if the children of this compound 
00883                                     node could have child attributes with the same
00884                                     type as the compound's attributes. This should never
00885                                     be the case.
00886 
00887                 Global: TRUE indicates that we should localise the attributes on all
00888                         parent compound nodes (top down), before localising the attributes for
00889                         this compound.
00890 
00891     
00892                 pAffectedAttrTypes: An optional set of attribute types. If this is specified
00893                                     then we only consider localising  those attributes
00894                                     which have a type which is in this set. 
00895                 RecursiveDownwards: Passed on to the attribute helper, means that if we have a child
00896                                     who is also compound then we will also localise their attributes.
00897                                     Defaults to FALSE.
00898 
00899     Outputs:    -
00900     Returns:    TRUE if successful
00901                 FALSE if we run out of memory, the localised attributes are not deleted
00902                 in this function.
00903 
00904     Purpose:    This function copies all attributes common to the compound to each child object 
00905                 within the compound which requires each attribute. 
00906 
00907                 The routine does not localise attributes on objects which can discard their child
00908                 attributes (like the caret)
00909                 
00910 
00911     Scope:      private
00912 
00913     SeeAlso:    NodeRenderableInk::LocaliseCommonAttributes
00914 
00915 ********************************************************************************************/
00916 
00917 
00918 BOOL NodeRenderableInk::LocaliseCommonAttrHelper(BOOL CheckForDuplicates,
00919                                                  BOOL Global,
00920                                                  AttrTypeSet* pAffectedAttrTypes,
00921                                                  BOOL RecursiveForChildren)
00922 {
00923     // Do we need to globally optimise ?
00924     if (Global)
00925     {
00926         Node* pParent = FindParent(); 
00927         if (pParent && (pParent->IsCompound()))
00928         {
00929             // We need to localise the parent's attributes first  (Recursive bit)
00930             if (!(((NodeRenderableInk*)pParent)->LocaliseCommonAttrHelper(CheckForDuplicates, TRUE, pAffectedAttrTypes)))
00931             {
00932                 return FALSE; // Failed
00933             } 
00934         }
00935     }
00936                
00937     // add all necessary attrs to each child object in the group
00938     for (Node* Current=FindFirstChild(); Current!=NULL; Current=Current->FindNext())
00939     {
00940         if (RecursiveForChildren && Current->IsCompound())
00941             ((NodeRenderableInk*)Current)->LocaliseCommonAttributes(FALSE, FALSE, NULL, TRUE);
00942     
00943         if (Current->IsAnObject())
00944         {
00945             NodeRenderableInk* pObject = (NodeRenderableInk*)Current;
00946             BOOL ChkForDups = CheckForDuplicates;
00947             Node* pRoot = RecursiveForChildren ? NULL : this;
00948             if(!pObject->MakeAttributeComplete(pRoot,ChkForDups,pAffectedAttrTypes))    
00949                 return FALSE;   // out of memory
00950         }
00951     }
00952 
00953     return TRUE; 
00954 }
00955 
00956 /********************************************************************************************
00957 
00958 >   void NodeRenderableInk::DeleteLocalisedAttributes(BOOL Global = FALSE 
00959                                                       AttrTypeSet* pAffectedAttrTypes)
00960 
00961     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00962     Created:    16/5/95
00963     
00964     Inputs:     Global: TRUE indicates that we should delete the attributes on all
00965                         parent compound nodes as well as this node's attributes
00966 
00967     
00968                 pAffectedAttrTypes: An optional set of attribute types. If this is specified
00969                                     then we only consider deleting  those attributes
00970                                     which have a type which is in this set.
00971 
00972     Scope:      private
00973 
00974     SeeAlso:    NodeRenderableInk::LocaliseCommonAttributes
00975 
00976 ********************************************************************************************/
00977 
00978 void NodeRenderableInk::DeleteLocalisedAttributes(BOOL Global,
00979                                                   AttrTypeSet* pAffectedAttrTypes )
00980 {
00981     // Do we need to delete any parent compound's attributes
00982     if (Global)
00983     {
00984         Node* pParent = FindParent(); 
00985         if (pParent && pParent->IsCompound())
00986         {
00987             // We need to localise the parent's attributes first  (Recursive bit)
00988             ((NodeRenderableInk*)pParent)->DeleteLocalisedAttributes(Global, pAffectedAttrTypes); 
00989         }
00990     }
00991 
00992 
00993     // Delete all moved attributes
00994     Node* Next; 
00995     Node* Current = FindFirstChild();
00996     while (Current != NULL && !Current->IsAnObject())
00997     {
00998         Next = Current->FindNext(); 
00999         if (Current->IsAnAttribute())
01000         {
01001             BOOL DeleteAttr = TRUE;
01002             if (pAffectedAttrTypes)
01003             {
01004                 // Only delete the attribute if it has been localised
01005                 if (!(pAffectedAttrTypes->InSet(((NodeAttribute*)Current)->GetAttributeType())))
01006                     DeleteAttr = FALSE;  
01007             }
01008             if (DeleteAttr)
01009             {
01010                 // Die
01011                 // Ilan 19/04/00
01012                 // More generally speaking, all attributes which returned FALSE in their ShouldBeOptimized()
01013                 // calls, will not have been localised to the child nodes during DoLocaliseCommonAttributes().
01014                 // Hence don't want to delete these attributes, they must remain attached to the group node
01015                 // which we are ungrouping so that they are present on an UNDO of a OpUngroup
01016                 // Attributes in this category include Feather attibutes and TemplateAttributes at present
01017 //              if (!Current->IsKindOf(CC_RUNTIME_CLASS(TemplateAttribute)))
01018                 if( ((NodeAttribute*)Current)->ShouldBeOptimized())
01019                 {
01020                     Current->CascadeDelete(); 
01021                     delete Current;
01022                 }
01023             }   
01024         }
01025         Current = Next; 
01026     }
01027 }
01028  
01029 /********************************************************************************************
01030 
01031 >   void NodeRenderableInk::DeleteFactoredOutAttribs(BOOL Global = FALSE 
01032                                                      AttrTypeSet* pAffectedAttrTypes)
01033 
01034     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01035     Created:    16/5/95
01036     
01037     Inputs:     Global: TRUE indicates that we should delete the attributes on all
01038                         parent compound nodes as well as this node's attributes
01039 
01040     
01041                 pAffectedAttrTypes: An optional set of attribute types. If this is specified
01042                                     then we only consider deleting  those attributes
01043                                     which have a type which is in this set.
01044 
01045 
01046     Purpose:    Deletes all child attributes of objects within the compound, which are defined
01047                 in the groups child attribute block. The attributes of objects which discard
01048                 their child attributes (like the caret) are only deleted if they have the same value
01049     Scope:      private
01050 
01051 ********************************************************************************************/
01052 
01053 void NodeRenderableInk::DeleteFactoredOutAttribs(BOOL Global, AttrTypeSet* pAffectedAttrTypes)
01054 {
01055     Node* pGroupNode = FindFirstChild(); 
01056     while(pGroupNode!=NULL)
01057     {
01058         // Karim 30/08/2000
01059         // Non-optimisable attributes, like feathers and names,
01060         // must not be automatically deleted - only automatically delete optimisable ones.
01061         if (pGroupNode->IsAnAttribute() && ((NodeAttribute*)pGroupNode)->ShouldBeOptimized())
01062         {
01063             NodeAttribute* pGroupAttr = (NodeAttribute*)pGroupNode;
01064             CCRuntimeClass* GrouptAttrType = pGroupAttr->GetAttributeType();
01065             if (pAffectedAttrTypes==NULL || pAffectedAttrTypes->InSet(GrouptAttrType))
01066             {
01067                 // delete this group attr type from all child objects of this group
01068                 // BUT if obj discards child attrs only delete attr if it also has same value
01069                 for (Node* pNode=FindFirstChild(); pNode!=NULL; pNode=pNode->FindNext())
01070                 {
01071                     if (pNode->IsAnObject())
01072                     {
01073                         NodeRenderableInk* pObject = (NodeRenderableInk*)pNode;
01074                         NodeAttribute* pDeadAttr = pObject->GetChildAttrOfType(GrouptAttrType);
01075                         if (pDeadAttr!=NULL)
01076                         {
01077                             // This code used to only test the attribute for equality if pObject
01078                             // returned TRUE from DiscardsAttributeChildren, otherwise it would 
01079                             // just assume that they are identical and delete it.
01080                             // The DiscardAttributeChildren checks are now done elsewhere so 
01081                             // this code now just assumes it can delete any attributes that have 
01082                             // got this far.
01083                             // This optimisation relies on the tree being in a "legal" state 
01084                             // at the start (i.e. correctly optimised) and also helps to correct 
01085                             // problems where attributes may have been incorrectly left on children
01086                             // (though such "corrections" may change the appearance of the document).
01087 
01088                             pDeadAttr->CascadeDelete(); 
01089                             delete pDeadAttr;   
01090                         }
01091                     }
01092                 }
01093             }
01094         }
01095         pGroupNode = pGroupNode->FindNext();        
01096     }
01097 
01098     // Do we need to delete any parent compound's attributes
01099     if (Global)
01100     {
01101         Node* pParent = FindParent(); 
01102         if (pParent && (pParent->IsCompound()))
01103         {
01104             // We need to delete the parent's attributes first  (Recursive bit)
01105             ((NodeRenderableInk*)pParent)->DeleteFactoredOutAttribs(Global, pAffectedAttrTypes); 
01106         }
01107     }
01108 } 
01109 
01110 
01111 /********************************************************************************************
01112 
01113 >   BOOL Node::OptimiseAttributes()
01114 
01115     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01116     Created:    8/8/94
01117     Inputs:     -
01118     Outputs:    -
01119     Returns:    -
01120     Purpose:    This function should be called on a subtree
01121     Errors:     -
01122     SeeAlso:    -
01123 
01124 ********************************************************************************************/
01125 
01126 
01127 BOOL Node::OptimiseAttributes()
01128 {
01129     Node* Current= this->FindFirstDepthFirst(); 
01130 
01131     while (Current != NULL)
01132     {
01133         if (Current->IsCompound())
01134         {
01135             ENSURE(Current->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableInk)), "Compound should be a NodeRenderableInk");
01136             // It's a compound node, so factor out common attributes
01137             // We don't want to attribute inside moulds (as yet)
01138             if ( !((IS_A(Current, NodeMouldGroup)) || (IS_A(Current, NodeMoulder))) )
01139             {
01140                 if (!((NodeRenderableInk*)Current)->FactorOutCommonChildAttributes())
01141                 {
01142                     return FALSE; 
01143                 }
01144             }
01145         }
01146         Current = Current->FindNextDepthFirst(this); 
01147     }
01148 
01149     return TRUE; 
01150 }
01151     
01152 //------------------------------------------------------------------------------------------
01153 // FactorOutCommonChildAttrAct methods
01154     
01155 /********************************************************************************************
01156 
01157 >   FactorOutCommonChildAttrAct::FactorOutCommonChildAttrAct()
01158 
01159     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01160     Created:    16/8/93
01161     Inputs:     -
01162     Outputs:    -
01163     Returns:    -
01164     Purpose:    FactorOutCommonChildAttrAct constructor
01165     Errors:     -
01166     SeeAlso:    -
01167 
01168 ********************************************************************************************/
01169     
01170     
01171 FactorOutCommonChildAttrAct::FactorOutCommonChildAttrAct()
01172 {
01173 }   
01174 
01175 /********************************************************************************************
01176 
01177 >   ActionCode FactorOutCommonChildAttrAct::Execute()
01178 
01179     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01180     Created:    16/8/93
01181     Inputs:     -
01182     Outputs:    ActionCode indicating if the action was successfully executed or not
01183     Returns:    -
01184     Purpose:    Executes the FactorOutCommonChildAttrAct which factors out all attributes 
01185                 which are common to all children of the compound object. All common attributes 
01186                 become first children of the compound object.
01187     Errors:     -
01188     SeeAlso:    LocaliseCommonAttrAct
01189                                                         
01190     
01191 ********************************************************************************************/
01192 
01193 ActionCode FactorOutCommonChildAttrAct::Execute()
01194 {
01195     LocaliseCommonAttrAct* NewAct;  
01196     ActionCode ActCode;  
01197 
01198     // Attempt to initialise the LocaliseCommonAttrAct action which will localise the attributes
01199     if ((ActCode = LocaliseCommonAttrAct::Init(pOperation,                    
01200                                                pOppositeActLst,  
01201                                                CompoundObj,
01202                                                Global,  
01203                                                pSetOfAffectedAttrTypes,
01204                                                ( Action**)(&NewAct))) != AC_FAIL) 
01205     { 
01206         if (!CompoundObj->FactorOutCommonChildAttributes(Global, pSetOfAffectedAttrTypes))
01207         {
01208             return AC_FAIL; 
01209         }                   
01210     }             
01211     return (ActCode);                        
01212 }    
01213 
01214 /********************************************************************************************
01215 
01216 >   static ActionCode FactorOutCommonChildAttrAct::Init(Operation* const pOp, 
01217                                                         ActionList* pActionList,
01218                                                         NodeRenderableInk* pCompound,
01219                                                         BOOL Global, 
01220                                                         AttrTypeSet* pAffectedAttrTypes, 
01221                                                         Action** NewAction); 
01222 
01223     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01224     Created:    14/9/93  
01225     
01226     Inputs:     pOp: The operation to which the action should be added
01227                 
01228                 pActionList: The action list in the operation object
01229 
01230                 pCompound:   The compound object
01231 
01232                 Global: When TRUE the attributes on all parent compounds are also
01233                         factored out.
01234 
01235                 pAffectedAttrTypes: An optional set of attribute types. If this is specified
01236                                     then we only consider factoring out  those attributes
01237                                     which have a type which is in this set. 
01238 
01239 
01240     Outputs:    NewAction:   A pointer to the action if it could be allocated. 
01241 
01242     Returns:    AC_FAIL:     There was not enough room in the operation history for the 
01243                              action and the user did not wish to continue. Usually 
01244                              End() should be called in this situation. 
01245                          
01246                 AC_NORECORD: There was not enough room in the operation history for
01247                              the action, but the user requested that he wished to 
01248                              continue without undo. 
01249                 
01250                 AC_OK      : The action was successfully initialised and added to the 
01251                              operation. 
01252                          
01253                            
01254     Purpose:    To check that there is sufficient room for the action in the operation
01255                 history, and if there is, then to add the action to the operations 
01256                 action list. 
01257                 
01258                 The function calls the Action::Init function passing the runtime class 
01259                 of a FactorOutCommonChildAttrAct.
01260     Errors:     -
01261     SeeAlso:    Action::Init
01262 
01263 ********************************************************************************************/
01264 
01265 ActionCode FactorOutCommonChildAttrAct::Init(Operation* const pOp, 
01266                            ActionList* pActionList,
01267                            NodeRenderableInk* pCompound,
01268                            BOOL global, 
01269                            AttrTypeSet* pAffectedAttrTypes, 
01270                            Action** NewAction) 
01271 
01272 {  
01273     ActionCode Ac = (Action::Init(pOp,
01274                      pActionList,
01275                      sizeof(FactorOutCommonChildAttrAct), 
01276                      CC_RUNTIME_CLASS(FactorOutCommonChildAttrAct), 
01277                      NewAction)); 
01278 
01279     if (*NewAction != NULL) 
01280     {
01281         ((FactorOutCommonChildAttrAct*)(*NewAction))->CompoundObj = pCompound;
01282         ((FactorOutCommonChildAttrAct*)(*NewAction))->pSetOfAffectedAttrTypes = pAffectedAttrTypes;
01283         ((FactorOutCommonChildAttrAct*)(*NewAction))->Global = global;
01284     }
01285                   
01286     return (Ac); 
01287 } 
01288 
01289 /********************************************************************************************
01290 
01291 >   virtual void FactorOutCommonChildAttrAct::Slaughter()
01292 
01293     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01294     Created:    24/05/95
01295     Inputs:     -
01296     Outputs:    -
01297     Returns:    -
01298     Purpose:    destructor which gets called when an operation is deleted  
01299     Errors:     -
01300     SeeAlso:    Action::Slaughter
01301 
01302 ********************************************************************************************/
01303 
01304 void FactorOutCommonChildAttrAct::Slaughter() 
01305 {         
01306     // Destroy the set of attribute types
01307     if (pSetOfAffectedAttrTypes)
01308     {
01309         pSetOfAffectedAttrTypes->DeleteAll(); 
01310         delete pSetOfAffectedAttrTypes;
01311     }
01312 
01313     // call the base class to destroy the action
01314     Action::Slaughter();
01315 }   
01316 
01317 
01318 //------------------------------------------------------------------------------------------
01319 // LocaliseCommonAttrAct methods
01320     
01321 /********************************************************************************************
01322 
01323 >   LocaliseCommonAttrAct::LocaliseCommonAttrAct()
01324 
01325     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01326     Created:    16/8/93
01327     Inputs:     -
01328     Outputs:    -
01329     Returns:    -
01330     Purpose:    LocaliseCommonAttrAct constructor
01331     Errors:     -
01332     SeeAlso:    -
01333 
01334 ********************************************************************************************/
01335     
01336     
01337 LocaliseCommonAttrAct::LocaliseCommonAttrAct()
01338 {
01339 }   
01340 
01341 /********************************************************************************************
01342 
01343 >   ActionCode LocaliseCommonAttrAct::Execute()
01344 
01345     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01346     Created:    16/8/93
01347     Inputs:     -
01348     Outputs:    ActionCode indicating if the action was successfully executed or not
01349     Returns:    -
01350     Purpose:    Executes the LocaliseCommonAttrAct which copies all attributes common to the 
01351                 compound object to each child object within the group which requires each 
01352                 attribute. The groups common attributes are deleted.
01353     Errors:     -
01354     SeeAlso:    FactorOutCommonChildAttrAct
01355                                                         
01356     
01357 ********************************************************************************************/
01358 
01359 ActionCode LocaliseCommonAttrAct::Execute()
01360 {
01361     FactorOutCommonChildAttrAct* NewAct;  
01362     ActionCode ActCode;  
01363 
01364     // Attempt to initialise the FactorOutCommonChildAttrAct action
01365     if ((ActCode = FactorOutCommonChildAttrAct::Init(pOperation,                    
01366                                                pOppositeActLst,  
01367                                                CompoundObj, 
01368                                                Global,
01369                                                pSetOfAffectedAttrTypes,
01370                                                ( Action**)(&NewAct))) != AC_FAIL) 
01371     { 
01372         if (!CompoundObj->LocaliseCommonAttributes(TRUE,    // Always check for duplicates when undoing
01373                                                    Global, 
01374                                                    pSetOfAffectedAttrTypes))
01375         {
01376             return AC_FAIL; 
01377         }                   
01378     }             
01379     return (ActCode);                        
01380 }    
01381 
01382 /********************************************************************************************
01383 
01384 >   static ActionCode LocaliseCommonAttrAct::Init(Operation* const pOp, 
01385                                                         ActionList* pActionList,
01386                                                         NodeRenderableInk* pCompound,
01387                                                         BOOL Global, 
01388                                                         AttrTypeSet* pAffectedAttrTypes, 
01389                                                         Action** NewAction); 
01390 
01391     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01392     Created:    14/9/93  
01393     
01394     Inputs:     pOp: The operation to which the action should be added
01395                 
01396                 pActionList: The action list in the operation object
01397 
01398                 pCompound:   The compound object
01399 
01400                 
01401                 Global: TRUE indicates that we should localise the attributes on all
01402                         parent compound nodes (top down), before localising the attributes for
01403                         this compound.
01404 
01405 
01406                 pAffectedAttrTypes: An optional set of attribute types. If this is specified
01407                                     then we only consider localising those attributes
01408                                     which have a type which is in this set. 
01409 
01410 
01411     Outputs:    NewAction:   A pointer to the action if it could be allocated. 
01412 
01413     Returns:    AC_FAIL:     There was not enough room in the operation history for the 
01414                              action and the user did not wish to continue. Usually 
01415                              End() should be called in this situation. 
01416                          
01417                 AC_NORECORD: There was not enough room in the operation history for
01418                              the action, but the user requested that he wished to 
01419                              continue without undo. 
01420                 
01421                 AC_OK      : The action was successfully initialised and added to the 
01422                              operation. 
01423                          
01424                            
01425     Purpose:    To check that there is sufficient room for the action in the operation
01426                 history, and if there is, then to add the action to the operations 
01427                 action list. 
01428                 
01429                 The function calls the Action::Init function passing the runtime class 
01430                 of a LocaliseCommonAttrAct.
01431     Errors:     -
01432     SeeAlso:    Action::Init
01433 
01434 ********************************************************************************************/
01435 
01436 ActionCode LocaliseCommonAttrAct::Init(Operation* const pOp, 
01437                            ActionList* pActionList,
01438                            NodeRenderableInk* pCompound,
01439                            BOOL global, 
01440                            AttrTypeSet* pAffectedAttrTypes,
01441                            Action** NewAction) 
01442 
01443 {  
01444     ActionCode Ac = (Action::Init(pOp,
01445                      pActionList,
01446                      sizeof(LocaliseCommonAttrAct), 
01447                      CC_RUNTIME_CLASS(LocaliseCommonAttrAct), 
01448                      NewAction)); 
01449 
01450     if (*NewAction != NULL) 
01451     {
01452         ((LocaliseCommonAttrAct*)(*NewAction))->CompoundObj = pCompound;
01453         ((LocaliseCommonAttrAct*)(*NewAction))->Global = global;
01454         ((LocaliseCommonAttrAct*)(*NewAction))->pSetOfAffectedAttrTypes = pAffectedAttrTypes;
01455 
01456     }
01457                   
01458     return (Ac); 
01459 }   
01460 
01461 
01462 /********************************************************************************************
01463 
01464 >   virtual void LocaliseCommonAttrAct::Slaughter()
01465 
01466     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01467     Created:    24/05/95
01468     Inputs:     -
01469     Outputs:    -
01470     Returns:    -
01471     Purpose:    destructor which gets called when an operation is deleted  
01472     Errors:     -
01473     SeeAlso:    Action::Slaughter
01474 
01475 ********************************************************************************************/
01476 
01477 void LocaliseCommonAttrAct::Slaughter() 
01478 {         
01479     // Destroy the set of attribute types
01480     if (pSetOfAffectedAttrTypes)
01481     {
01482         pSetOfAffectedAttrTypes->DeleteAll(); 
01483         delete pSetOfAffectedAttrTypes;
01484     }
01485 
01486     // call the base class to destroy the action
01487     Action::Slaughter();
01488 }   

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