#include <undoop.h>
Inheritance diagram for UndoableOperation:
Public Member Functions | |
BOOL | DoInvalidateNodesRegions (Range NodeRange, BOOL IncludeBlobs, BOOL UndoBlobs=FALSE, BOOL IfBgRedraw=FALSE, BOOL bForceRecache=TRUE) |
This low level Do function invalidates a region which is the union of the bounding rectangles of each node in the range. When the includeBlobs flag is TRUE the region which gets invalidated includes the objects blobs. | |
BOOL | DoInvalidateNodeRegion (NodeRenderableBounded *Node, BOOL IncludeBlobs, BOOL UndoBlobs=FALSE, BOOL IfBgRedraw=FALSE, BOOL bForceRecache=TRUE) |
Invalidates the nodes bounding rectangle, or blob bounding rectangle. | |
BOOL | DoInvalidateRegion (Spread *pSpread, const DocRect &InvalidRegion) |
Invalidates the region specified and adds the appropriate action to the action list for the current operation. If you are invalidating a region associated with a node in the tree then you should be using DoInvalidateNodeRegion() or DoInvalidateNodesRegion(). | |
BOOL | DoSaveCopyOfNode (NodeRenderable *Node) |
This fn saves a copy of the node in the operation history. When the operation is undone the copy is restored. | |
BOOL | DoSaveCopyOfNodes (Range NodeRange) |
This fn takes a copy of the nodes in the range. The copies are restored when the operation is undone. | |
BOOL | DoHideNode (Node *NodeToHide, BOOL IncludeSubtreeSize, NodeHidden **nodeHidden=NULL, BOOL TellSubtree=TRUE) |
This low level Do function hides the subtree with root NodeToHide. | |
BOOL | DoHideNodes (Range NodeRange, BOOL IncludeSubtreeSize, BOOL TellSubtree=TRUE) |
This low level Do function hides a range of the subtrees. | |
BOOL | DoHideComplexRange (Range &RangeToHide) |
This function is a pre process to DoHideNodes(). It calls each object in the range to hide themselves in a complex way. It may be that no objects in the selection require this facility, which means the RangeToHide object will be returned from this function unaffected. DoHideNodes() will then go through hidding all nodes in the range itself. If however a node responds to ComplexHide() and hides itself, the node will be removed from the range. This allows complex group nodes to control how they are hidden. Note, it is expected that ComplexHide() responders will hide nodes themselves This will have the automatic effect of removing them from the range. Hidden nodes do not appear in ranges. | |
BOOL | DoInsertNewNode (NodeRenderableBounded *NewNode, Spread *pSpread, BOOL InvalidateRgn, BOOL ClearSelection=TRUE, BOOL SelectNewObject=TRUE, BOOL NormaliseAttributes=TRUE) |
Inserts the node as a last child of the active layer of the pSpread. If the NewNode is a NodeRenderableInk then the node becomes selected and all other nodes are deselected. If pSpread is NULL then the object is inserted on the selected spread. | |
BOOL | DoInsertNewNode (NodeRenderableBounded *NewNode, Node *ContextNode, AttachNodeDirection Direction, BOOL InvalidateRegion, BOOL ClearSelection=TRUE, BOOL SelectNewObject=TRUE, BOOL NormaliseAttributes=TRUE) |
This high level do function attaches the node to ContextNode in the direction specified. If the NewNode is a NodeRenderableInk then the node becomes selected and all other nodes are deselected. | |
BOOL | DoMoveNode (Node *MoveNode, Node *Destination, AttachNodeDirection Direction) |
This high level function moves NodeToMove from its current position in the tree, and attaches it to Destination in the direction specified by Direction. | |
BOOL | DoMoveNodes (Range NodeRange, Node *Destination, AttachNodeDirection Direction) |
This high level function moves the range of nodes from their current position in the tree, and attaches them to the Destination node in the direction specified by Direction. | |
BOOL | DoTransformNode (NodeRenderableInk *NodeToTransform, TransformBase *T) |
This high level Do function applies the transform Trans to the NodeToTransform. | |
BOOL | DoTransformNodes (Range NodeRange, TransformBase *T) |
This high level Do function applies the transform Trans to each object in the range. | |
BOOL | DoMakeShapes (Range NodeRange) |
This low level Do function calls the DoBecomeA virtual function on all SelectedNodes. It is the node's DoBecomeA function which is responsible for generating actions. | |
BOOL | DoFlattenRange (Range NodeRange) |
Not implemented yet. | |
BOOL | DoCopyNodesToClipboard (Range NodeRange) |
This Do function copies all nodes in the range to the internal clipboard. The objects are made attribute complete prior to being moved. | |
BOOL | DoRemoveAttrTypeFromSubtree (Node *Subtree, CCRuntimeClass *NodeClass, Node *pExceptThis=NULL) |
Searches the subtree and every attribute which has type AttrType is hidden. | |
BOOL | DoChangeSelection (NodePath *ThisNode, INT32 Index, BOOL NewState) |
This 'Do' function changes the selected state of a particular element in a path it creates all the necessary undo information so that the selection can be undone. | |
BOOL | DoDeletePathSection (NodePath *ThisNode, INT32 Index, INT32 NumElements, BOOL RedrawPath=TRUE) |
This 'Do' function changes the selected state of a particular element in a path it creates all the necessary undo information so that the selection can be undone. | |
BOOL | DoAlterPathElement (NodePath *ThisNode, INT32 Index, DocCoord NewCoord, PathFlags NewFlags, PathVerb NewVerb, BOOL RedrawPath=TRUE) |
This 'Do' function changes the selected element, recording undo information. | |
BOOL | DoInsertPathElement (NodePath *ThisPath, INT32 Index, DocCoord NewCoord, PathFlags NewFlags, PathVerb NewVerb, BOOL RedrawPath=TRUE) |
This 'Do' function adds an element into a path, recording undo information. | |
BOOL | DoReversePath (NodePath *ThisPath, BOOL RedrawPath=TRUE) |
This 'Do' function reverse a path, recording undo information. | |
BOOL | DoSmoothNodePath (NodePath *pThisNode, double smoothacc) |
This function will smooth a node path given an accuracy. It will create a new node in the tree after the node specified and hide node passed if all is succesfull. | |
BOOL | DoMakeNodeFromPath (NodePath *pParentNode, Path *pParentPath, AttachNodeDirection Direction, BOOL CopyAttributes) |
This functio will create a new nodepath and attach it in the specified direction to the context node specified. It will also copy attributes applied as children of the ConextNode to the new node if required. | |
BOOL | DoLocaliseForAttrChange (NodeRenderableInk *Object, AttrTypeSet *pAffectedAttrTypes, ObjectSet *pLocalisedCompounds) |
This Do function must be called on an object prior to a set of attributes being applied to it. It globally localises those attributes which have a type in the pAffectedAttrTypes set. | |
BOOL | DoLocaliseForAttrChange (NodeRenderableInk *Object, CCRuntimeClass *pAffectedAttrType, ObjectSet *pLocalisedCompounds) |
This Do function must be called on an object prior to an attribute being applied to it. If you are going to apply multiple attributes to the Object then it is more efficient to call the other version of this function which takes a set of attribute types. | |
BOOL | DoLocaliseForAttrChange (Range *pRange, AttrTypeSet *pAffectedAttrTypes, BOOL ExcludeTextObjects=FALSE) |
This Do function must be called on a range prior to a set of attributes being applied to it. It globally localises those attributes which have a type in the pAffectedAttrTypes set. | |
BOOL | DoLocaliseForAttrChange (Range *pRange, CCRuntimeClass *pAffectedAttrType) |
This Do function must be called on a range prior to an attribute being applied to it. If you are going to apply multiple attributes to the range then it is more efficient to call the other version of this function which takes a set of attribute types. | |
BOOL | DoFactorOutAfterAttrChange (NodeRenderableInk *Object, AttrTypeSet *pAffectedAttrTypes) |
This Do function must be called on an object after attributes have being applied to it. | |
BOOL | DoFactorOutAfterAttrChange (NodeRenderableInk *Object, CCRuntimeClass *pAffectedAttrType) |
This Do function must be called on an object after an attribute being applied to it. If you have applied multiple attributes to the Object then it is more efficient to call the other version of this function which takes a set of attribute types. | |
BOOL | DoFactorOutAfterAttrChange (Range *pRange, AttrTypeSet *pAffectedAttrTypes) |
This Do function must be called on the range after attributes have being applied to it. | |
BOOL | DoFactorOutAfterAttrChange (Range *pRange, CCRuntimeClass *pAffectedAttrType) |
This Do function must be called on the range after an attribute being applied to it. If you have applied multiple attributes to the range then it is more efficient to call the other version of this function which takes a set of attribute types. | |
BOOL | DoFactorOutAfterAttrChange (ObjectSet *pLocalisedCompounds, AttrTypeSet *pAffectedAttrTypes) |
This Do function is designed to be called after all attributes in the pAffectedAttrTypes set have been localised on all compound nodes in the pLocalisedCompounds set. | |
BOOL | DoFactorOutAfterAttrChange (ObjectSet *pLocalisedCompounds, CCRuntimeClass *pAffectedAttrType) |
This Do function is designed to be called after pAffectedAttrType has been localised on all compound nodes in the pLocalisedCompounds set. | |
BOOL | DoFactorOutCommonChildAttributes (NodeRenderableInk *CompoundObject, BOOL Global=FALSE, AttrTypeSet *pAffectedAttrTypes=NULL) |
This function is an information gatherer for the DoFactorOutAfterDeletion function. See this function for a full description of its purpose. Whenever we delete a range of objects, if any objects in the range have compound parents then we must adjust the common attributes on these compounds. This function factors out all attributes which are common to all children of the compound object. All common attributes become first children of the compound object. | |
BOOL | DoFactorOutCommonAttributes (NodeRenderableInk *pRootNode, BOOL bGlobal=FALSE, AttrTypeSet *pAffectedAttrTypes=NULL) |
Just a wrapper to get function name consistency and do the common IsCompound test to prevent DFOCCA from barfing... | |
BOOL | DoLocaliseCommonAttributes (NodeRenderableInk *CompoundObject, BOOL CheckForDuplicates=FALSE, BOOL Global=FALSE, AttrTypeSet *pAffectedAttrTypes=NULL) |
This function is the opposite of DoFactorOutCommonChildAttributes it copies all attributes common to the compound object to each child object within the group which requires each attribute. The groups common attributes are deleted. | |
BOOL | DoSelectNode (NodeRenderableInk *NodeToSelect, Spread *Parent=NULL) |
The function selects NodeToSelect. It also generates an action which will deselect the node when executed. | |
BOOL | DoDeselectNode (NodeRenderableInk *NodeToDeselect, Spread *Parent=NULL) |
The function de-selects NodeToDeselect. It also generates an action which will select the node when executed. | |
UndoableOperation () | |
Constructs a new undoable operation object:. | |
virtual | ~UndoableOperation () |
UndoableOperation destructor. | |
virtual void | PerformMergeProcessing () |
This function gets called from the Operation::EndOp method after the operation has ended successfuly and been added to the operation history. If the operation could potentially merge itself with the previous operation then perform this merging here. | |
void | MergeWithPrevious () |
Moves all the actions in this operation to the end of the previous action, then deletes this action. | |
virtual BOOL | UpdateChangedNodes (ObjChangeParam *pParam, Spread *pSpread=NULL) |
This function overrides its namesake in Operation, calling the base function first and then adding a call to NameGallery::PostTriggerEdit if this Op admits it may change the bounds of nodes within the tree. | |
virtual BOOL | NoStretchUpdateChangedNodes (ObjChangeParam *pParam, Document *pDoc) |
This is *not* an override of Operation::UpdateChangedNodes(..., Document*), although it performs *almost* exactly the same job. It is provided solely for NameGallery::PostTriggerEdit to call in order to get all affected nodes to update themselves correctly after a stretch. PostTriggerEdit is itself called in response to normal UpdateChangedNodes calls, so this avoids recursion problems. | |
virtual BOOL | MayChangeNodeBounds () const |
virtual BOOL | GetStarted () const |
Static Public Member Functions | |
static BOOL | RegisterOpDescriptor (UINT32 toolID, UINT32 txID, CCRuntimeClass *RuntimeClass, TCHAR *tok, pfnGetState gs, UINT32 helpId=0, UINT32 bubbleID=0, UINT32 resourceID=0, UINT32 controlID=0, SystemBarType GroupBarID=SYSTEMBAR_ILLEGAL, BOOL ReceiveMessages=TRUE, BOOL Smart=FALSE, BOOL Clean=FALSE, UINT32 OneOpenInstID=0, UINT32 AutoStateFlags=0) |
This function should be called from the operations Init method. It creates an OpDescriptor for the operation. | |
Static Public Attributes | |
static BOOL | MovingNode = FALSE |
Private Member Functions | |
Range * | IncludeParentTransformNodesInRange (Range *Rng) |
Transforms the node, checking if any parents need to transform too. | |
Private Attributes | |
BOOL | WarnInsertObjsOntoLockedLayers |
Definition at line 195 of file undoop.h.
|
Constructs a new undoable operation object:.
Definition at line 294 of file undoop.cpp. 00294 : Operation() 00295 { 00296 // This var is a flag that ensures that this warning will only appear once for the lifetime of this op 00297 WarnInsertObjsOntoLockedLayers = TRUE; 00298 }
|
|
UndoableOperation destructor.
Definition at line 317 of file undoop.cpp.
|
|
This 'Do' function changes the selected element, recording undo information.
Definition at line 2126 of file undoop.cpp. 02132 { 02133 #ifndef STANDALONE 02134 02135 // Here we're changing an element, so we have to change the element in the path, 02136 // recording undo information at the same time. 02137 ModifyElementAction* ModAction = NULL; 02138 02139 // Get pointers to all the arrays of the path 02140 PathVerb* Verbs = NULL; 02141 DocCoord* Coords = NULL; 02142 PathFlags* Flags = NULL; 02143 ThisPath->InkPath.GetPathArrays(&Verbs, &Coords, &Flags); 02144 02145 // Create an undo action for this action, which is a ModifyElementAction 02146 ActionCode Act; 02147 Act = ModifyElementAction::Init(this, 02148 &UndoActions, 02149 Verbs[Index], 02150 Flags[Index], 02151 Coords[Index], 02152 Index, 02153 ThisPath, 02154 (Action**)(&ModAction)); 02155 if (Act == AC_FAIL) 02156 return FALSE; 02157 02158 Document* pDocument = GetWorkingDoc(); 02159 ERROR2IF(pDocument == NULL, FALSE, "There was no Document when deleteing path elements"); 02160 Spread* pSpread = ThisPath->FindParentSpread(); 02161 ERROR2IF(pSpread == NULL, FALSE, "Path had no parent spread"); 02162 02163 // Force a re-draw of the place where the path used to be 02164 if (RedrawPath) 02165 { 02166 DocRect Invalid = ThisPath->GetUnionBlobBoundingRect(); 02167 // Mark the region as requiring object to recache any cached 02168 // data they may be holding because the Op may have changed it 02169 pDocument->ForceRedraw( pSpread, Invalid, FALSE, ThisPath ); 02170 } 02171 02172 // Update the coords 02173 Verbs[Index] = NewVerb; 02174 Flags[Index] = NewFlags; 02175 Coords[Index] = NewCoord; 02176 02177 // The bounding rect may have changed 02178 ThisPath->InvalidateBoundingRect(); 02179 02180 // redraw the new area 02181 if (RedrawPath) 02182 { 02183 // redraw the new area 02184 DocRect Invalid = ThisPath->GetUnionBlobBoundingRect(); 02185 // Mark the region as requiring object to recache any cached 02186 // data they may be holding because the Op may have changed it 02187 pDocument->ForceRedraw( pSpread, Invalid, FALSE, ThisPath ); 02188 } 02189 02190 #endif 02191 return TRUE; 02192 }
|
|
This 'Do' function changes the selected state of a particular element in a path it creates all the necessary undo information so that the selection can be undone.
Definition at line 1978 of file undoop.cpp. 01979 { 01980 #ifndef STANDALONE 01981 01982 ModifyFlagsAction* UnAction; 01983 PathFlags* Flags = ThisNode->InkPath.GetFlagArray(); 01984 if (Flags[Index].IsSelected != NewState) 01985 { 01986 ActionCode Act = ModifyFlagsAction::Init(this, 01987 &UndoActions, 01988 Flags[Index], 01989 Index, 01990 ThisNode, 01991 (Action**)&UnAction); 01992 if (Act == AC_FAIL) 01993 return FALSE; 01994 01995 Flags[Index].IsSelected = NewState; 01996 return TRUE; 01997 } 01998 01999 #endif 02000 02001 return TRUE; 02002 }
|
|
This Do function copies all nodes in the range to the internal clipboard. The objects are made attribute complete prior to being moved.
The nodes are then copied to the clipboard CopyComponentData is then called on each node which has been copied to allow component data to be copied to the clipboard. In the operations End method: If the operation has not failed then EndComponentCopy is called on each doc component do give them a chance to commit changes. If the operation has failed then AbortComponentCopy is called instead.
Definition at line 1830 of file undoop.cpp. 01831 { 01832 BOOL CopiedOK; 01833 BOOL ok; 01834 01835 InternalClipboard* pInternalClip = InternalClipboard::Instance(); 01836 01837 // After the operation ends we will need to inform all DocComponents in the clipboard 01838 // of the outcome. 01839 InformDocComponentsOfOperationsOutcome(pInternalClip); 01840 01841 01842 // Inform all DocComponents in the clipboard that a copy is about to take place 01843 CALL_WITH_FAIL(pInternalClip->StartComponentCopy(), this, ok) 01844 if (!ok) 01845 { 01846 // Start Component copy has failed so abort operation 01847 // Note that AbortComponentCopy will get called in the ops end method 01848 return FALSE; 01849 } 01850 01851 // Try to copy the selection to the clipboard 01852 CALL_WITH_FAIL(InternalClipboard::CopyObjects(NodeRange, this), this, CopiedOK) 01853 01854 if (!CopiedOK) 01855 { 01856 return FALSE; 01857 } 01858 01859 // Now try and copy accross the component data 01860 01861 CALL_WITH_FAIL(InternalClipboard::CopyComponentData(pOurDoc), this, CopiedOK) 01862 01863 if (!CopiedOK) 01864 { 01865 return FALSE; 01866 } 01867 01868 01869 // Create action, this action will do nothing for undo but it's twin redo action will 01870 // copy the selection to the clipboard. 01871 CopyObjectsToClipboardAction* UndoCopyObjectsToClipboardAction; 01872 01873 if ( CopyObjectsToClipboardAction::Init(this, 01874 &UndoActions, 01875 NodeRange, 01876 ( Action**)(&UndoCopyObjectsToClipboardAction)) == AC_FAIL) 01877 { 01878 return FALSE; // Failed to create action 01879 } 01880 return TRUE; // Success 01881 }
|
|
This 'Do' function changes the selected state of a particular element in a path it creates all the necessary undo information so that the selection can be undone.
Definition at line 2023 of file undoop.cpp. 02024 { 02025 #ifndef STANDALONE 02026 02027 InsertPathElementAction* UnAction = NULL; 02028 ActionCode Act; 02029 Act = InsertPathElementAction::Init(this, &UndoActions, NumElements, Index, 02030 (Action**)(&UnAction)); 02031 if (Act == AC_FAIL) 02032 return FALSE; 02033 02034 Document* pDocument = GetWorkingDoc(); 02035 ERROR2IF(pDocument == NULL, FALSE, "There was no Document when deleteing path elements"); 02036 Spread* pSpread = ThisPath->FindParentSpread(); 02037 ERROR2IF(pSpread == NULL, FALSE, "Path had no parent spread"); 02038 02039 // Force a re-draw of the place where the path used to be 02040 if (RedrawPath) 02041 { 02042 DocRect Invalid = ThisPath->GetUnionBlobBoundingRect(); 02043 // Mark the region as requiring object to recache any cached 02044 // data they may be holding because the Op may have changed it 02045 pDocument->ForceRedraw(pSpread, Invalid, FALSE, ThisPath); 02046 } 02047 02048 if ((Act != AC_NORECORD) && (UnAction != NULL)) 02049 { 02050 // I have to claim some memory to store the elements I'm deleting... 02051 PathVerb* ChangedVerbs = NULL; 02052 DocCoord* ChangedCoords = NULL; 02053 PathFlags* ChangedFlags = NULL; 02054 ALLOC_WITH_FAIL(ChangedVerbs,(PathVerb*) CCMalloc(NumElements * sizeof(PathVerb)),this); 02055 ALLOC_WITH_FAIL(ChangedCoords,(DocCoord*) CCMalloc(NumElements * sizeof(DocCoord)),this); 02056 ALLOC_WITH_FAIL(ChangedFlags,(PathFlags*) CCMalloc(NumElements * sizeof(PathFlags)),this); 02057 02058 if (!ChangedVerbs || !ChangedCoords || !ChangedFlags) 02059 { 02060 if (ChangedVerbs) CCFree(ChangedVerbs); 02061 if (ChangedCoords) CCFree(ChangedCoords); 02062 if (ChangedFlags) CCFree(ChangedFlags); 02063 return FALSE; 02064 } 02065 02066 // Get pointers to all the arrays of the path 02067 PathVerb* Verbs = NULL; 02068 DocCoord* Coords = NULL; 02069 PathFlags* Flags = NULL; 02070 ThisPath->InkPath.GetPathArrays(&Verbs, &Coords, &Flags); 02071 02072 // Now copy the data from the path into the arrays 02073 for (INT32 i=0;i<NumElements;i++) 02074 { 02075 ChangedVerbs[i] = Verbs[Index+i]; 02076 ChangedCoords[i] = Coords[Index+i]; 02077 ChangedFlags[i] = Flags[Index+i]; 02078 } 02079 02080 // Now pass these arrays to the Insert action 02081 UnAction->RecordPath(ChangedVerbs, ChangedFlags, ChangedCoords, ThisPath); 02082 } 02083 02084 // Now we've recorded the data we're about to delete, let's delete it 02085 ThisPath->InkPath.DeleteSection(Index, NumElements); 02086 02087 if (RedrawPath) 02088 { 02089 DocRect Invalid = ThisPath->GetUnionBlobBoundingRect(); 02090 // Accumulate this invalid region in a pending list until the Op 02091 // finishes 02092 // Mark the region as requiring object to recache any cached 02093 // data they may be holding because the Op may have changed it 02094 pDocument->ForceRedraw(pSpread, Invalid, FALSE, ThisPath); 02095 } 02096 02097 #endif 02098 return TRUE; 02099 }
|
|
The function de-selects NodeToDeselect. It also generates an action which will select the node when executed.
Definition at line 1733 of file undoop.cpp. 01734 { 01735 SelectDeselectAction* UndoSelectDeselectAction; 01736 // Create an action to deselect the NodeToSelect when we undo. 01737 if ( SelectDeselectAction::Init(this, 01738 &UndoActions, 01739 NodeToDeselect, 01740 Parent, 01741 (Action**)(&UndoSelectDeselectAction)) 01742 != AC_FAIL) 01743 { 01744 // We shall be able to select the object if we fail so deselect it. 01745 NodeToDeselect->DeSelect(FALSE); 01746 return (TRUE); 01747 } 01748 else 01749 return (FALSE); 01750 }
|
|
This Do function is designed to be called after pAffectedAttrType has been localised on all compound nodes in the pLocalisedCompounds set.
Before calling the function you should have localised the attribute by calling DoLocaliseForAttrChange.
Definition at line 3316 of file undoop.cpp. 03318 { 03319 ERROR3IF(!pLocalisedCompounds, "DoFactorOutAfterAttrChange called with a NULL compound set"); 03320 ERROR3IF(!pAffectedAttrType, "DoFactorOutAfterAttrChange called with a NULL attr type"); 03321 03322 03323 // Scan the range 03324 ObjectItem* pObjItem = (ObjectItem*)(pLocalisedCompounds->GetHead()); 03325 NodeRenderableInk* pCurrent; 03326 03327 // We need an attribute type set 03328 AttrTypeSet Set; 03329 03330 // Add the attributes type to the set 03331 if (!(Set.AddToSet(pAffectedAttrType))) 03332 { 03333 return FALSE; 03334 } 03335 03336 while (pObjItem) 03337 { 03338 pCurrent = pObjItem->pObject; 03339 ERROR3IF(!(pCurrent->IsCompound()), "Set should only contain compound objects"); 03340 if (pCurrent->IsCompound()) 03341 { 03342 if (!DoFactorOutCommonChildAttributes((NodeRenderableInk*)pCurrent, 03343 TRUE, // Global 03344 &Set)) 03345 { 03346 Set.DeleteAll(); 03347 return FALSE; 03348 } 03349 } 03350 pObjItem = (ObjectItem*)pLocalisedCompounds->GetNext(pObjItem); 03351 } 03352 03353 Set.DeleteAll(); 03354 return TRUE; 03355 }
|
|
This Do function is designed to be called after all attributes in the pAffectedAttrTypes set have been localised on all compound nodes in the pLocalisedCompounds set.
Before calling the function you should have localised the attribute by calling DoLocaliseForAttrChange.
Definition at line 3248 of file undoop.cpp. 03250 { 03251 ERROR3IF(!pLocalisedCompounds, "DoFactorOutAfterAttrChange called with a NULL compound set"); 03252 //ERROR3IF(!pAffectedAttrTypes, "DoFactorOutAfterAttrChange called with a NULL attr type set"); 03253 03254 // Scan the range 03255 ObjectItem* pObjItem = (ObjectItem*)(pLocalisedCompounds->GetHead()); 03256 NodeRenderableInk* pCurrent; 03257 03258 while (pObjItem) 03259 { 03260 pCurrent = pObjItem->pObject; 03261 ERROR3IF(!(pCurrent->IsCompound()), "Set should only contain compound objects"); 03262 if (pCurrent->IsCompound()) 03263 { 03264 if (!DoFactorOutCommonChildAttributes((NodeRenderableInk*)pCurrent, 03265 TRUE, // Global 03266 pAffectedAttrTypes)) 03267 { 03268 return FALSE; 03269 } 03270 } 03271 pObjItem = (ObjectItem*)pLocalisedCompounds->GetNext(pObjItem); 03272 } 03273 03274 return TRUE; 03275 03276 }
|
|
This Do function must be called on the range after an attribute being applied to it. If you have applied multiple attributes to the range then it is more efficient to call the other version of this function which takes a set of attribute types.
Before calling the function you should have localised the attribute by calling DoLocaliseForAttrChange. If an object in the range Discards its attribute children then its attributes are ignored when factoring (eg. the caret) Note: When applying an attribute, we are not always going to apply it to the object itself, sometimes we need to apply it to the object's parent. Eg. when we apply a line based attribute to a text character the attributes will get applied to the parent TextLine. In this situation we do not factor out the objects attributes, but its parents attributes instead. Note: When applying attributes, we are not always going to apply the attributes to the object itself, sometimes we need to apply them to the object's parent. Eg. when we apply a line based attribute to a text character the attributes will get applied to the parent TextLine. In this situation we do not factor out the object's attributes, but its parents attributes instead.
Definition at line 2740 of file undoop.cpp. 02742 { 02743 ERROR3IF(pRange->Count() == 0, "Range::DoFactorOutAfterAttrChange called on an empty range"); 02744 // Scan the range 02745 02746 // Iterate over the top of any liveeffects applied to the selection 02747 // Its important that this iteration matches those used in DoApplyAttribute functions 02748 // so that attributes are put in the places where mutation will find them 02749 ListRange* pLevel = EffectsStack::GetNewLevelRange(pRange, FALSE); // We DO own this range 02750 Node* pCurrent = pLevel->FindFirst(); 02751 02752 // There is no need to factor out the attributes on a compound more than once, so we 02753 // remember the last compound node which has had its attributes factored out 02754 NodeRenderableInk* pFactoredOutCompound = NULL; 02755 02756 Node* pParent; 02757 Node* pObject; 02758 while (pCurrent) 02759 { 02760 pObject = pCurrent; 02761 // Get the object that the attribute has been applied to 02762 ERROR3IF(!pAffectedAttrType, "AttrType is NULL"); 02763 pObject = ((NodeRenderableInk*)pObject)->GetObjectToApplyTo(pAffectedAttrType); 02764 02765 // If the object can discard its attribute children then we should not try to factor 02766 // out its attributes 02767 02768 { 02769 02770 // We only need to factor out attributes on nodes which have a compound parent 02771 pParent = pObject->FindParent(); 02772 ERROR3IF(pParent == NULL, "Range::DoFactorOutAfterAttrChange, node found without a parent"); 02773 02774 // Only factor out attribs if the parent has not already had its attribs factored out 02775 if ((pParent->IsCompound()) && (pParent != pFactoredOutCompound)) 02776 { 02777 // Attempt to localise the compound 02778 if (!DoFactorOutAfterAttrChange((NodeRenderableInk*)pObject, pAffectedAttrType)) 02779 { 02780 delete pLevel; 02781 return FALSE; 02782 } 02783 02784 pFactoredOutCompound = (NodeRenderableInk*)pParent; // Remember that it's been localised 02785 } 02786 } 02787 pCurrent = pLevel->FindNext(pCurrent); 02788 } 02789 02790 delete pLevel; 02791 return TRUE; 02792 }
|
|
This Do function must be called on the range after attributes have being applied to it.
Before calling the function you should have localised attributes by calling DoLocaliseForAttrChange. If an object in the range Discards its attribute children then its attributes are ignored when factoring (eg. the caret) Note: When applying attributes, we are not always going to apply the attributes to the object itself, sometimes we need to apply them to the object's parent. Eg. when we apply a line based attribute to a text character the attributes will get applied to the parent TextLine. In this situation we do not factor out the objects attributes, but its parents attributes instead. Warning ~~~~~~~ All attribute types in the AttrTypeSet must have been localised (and so need factoring out) on the same compound node. This means for example that the AttrType set cannot contain a Bold and a Line space attribute. If we need to do this in future then the routine will need to be changed.
Definition at line 2625 of file undoop.cpp. 02627 { 02628 ERROR3IF(pRange->Count() == 0, "Range::DoFactorOutAfterAttrChange called on an empty range"); 02629 02630 // Iterate over the top of any liveeffects applied to the selection 02631 // Its important that this iteration matches those used in DoApplyAttribute functions 02632 // so that attributes are put in the places where mutation will find them 02633 ListRange* pLevel = EffectsStack::GetNewLevelRange(pRange, FALSE); // We DO own this range 02634 Node* pCurrent = pLevel->FindFirst(); 02635 02636 // There is no need to factor out the attributes on a compound more than once, so we 02637 // remember the last compound node which has had its attributes factored out 02638 NodeRenderableInk* pFactoredOutCompound = NULL; 02639 02640 Node* pParent; 02641 Node* pObject; 02642 02643 while (pCurrent) 02644 { 02645 // If the object can discard its attribute children then we should not try to factor 02646 // out its attributes 02647 CCRuntimeClass* AttrType; 02648 02649 pObject = pCurrent; 02650 if (pAffectedAttrTypes && (!pAffectedAttrTypes->IsEmpty())) 02651 { 02652 AttrType = ((AttrTypeItem*)pAffectedAttrTypes->GetHead())->AttributeType; 02653 ERROR3IF(!AttrType, "AttrType set contains NULL attribute type"); 02654 pObject = ((NodeRenderableInk*)pObject)->GetObjectToApplyTo(AttrType); 02655 } 02656 02657 // DY added test for NULL, which can occur with bevels 02658 if ((pObject != NULL)) 02659 { 02660 // We only need to factor out attributes on nodes which have a compound parent 02661 pParent = pObject->FindParent(); 02662 ERROR3IF(pParent == NULL, "Range::DoFactorOutAfterAttrChange, node found without a parent"); 02663 02664 // Only factor out attribs if the parent has not already had its attribs factored out 02665 if ((pParent->IsCompound()) && (pParent != pFactoredOutCompound)) 02666 { 02667 // Attempt to localise the compound 02668 if (!DoFactorOutAfterAttrChange((NodeRenderableInk*)pObject, pAffectedAttrTypes)) 02669 { 02670 delete pLevel; 02671 return FALSE; 02672 } 02673 02674 pFactoredOutCompound = (NodeRenderableInk*)pParent; // Remember that it's been localised 02675 } 02676 } 02677 02678 pCurrent = pLevel->FindNext(pCurrent); 02679 } 02680 02681 delete pLevel; 02682 return TRUE; 02683 }
|
|
This Do function must be called on an object after an attribute being applied to it. If you have applied multiple attributes to the Object then it is more efficient to call the other version of this function which takes a set of attribute types.
If the function is called on a object which does not have a compound parent then there will be no attributes to factor out so the function will simply return TRUE without having done anything. Before calling the function you should have localised attributes by calling DoLocaliseForAttrChange. If the object discards its attribute children then the routine does nothing (eg. the caret) Note: When applying attributes, we are not always going to apply the attributes to the object itself, sometimes we need to apply them to the object's parent. Eg. when we apply a line based attribute to a text character the attributes will get applied to the parent TextLine. In this situation we do not factor out the objects attributes, but its parents attributes instead.
Definition at line 3170 of file undoop.cpp. 03172 { 03173 BOOL ok = TRUE; 03174 03175 // Get object attr was applied to 03176 ERROR3IF(!pAffectedAttrType, "AttrType is NULL"); 03177 Object = Object->GetObjectToApplyTo(pAffectedAttrType); 03178 03179 { 03180 03181 Node* pParent; 03182 pParent = Object->FindParent(); 03183 ERROR3IF(!pParent, "UndoableOperation::DoFactorOutAfterAttrChange called on an object which has no parent"); 03184 03185 if (pParent->IsCompound()) 03186 { 03187 03188 // We need an attribute type set 03189 AttrTypeSet Set; 03190 03191 // Add the attributes type to the set 03192 if (!(Set.AddToSet(pAffectedAttrType))) 03193 { 03194 ok = FALSE; 03195 } 03196 03197 if (ok) 03198 { 03199 03200 return (DoFactorOutCommonChildAttributes((NodeRenderableInk*)pParent, 03201 TRUE, // Global 03202 &Set)); 03203 } 03204 03205 Set.DeleteAll(); 03206 } 03207 } 03208 return ok; 03209 }
|
|
This Do function must be called on an object after attributes have being applied to it.
If the function is called on a object which does not have a compound parent then there will be no attributes to factor out so the function will simply return TRUE without having done anything. Before calling the function you should have localised attributes by calling DoLocaliseForAttrChange. If the object discards its attribute children then the routine does nothing (eg. the caret) Note: When applying attributes, we are not always going to apply the attributes to the object itself, sometimes we need to apply them to the object's parent. Eg. when we apply a line based attribute to a text character the attributes will get applied to the parent TextLine. In this situation we do not factor out the objects attributes, but its parents attributes instead. Warning ~~~~~~~ All attribute types in the AttrTypeSet must have been localised (and so need factoring out) on the same compound node. This means for example that the AttrType set cannot contain a Bold and a Line space attribute. If we need to do this in future then the routine will need to be changed.
Definition at line 3091 of file undoop.cpp. 03093 { 03094 CCRuntimeClass* AttrType; 03095 03096 // Get object which attrib was applied to 03097 if (pAffectedAttrTypes && (!pAffectedAttrTypes->IsEmpty())) 03098 { 03099 AttrType = ((AttrTypeItem*)pAffectedAttrTypes->GetHead())->AttributeType; 03100 ERROR3IF(!AttrType, "AttrType set contains NULL attribute type"); 03101 Object = Object->GetObjectToApplyTo(AttrType); 03102 } 03103 03104 { 03105 Node* pParent; 03106 pParent = Object->FindParent(); 03107 ERROR3IF(!pParent, "UndoableOperation::DoFactorOutAfterAttrChange called on an object which has no parent"); 03108 03109 if (pParent->IsCompound()) 03110 { 03111 return (DoFactorOutCommonChildAttributes((NodeRenderableInk*)pParent, 03112 TRUE, // Global 03113 pAffectedAttrTypes)); 03114 } 03115 } 03116 return TRUE; 03117 }
|
|
Just a wrapper to get function name consistency and do the common IsCompound test to prevent DFOCCA from barfing...
Definition at line 3644 of file undoop.cpp. 03647 { 03648 if (pRootNode->IsCompound()) 03649 DoFactorOutCommonChildAttributes(pRootNode, bGlobal, pAffectedAttrTypes); 03650 03651 return TRUE; 03652 }
|
|
This function is an information gatherer for the DoFactorOutAfterDeletion function. See this function for a full description of its purpose. Whenever we delete a range of objects, if any objects in the range have compound parents then we must adjust the common attributes on these compounds. This function factors out all attributes which are common to all children of the compound object. All common attributes become first children of the compound object.
pAffectedAttrTypes: An optional set of attribute types. If this is specified then we only consider factoring out those attributes which have a type which is in this set.
As with all Do functions actions are generated to undo/redo
Definition at line 3581 of file undoop.cpp. 03584 { 03585 LocaliseCommonAttrAct* UndoAct; 03586 03587 if (!CompoundObject->DiscardsAttributeChildren()) 03588 { 03589 // Make a copy of the attribute type set to store in the Action 03590 AttrTypeSet* pSet = NULL; 03591 if (pAffectedAttrTypes) 03592 { 03593 pSet = pAffectedAttrTypes->CopySet(); 03594 if (!pSet) 03595 return FALSE; // Failed to create set 03596 } 03597 03598 // Create an action to localise attributes which have been factored out 03599 if ( LocaliseCommonAttrAct::Init(this, 03600 &UndoActions, 03601 CompoundObject, 03602 Global, 03603 pSet, 03604 (Action**)(&UndoAct)) 03605 == AC_FAIL) 03606 return FALSE; 03607 } 03608 03609 if (!CompoundObject->FactorOutCommonChildAttributes(Global, pAffectedAttrTypes)) 03610 { 03611 FailAndExecuteAllButLast(); 03612 return FALSE; 03613 } 03614 03615 return TRUE; 03616 }
|
|
Not implemented yet.
Definition at line 1898 of file undoop.cpp. 01899 { 01900 return FALSE; 01901 }
|
|
This function is a pre process to DoHideNodes(). It calls each object in the range to hide themselves in a complex way. It may be that no objects in the selection require this facility, which means the RangeToHide object will be returned from this function unaffected. DoHideNodes() will then go through hidding all nodes in the range itself. If however a node responds to ComplexHide() and hides itself, the node will be removed from the range. This allows complex group nodes to control how they are hidden. Note, it is expected that ComplexHide() responders will hide nodes themselves This will have the automatic effect of removing them from the range. Hidden nodes do not appear in ranges.
Definition at line 850 of file undoop.cpp. 00851 { 00852 BOOL Failed=FALSE; 00853 Node *Next, *Current = RangeToHide.FindFirst(); 00854 00855 while (Current!=NULL) 00856 { 00857 // set the next node pointer. 00858 Next=RangeToHide.FindNext(Current); 00859 INT32 success = Current->ComplexHide(this, Next); 00860 // success=-1 then error unable to hide node 00861 // success= 0 then ignore 00862 // success= 1 then node has been hidden 00863 Failed=(success<0); 00864 if (Failed) 00865 break; 00866 00867 Current=Next; 00868 } 00869 00870 return (!Failed); 00871 }
|
|
This low level Do function hides the subtree with root NodeToHide.
Definition at line 702 of file undoop.cpp. 00706 { 00707 ERROR3IF(!OpFlags.SucceedAndDiscard && NodeToHide->IsAnAttribute() && NodeToHide->FindParent()->DiscardsAttributeChildren(), "DoHide called under Caret"); 00708 00709 if (NodeToHide->DiscardsAttributeChildren()) // If the node to hide doesn't want to produce undo (CaretNode) 00710 return TRUE; // Then bomb out now before we do anything... 00711 00712 // We shouldn't tell the node that it's being hidden if we are only 00713 // moving it. 00714 // Also if we are Hiding a Node Group, then there is no 00715 // need to tell anyone either. As the children are unaffected. 00716 if (TellSubtree) 00717 { 00718 // Tell the node and it's subtree, that they are being hidden 00719 Node* pNode = NodeToHide->FindFirstDepthFirst(); 00720 while (pNode!=NULL) 00721 { 00722 if (!pNode->HidingNode()) 00723 return FALSE; 00724 00725 // And find the next node 00726 pNode = pNode->FindNextDepthFirst(NodeToHide); 00727 } 00728 // Invalidate the region, we need to do this here because we are deleting the node 00729 if (NodeToHide->IsBounded()) 00730 ((NodeRenderableBounded*)NodeToHide)->InvalidateBoundingRect(); 00731 00732 } 00733 00734 // removed by Ed 23/5/95 'cos it caused text redraw problems 00735 // and nobody could justify why just moving an object in the tree should 00736 // cause the renderable bound associated with it to be invalidated 00737 // // Invalidate the region 00738 // if (NodeToHide->IsBounded()) 00739 // ((NodeRenderableBounded*)NodeToHide)->InvalidateBoundingRect(); 00740 00741 // Try to hide the Node 00742 NodeHidden* Hidden; 00743 ALLOC_WITH_FAIL(Hidden,(new NodeHidden(NodeToHide)),this); 00744 if (Hidden == NULL) 00745 { 00746 return (FALSE); 00747 } 00748 00749 // Try to create a ShowNodeAction which will show the node that we have just hidden. 00750 00751 ShowNodeAction* UndoShowNodeAction; 00752 00753 if (ShowNodeAction::Init(this, 00754 &UndoActions, 00755 Hidden, 00756 IncludeSubtreeSize, 00757 (Action**)(&UndoShowNodeAction), 00758 TellSubtree) == AC_FAIL) 00759 { 00760 // We must unhide the NodeToHide manually, cos no action will do it for us 00761 Hidden->ShowNode(); // Hidden is deleted don't worry 00762 return FALSE; 00763 } 00764 00765 if (NodeToHide->IsSelected()) 00766 { 00767 // Update the selection range 00768 Camelot.UpdateSelection(); 00769 } 00770 00771 // If the user provided a nodeHidden parameter then return a pointer to the NodeHidden 00772 if (nodeHidden != NULL) 00773 *nodeHidden = Hidden; 00774 00775 // Added by Jim: Broadcast the layerchanged message when inserting a new layer 00776 00777 if (NodeToHide->GetRuntimeClass() == CC_RUNTIME_CLASS(Layer)) 00778 { 00779 Spread* pSpread = (Spread*) Hidden->FindParent(CC_RUNTIME_CLASS(Spread)); 00780 BROADCAST_TO_ALL(SpreadMsg(pSpread,SpreadMsg::LAYERCHANGES)); 00781 } 00782 // Success 00783 return (TRUE); 00784 }
|
|
This low level Do function hides a range of the subtrees.
Definition at line 809 of file undoop.cpp. 00810 { 00811 Node* Current = NodeRange.FindFirst(); 00812 while (Current != NULL) 00813 { 00814 Node* Next = NodeRange.FindNext(Current); 00815 if (!DoHideNode(Current, IncludeSubtreeSize, NULL, TellSubtree)) 00816 { 00817 return FALSE; // Failure 00818 } 00819 Current = Next; 00820 } 00821 return TRUE; // Success 00822 }
|
|
This high level do function attaches the node to ContextNode in the direction specified. If the NewNode is a NodeRenderableInk then the node becomes selected and all other nodes are deselected.
Definition at line 536 of file undoop.cpp. 00543 { 00544 // Insert the NewNode into the tree 00545 NewNode->AttachNode(ContextNode, Direction); 00546 NewNode->SetSelected(FALSE); 00547 00548 // This is a brand new node, so we have to make sure that all its parents 00549 // are invalidated as well. 00550 // if this nodes bounding rect was already invalid when it was added the parent 00551 // will not be invalidated as well, so we first mark its bounds as valid. 00552 // This is very important - Ask Rik if you think it looks silly. 00553 NewNode->ValidateBoundingRect(); 00554 NewNode->InvalidateBoundingRect(); 00555 00556 // If inserting a node onto a layer that is locked or invisible, warn the user before 00557 // proceeding, and ensure that the node is not selected. 00558 if (NewNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableInk))) 00559 { 00560 Layer* pLayer = (Layer*)NewNode->FindParent(CC_RUNTIME_CLASS(Layer)); 00561 if (pLayer != NULL) 00562 { 00563 if (!pLayer->IsVisible() || pLayer->IsLocked()) 00564 { 00565 if (WarnInsertObjsOntoLockedLayers) 00566 { 00567 #if (_OLE_VER >= 0x200) 00568 // Only warn the user if the document is visible to him/her. 00569 if (pOurDoc && pOurDoc->GetOilDoc() && pOurDoc->GetOilDoc()->IsVisible()) 00570 #endif 00571 { 00572 // ignore this warning on some ops - like if we have text syncing between layers 00573 // or other bar ops that manipulate invisible layers 00574 // or doing the right click from drag op since the msg upsets the drag 00575 PORTNOTE("text","Removed OpTextFormat reference") 00576 #ifndef EXCLUDE_FROM_XARALX 00577 if (!IS_A(this, OpTextFormat) && !IS_A(this, OpDuplicateBar) && !IS_A(this, OpCopyAndTransform)) 00578 InformWarning(_R(IDS_WARNING_INSERTLAYER)); 00579 #endif 00580 } 00581 00582 // Set flag to FALSE so it won't be reported back again in this op 00583 WarnInsertObjsOntoLockedLayers = FALSE; 00584 } 00585 SelectNewObject = FALSE; 00586 } 00587 00588 // Note that this layer has been edited 00589 pLayer->SetEdited(TRUE); 00590 #ifdef _DEBUG 00591 // Tell the frame gallery to update its display of the frame 00592 BROADCAST_TO_ALL(LayerMsg(pLayer, LayerMsg::/*LayerReason::*/REDRAW_LAYER)); 00593 #endif 00594 } 00595 } 00596 00597 // Create a hide node action to hide the node when we undo 00598 HideNodeAction* UndoHideNodeAction; 00599 if (HideNodeAction::Init(this, 00600 &UndoActions, 00601 NewNode, 00602 TRUE, // Include subtree size 00603 ( Action**)(&UndoHideNodeAction)) 00604 == AC_FAIL) 00605 00606 { 00607 return FALSE; 00608 } 00609 00610 00611 00612 // Make it the currently selected object if it is an Ink object 00613 if ( NewNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableInk)) ) 00614 { 00615 if (ClearSelection) 00616 { 00617 NodeRenderableInk::DeselectAll(); 00618 GetApplication()->UpdateSelection(); 00619 00620 } 00621 00622 if (SelectNewObject) 00623 { 00624 00625 // Select the new node 00626 ((NodeRenderableInk*)NewNode)->Select(FALSE); 00627 } 00628 00629 00630 if (NormaliseAttributes) 00631 { 00632 ((NodeRenderableInk*)NewNode)->NormaliseAttributes(); // Removes redundant attributes 00633 } 00634 00635 00636 } 00637 00638 // Update the selection 00639 if (NewNode->IsSelected()) 00640 GetApplication()->UpdateSelection(); 00641 00642 00643 if ( NewNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableBounded)) ) 00644 { 00645 if (InvalidateRegion) 00646 { 00647 NewNode->ReleaseCached(TRUE, FALSE, TRUE, TRUE); 00648 if (!DoInvalidateNodeRegion((NodeRenderableBounded*)NewNode, TRUE, FALSE, FALSE, FALSE)) // Don't recache automatically! 00649 { 00650 return FALSE; 00651 } 00652 } 00653 } 00654 00655 // #ifdef _DEBUG 00656 // // If the node being Inserted is a layer then people need to know about it 00657 // if (NewNode->GetRuntimeClass() == CC_RUNTIME_CLASS(Layer)) 00658 // { 00659 // TRACE( _T("Layer inserted. Have you remembered to broadcast a SpreadMsg::LAYERCHANGES message?")); 00660 // //Spread* pSpread = (Spread*) NewNode->FindParent(CC_RUNTIME_CLASS(Spread)); 00661 // //BROADCAST_TO_ALL(SpreadMsg(pSpread,SpreadMsg::LAYERCHANGES)); 00662 // } 00663 // #endif 00664 00665 // Added by Jim: Broadcast the layerchanged message when inserting a new layer 00666 00667 if (NewNode->GetRuntimeClass() == CC_RUNTIME_CLASS(Layer)) 00668 { 00669 Spread* pSpread = (Spread*) NewNode->FindParent(CC_RUNTIME_CLASS(Spread)); 00670 BROADCAST_TO_ALL(SpreadMsg(pSpread,SpreadMsg::LAYERCHANGES)); 00671 } 00672 00673 return (TRUE); 00674 }
|
|
Inserts the node as a last child of the active layer of the pSpread. If the NewNode is a NodeRenderableInk then the node becomes selected and all other nodes are deselected. If pSpread is NULL then the object is inserted on the selected spread.
Definition at line 363 of file undoop.cpp. 00370 { 00371 ENSURE( pOurDoc!=NULL, "No current document in DoInsertNode" ); 00372 00373 // Insert node as the active layer of the spread 00374 pOurDoc->InsertNewNode(NewNode, pSpread); 00375 NewNode->SetSelected(FALSE); 00376 00377 // This is a brand new node, so we have to make sure that all its parents 00378 // are invalidated as well. 00379 // if this nodes bounding rect was already invalid when it was added the parent 00380 // will not be invalidated as well, so we first mark its bounds as valid. 00381 // This is very important - Ask Rik if you think it looks silly. 00382 NewNode->ValidateBoundingRect(); 00383 NewNode->InvalidateBoundingRect(); 00384 00385 // If inserting a node onto a layer that is locked or invisible, warn the user before 00386 // proceeding, and ensure that the node is not selected. 00387 if (NewNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableInk))) 00388 { 00389 Layer* pLayer = (Layer*)NewNode->FindParent(CC_RUNTIME_CLASS(Layer)); 00390 if (pLayer != NULL) 00391 { 00392 if (!pLayer->IsVisible() || pLayer->IsLocked()) 00393 { 00394 if (WarnInsertObjsOntoLockedLayers) 00395 { 00396 #if (_OLE_VER >= 0x200) 00397 // Only warn the user if the document is visible to him/her. 00398 if (pOurDoc && pOurDoc->GetOilDoc() && pOurDoc->GetOilDoc()->IsVisible()) 00399 #endif 00400 { 00401 InformWarning(_R(IDS_WARNING_INSERTLAYER)); 00402 } 00403 // Set flag to FALSE so it won't be reported back again in this op 00404 WarnInsertObjsOntoLockedLayers = FALSE; 00405 } 00406 SelectNewObject = FALSE; 00407 } 00408 00409 // Note that this layer has been edited 00410 pLayer->SetEdited(TRUE); 00411 #ifdef _DEBUG 00412 // Tell the frame gallery to update its display of the frame 00413 BROADCAST_TO_ALL( LayerMsg( pLayer, LayerMsg::REDRAW_LAYER ) ); 00414 #endif 00415 } 00416 } 00417 00418 00419 /* 00420 if (InvalidateRgn) 00421 { 00422 if (!DoInvalidateNodeRegion((NodeRenderable*)NewNode, TRUE)) 00423 { 00424 // Remove the NewNodeFrom the tree 00425 NewNode->UnlinkNodeFromTree(); 00426 return FALSE; 00427 } 00428 } 00429 */ 00430 00431 // Create a hide node action to hide the node when we undo 00432 HideNodeAction* UndoHideNodeAction; 00433 if (HideNodeAction::Init(this, 00434 &UndoActions, 00435 NewNode, 00436 TRUE, // Include subtree size 00437 ( Action**)(&UndoHideNodeAction)) 00438 == AC_FAIL) 00439 00440 { 00441 // Remove the NewNodeFrom the tree 00442 NewNode->UnlinkNodeFromTree(); 00443 return FALSE; 00444 } 00445 00446 00447 // Make it the currently selected object if it is an Ink object 00448 if ( NewNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableInk)) ) 00449 { 00450 if (ClearSelection) 00451 { 00452 NodeRenderableInk::DeselectAll(); 00453 GetApplication()->UpdateSelection(); 00454 } 00455 00456 00457 if (SelectNewObject) 00458 { 00459 // Select the new node, and don't redraw it yet 00460 ((NodeRenderableInk*)NewNode)->Select(FALSE); 00461 } 00462 00463 if (NormaliseAttributes) 00464 { 00465 ((NodeRenderableInk*)NewNode)->NormaliseAttributes(); // Removes redundant attributes 00466 } 00467 00468 00469 } 00470 00471 // Update the selection 00472 if (NewNode->IsSelected()) 00473 GetApplication()->UpdateSelection(); 00474 00475 if ( NewNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableBounded)) ) 00476 { 00477 if (InvalidateRgn) 00478 { 00479 if (!DoInvalidateNodeRegion((NodeRenderableBounded*)NewNode, TRUE)) 00480 { 00481 return FALSE; 00482 } 00483 } 00484 } 00485 00486 // Added by Jim: Broadcast the layerchanged message when inserting a new layer 00487 00488 if (NewNode->GetRuntimeClass() == CC_RUNTIME_CLASS(Layer)) 00489 { 00490 Spread* pSpread = (Spread*) NewNode->FindParent(CC_RUNTIME_CLASS(Spread)); 00491 BROADCAST_TO_ALL(SpreadMsg(pSpread,SpreadMsg::LAYERCHANGES)); 00492 } 00493 00494 return (TRUE); 00495 }
|
|
This 'Do' function adds an element into a path, recording undo information.
Definition at line 3873 of file undoop.cpp. 03879 { 03880 #ifndef STANDALONE 03881 03882 // Create an undo action for this action, which is a RemoveElementAction 03883 RemovePathElementAction* pAction = NULL; 03884 ActionCode Act; 03885 Act = RemovePathElementAction::Init(this, 03886 &UndoActions, 03887 1, 03888 Index+1, 03889 (Action**)(&pAction)); 03890 if (Act == AC_FAIL) 03891 return FALSE; 03892 03893 // Tell the operation where the path is 03894 if (pAction != NULL) 03895 pAction->RecordPath(ThisPath); 03896 03897 Document* pDocument = GetWorkingDoc(); 03898 ERROR2IF(pDocument == NULL, FALSE, "There was no Document when deleteing path elements"); 03899 Spread* pSpread = ThisPath->FindParentSpread(); 03900 ERROR2IF(pSpread == NULL, FALSE, "Path had no parent spread"); 03901 03902 // Force a re-draw of the place where the path used to be 03903 if (RedrawPath) 03904 { 03905 DocRect Invalid = ThisPath->GetUnionBlobBoundingRect(); 03906 // Mark the region as requiring object to recache any cached 03907 // data they may be holding because the Op may have changed it 03908 pDocument->ForceRedraw( pSpread, Invalid, FALSE, ThisPath ); 03909 } 03910 03911 // Insert the new element 03912 ThisPath->InkPath.InsertSection(Index,1); 03913 03914 // Get pointers to all the arrays of the path 03915 PathVerb* Verbs = NULL; 03916 DocCoord* Coords = NULL; 03917 PathFlags* Flags = NULL; 03918 ThisPath->InkPath.GetPathArrays(&Verbs, &Coords, &Flags); 03919 03920 // Update the coords 03921 Verbs[Index+1] = NewVerb; 03922 Flags[Index+1] = NewFlags; 03923 Coords[Index+1] = NewCoord; 03924 03925 // The bounding rect may have changed 03926 ThisPath->InvalidateBoundingRect(); 03927 03928 // Redraw the new area 03929 if (RedrawPath) 03930 { 03931 DocRect Invalid = ThisPath->GetUnionBlobBoundingRect(); 03932 // Mark the region as requiring object to recache any cached 03933 // data they may be holding because the Op may have changed it 03934 pDocument->ForceRedraw( pSpread, Invalid, FALSE, ThisPath ); 03935 } 03936 03937 #endif 03938 return TRUE; 03939 }
|
|
Invalidates the nodes bounding rectangle, or blob bounding rectangle.
Definition at line 1646 of file undoop.cpp. 01651 { 01652 ENSURE((!OpFlags.Failed), "Calling a DO function after operation has failed"); 01653 01654 // Range = Sel nodes, Unsel nodes, cross layers, Locked layers, Ignore Non-renderables, Ignore invisible layers 01655 RangeControl rc( TRUE, TRUE, TRUE, FALSE, TRUE, TRUE ); 01656 Range range( Node, Node, rc ); 01657 01658 return( DoInvalidateNodesRegions( range, IncludeBlobs, UndoBlobs, IfBgRedraw, bForceRecache ) ); 01659 }
|
|
This low level Do function invalidates a region which is the union of the bounding rectangles of each node in the range. When the includeBlobs flag is TRUE the region which gets invalidated includes the objects blobs.
All members of the range must be on the same spread No member of the range can be hidden
Definition at line 1470 of file undoop.cpp. 01474 { 01475 ENSURE((!OpFlags.Failed), "Calling a DO function after operation has failed"); 01476 01477 if (UndoBlobs) 01478 { 01479 // Undo blobs = TRUE 01480 // We will use different 'IncludeBlobs' when we undo/redo this op 01481 // to the one we use initially. 01482 UndoBlobs = !IncludeBlobs; 01483 } 01484 else 01485 { 01486 // Undo blobs = FALSE 01487 // We will use the same 'IncludeBlobs' when we undo/redo this op 01488 // as the one we use initially. 01489 UndoBlobs = IncludeBlobs; 01490 } 01491 01492 BOOL bOldValue = NodeRange.SetPromoteToParent(TRUE); 01493 NodeRenderableBounded* CurrentNode = (NodeRenderableBounded*)NodeRange.FindFirst(); 01494 NodeRange.SetPromoteToParent(bOldValue); 01495 01496 if (CurrentNode == NULL) 01497 return TRUE; // The range is empty so NOP 01498 01499 // ENSURE the range of nodes is not empty 01500 // ENSURE (CurrentNode != NULL, "Calling DoInvalidateNodesRegions with an empty range"); 01501 01502 // ENSURE(CurrentNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderable)), 01503 // "Trying to invalidate a non NodeRenderable node"); 01504 01505 // Find the spread 01506 Spread* pSpread = (Spread*)CurrentNode->FindParent(CC_RUNTIME_CLASS(Spread)); 01507 01508 01509 01510 // Matt 27/11/2000 01511 // OK, here's the beef... At present, if you group a shadowed object, the tree structure correctly 01512 // reflects this as a NodeShadowController with a NodeGroup parent... Now, when we've clicked on the 01513 // 'Set New Design' button, the NodeGroup is passed OK and is hidden after being copied (as was intended) 01514 // but the NodeShadowController beneath this is then tested: When asked what it's parent spread is, it 01515 // will promptly keel over, triggering the following ENSURE as its parent (the NodeGroup) no longer has 01516 // a pointer to its parent (ie it is NULL) - to cater for this, if we reach this point and we have no 01517 // parent spread, we can assume one of two things: 01518 // 1. The node above us has been hidden, therefore we are already implicitly hidden and we shouldn't 01519 // undertake any special work 01520 // 2. Everything is stuffed so bad in our tree that it really doesn't matter what we do here - we're 01521 // about to die anyhow... 01522 // Therefore, we can just return without failing with an ensure... 01523 // 01524 // ENSURE(pSpread != NULL, "Spread is NULL"); 01525 01526 01527 01528 if (pSpread) 01529 { 01530 if (IfBgRedraw) 01531 { 01532 // ------------------------------------------------------------------------------------- 01533 // Try and create an InvalidateRegionAction 01534 InvalidateRegionIfBgRedrawAction* UndoInvalidateRgnAction; 01535 01536 // Create an InvalidateRegionAction 01537 // Note that unfortunatly the action has to store the node range, rather than the 01538 // bounding rectangle because GetBlobBoundingRect must be calculated on the fly. 01539 01540 if ( InvalidateRegionIfBgRedrawAction::Init(this, 01541 &UndoActions, 01542 NodeRange, 01543 pSpread, 01544 UndoBlobs, 01545 ( Action**)(&UndoInvalidateRgnAction)) == AC_FAIL) 01546 { 01547 return FALSE; // Failed to create action 01548 } 01549 01550 if (!GetApplication()->IsBgRendering()) 01551 { 01552 return TRUE; // Ignore if no Bg Rendering in progress 01553 } 01554 01555 // GetApplication()->DeleteRenderRegions(DocView::GetSelected()); 01556 // GetApplication()->BgRendering = FALSE; 01557 } 01558 else 01559 { 01560 // ------------------------------------------------------------------------------------- 01561 // Try and create an InvalidateRegionAction 01562 InvalidateRegionAction* UndoInvalidateRgnAction; 01563 01564 // Create an InvalidateRegionAction 01565 // Note that unfortunatly the action has to store the node range, rather than the 01566 // bounding rectangle because GetBlobBoundingRect must be calculated on the fly. 01567 01568 if ( InvalidateRegionAction::Init(this, 01569 &UndoActions, 01570 NodeRange, 01571 pSpread, 01572 UndoBlobs, 01573 ( Action**)(&UndoInvalidateRgnAction)) == AC_FAIL) 01574 { 01575 return FALSE; // Failed to create action 01576 } 01577 } 01578 01579 ENSURE(pOurDoc != 0, "There was no document in DoInvalidateNodesRegions"); 01580 01581 // Invalidate the bounds of each node in the range 01582 01583 if (pOurDoc != NULL) 01584 { 01585 DocRect TempRect; 01586 01587 BOOL bOldValue = NodeRange.SetPromoteToParent(TRUE); 01588 while (CurrentNode != NULL) 01589 { 01590 // Because we had a Range param, we could possibly be given any legal node in the tree, 01591 // e.g. the Insert node, not just renderable bounded objects, hence this 'if' statement 01592 if (CurrentNode->IsAnObject() || CurrentNode->IsPaper()) 01593 { 01594 ENSURE(CurrentNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableBounded)), 01595 "Trying to invalidate a non NodeRenderable node"); 01596 01597 TempRect = (IncludeBlobs ? 01598 (CurrentNode->GetUnionBlobBoundingRect()): 01599 (CurrentNode->GetBoundingRect()) 01600 ); 01601 TempRect = TempRect.Union(CurrentNode->GetEffectStackBounds()); 01602 01603 // Accumulate this invalid region in a pending list until the Op 01604 // finishes 01605 // Mark the region as requiring object to recache any cached 01606 // data they may be holding because the Op may have changed it 01607 // pOurDoc->ForceRedraw(pSpread, TempRect, TRUE, bForceRecache ? CurrentNode : NULL); 01608 pOurDoc->ForceRedraw(pSpread, TempRect, TRUE, CurrentNode, bForceRecache); 01609 } 01610 01611 CurrentNode = (NodeRenderableBounded*) NodeRange.FindNext(CurrentNode); 01612 } 01613 NodeRange.SetPromoteToParent(bOldValue); 01614 } 01615 } 01616 01617 // Now invalidate the region 01618 return TRUE; 01619 }
|
|
Invalidates the region specified and adds the appropriate action to the action list for the current operation. If you are invalidating a region associated with a node in the tree then you should be using DoInvalidateNodeRegion() or DoInvalidateNodesRegion().
Definition at line 1680 of file undoop.cpp. 01681 { 01682 // make sure that things are worth doing 01683 ENSURE((!OpFlags.Failed), "Calling a DO function after operation has failed"); 01684 ENSURE(pSpread!=NULL, "Attempt to invalidate a region on a null spread."); 01685 01686 // If the region is empty we could save everyone a lot of trouble 01687 if (InvalidRegion.IsEmpty()) 01688 return TRUE; 01689 01690 // Try and create an InvalidateArbitaryRegionAction and fail if it does not work 01691 InvalidateArbitaryAction* pAction; 01692 ActionCode ActCode = InvalidateArbitaryAction::Init( this, &UndoActions, pSpread, 01693 InvalidRegion, (Action**)(&pAction)); 01694 01695 // See if it worked 01696 if (ActCode==AC_FAIL) 01697 return FALSE; 01698 01699 // Now we can invalidate the region for the caller 01700 // First we need a document 01701 ENSURE(pOurDoc != NULL, "There was no document in DoInvalidateRegions"); 01702 01703 // Invalidate the bounds of each node in the range 01704 if (pOurDoc != NULL) 01705 // Accumulate this invalid region in a pending list until the Op 01706 // finishes 01707 // Mark the region as requiring object to recache any cached 01708 // data they may be holding because the Op may have changed it 01709 pOurDoc->ForceRedraw(pSpread, InvalidRegion, TRUE, pSpread); 01710 01711 // Tell them that everything worked out just fine 01712 return TRUE; 01713 }
|
|
This function is the opposite of DoFactorOutCommonChildAttributes it copies all attributes common to the compound object to each child object within the group which requires each attribute. The groups common attributes are deleted.
Global: TRUE indicates that we should localise the attributes on all parent compound nodes (top down), before localising the attributes for this compound. pAffectedAttrTypes: An optional set of attribute types. If this is specified then we only consider localising those attributes which have a type which is in this set.
Definition at line 3697 of file undoop.cpp. 03701 { 03702 03703 FactorOutCommonChildAttrAct* UndoAct; 03704 03705 03706 // Create an action to localise attributes which have been factored out 03707 if (!CompoundObject->DiscardsAttributeChildren()) 03708 { 03709 // Make a copy of the attribute type set to store in the Action 03710 AttrTypeSet* pSet = NULL; 03711 if (pAffectedAttrTypes) 03712 { 03713 pSet = pAffectedAttrTypes->CopySet(); 03714 if (!pSet) 03715 return FALSE; // Failed to create set 03716 } 03717 03718 if ( FactorOutCommonChildAttrAct::Init(this, 03719 &UndoActions, 03720 CompoundObject, 03721 Global, 03722 pSet, 03723 (Action**)(&UndoAct)) 03724 == AC_FAIL) 03725 return FALSE; 03726 } 03727 03728 if (!CompoundObject->LocaliseCommonAttributes(CheckForDuplicates, 03729 Global, 03730 pAffectedAttrTypes)) 03731 { 03732 FailAndExecuteAllButLast(); 03733 return FALSE; 03734 } 03735 03736 return TRUE; 03737 }
|
|
This Do function must be called on a range prior to an attribute being applied to it. If you are going to apply multiple attributes to the range then it is more efficient to call the other version of this function which takes a set of attribute types.
If an object in the range Discards its attribute children then its attributes are not localised. Note: When applying an attribute, we are not always going to apply it to the object itself, sometimes we need to apply it to the object's parent. Eg. when we apply a line based attribute to a text character the attributes will get applied to the parent TextLine. In this situation we do not localise the objects attributes, but its parents attributes instead.
Definition at line 2518 of file undoop.cpp. 02520 { 02521 ERROR3IF(pRange->Count() == 0, "Range::DoLocaliseForAttrChange called on an empty range"); 02522 02523 // Iterate over the top of any liveeffects applied to the selection 02524 // Its important that this iteration matches those used in DoApplyAttribute functions 02525 // so that attributes are put in the places where mutation will find them 02526 ListRange* pLevel = EffectsStack::GetNewLevelRange(pRange, FALSE); // We DO own this range 02527 Node* pCurrent = pLevel->FindFirst(); 02528 02529 // There is no need to localise a compound more than once so we remember the last localised 02530 NodeRenderableInk* pLocalisedCompound = NULL; 02531 02532 Node* pParent; 02533 Node* pObject; 02534 02535 while (pCurrent) 02536 { 02537 pObject = pCurrent; 02538 // Determine if the attribute will get applied to this object, or an alternative object 02539 // (probably its parent) 02540 ERROR3IF(!pAffectedAttrType, "AttrType is NULL"); 02541 pObject = ((NodeRenderableInk*)pObject)->GetObjectToApplyTo(pAffectedAttrType); 02542 02543 { 02544 02545 // We only need to localise those nodes which have a compound parent 02546 pParent = pObject->FindParent(); 02547 ERROR3IF(pParent == NULL, "Range::DoLocaliseForAttrChange, node found without a parent"); 02548 02549 // Only localise the parent if it is a compound node which has not already been localised 02550 if ((pParent->IsCompound()) && (pParent != pLocalisedCompound)) 02551 { 02552 // Attempt to localise the compound 02553 if (!DoLocaliseForAttrChange((NodeRenderableInk*)pObject, pAffectedAttrType, NULL)) 02554 { 02555 delete pLevel; 02556 return FALSE; 02557 } 02558 02559 pLocalisedCompound = (NodeRenderableInk*)pParent; // Remember that it's been localised 02560 } 02561 } 02562 pCurrent = pLevel->FindNext(pCurrent); 02563 } 02564 02565 delete pLevel; 02566 return TRUE; 02567 }
|
|
This Do function must be called on a range prior to a set of attributes being applied to it. It globally localises those attributes which have a type in the pAffectedAttrTypes set.
All attriute types in this set must be localised on the same compound node (See note below). ExcludeTextObjects: When TRUE atttributes will not be localised on Text compounds. This is useful for selection deletions, where TextStory localisation will be left to the Story itself. This is a bit unpleasant.
If an object in the range Discards its attribute children then its attributes are not localised. Note: When applying attributes, we are not always going to apply the attributes to the object itself, sometimes we need to apply them to the object's parent. Eg. when we apply a line based attribute to a text character the attributes will get applied to the parent TextLine. In this situation we do not localise the objects attributes, but its parents attributes instead. Warning ~~~~~~~ All attribute types in the AttrTypeSet must be localised on the same compound node. This means for example that the AttrType set cannot contain a Bold and a Line space attribute. If we need to do this in future then the routine will need to be changed.
Definition at line 2406 of file undoop.cpp. 02409 { 02410 ERROR3IF(pRange->Count() == 0, "Range::DoLocaliseForAttrChange called on an empty range"); 02411 02412 // Iterate over the top of any liveeffects applied to the selection 02413 // Its important that this iteration matches those used in DoApplyAttribute functions 02414 // so that attributes are put in the places where mutation will find them 02415 ListRange* pLevel = EffectsStack::GetNewLevelRange(pRange, FALSE); // We DO own this range 02416 Node* pCurrent = pLevel->FindFirst(); 02417 02418 // There is no need to localise a compound more than once so we remember the last localised 02419 NodeRenderableInk* pLocalisedCompound = NULL; 02420 02421 CCRuntimeClass* AttrType; 02422 Node* pParent; 02423 Node* pObject; 02424 02425 while (pCurrent) 02426 { 02427 pObject = pCurrent; 02428 // Determine if the attribute will get applied to this object, or an alternative object 02429 // (probably its parent) 02430 if (pAffectedAttrTypes && (!pAffectedAttrTypes->IsEmpty())) 02431 { 02432 AttrType = ((AttrTypeItem*)pAffectedAttrTypes->GetHead())->AttributeType; 02433 ERROR3IF(!AttrType, "AttrType set contains NULL attribute type"); 02434 pObject = ((NodeRenderableInk*)pObject)->GetObjectToApplyTo(AttrType); 02435 } 02436 02437 if (pObject != NULL) 02438 { 02439 02440 // We only need to localise those nodes which have a compound parent 02441 pParent = pObject->FindParent(); 02442 ERROR3IF(pParent == NULL, "Range::DoLocaliseForAttrChange, node found without a parent"); 02443 02444 // Only localise the parent if it is a compound node which has not already been localised 02445 if ((pParent->IsCompound()) && (pParent != pLocalisedCompound)) 02446 { 02447 if (!(ExcludeTextObjects && ((IS_A(pParent, TextLine)) || (IS_A(pParent, TextStory)))) ) 02448 { 02449 // Attempt to localise the compound 02450 if (!DoLocaliseForAttrChange((NodeRenderableInk*)pObject, pAffectedAttrTypes, NULL)) 02451 { 02452 delete pLevel; 02453 return FALSE; 02454 } 02455 02456 pLocalisedCompound = (NodeRenderableInk*)pParent; // Remember that it's been localised 02457 } 02458 } 02459 } 02460 02461 pCurrent = pLevel->FindNext(pCurrent); 02462 } 02463 02464 delete pLevel; 02465 return TRUE; 02466 }
|
|
This Do function must be called on an object prior to an attribute being applied to it. If you are going to apply multiple attributes to the Object then it is more efficient to call the other version of this function which takes a set of attribute types.
pLocalisedCompounds: An optional set of compounds which have already had their pAffectedAttrType localised. If Object has a parent compound which is in this set then its attributes will not need to be localised again.
If the function is called on a object which does not have a compound parent then there will be no attributes to localise so the function will simply return TRUE without having done anything. If the object discards its attribute children then the routine does nothing (eg. the caret) Note: When applying attributes, we are not always going to apply the attributes to the object itself, sometimes we need to apply them to the object's parent. Eg. when we apply a line based attribute to a text character the attributes will get applied to the parent TextLine. In this situation we do not localise the objects attributes, but its parents attributes instead.
Definition at line 2973 of file undoop.cpp. 02976 { 02977 BOOL ok = TRUE; 02978 // Determine if the attribute will get applied to this object, or an alternative object 02979 // (probably its parent) 02980 ERROR3IF(!pAffectedAttrType, "AttrType is NULL"); 02981 Object = Object->GetObjectToApplyTo(pAffectedAttrType); 02982 02983 { 02984 02985 Node* pParent; 02986 pParent = Object->FindParent(); 02987 ERROR3IF(!pParent, "UndoableOperation::DoLocaliseForAttrChange called on an object which has no parent"); 02988 02989 if (pParent->IsCompound()) 02990 { 02991 02992 // We an attribute type set 02993 AttrTypeSet Set; 02994 02995 // Add the attributes type to the set 02996 if (!Set.AddToSet(pAffectedAttrType)) 02997 { 02998 ok = FALSE; 02999 } 03000 03001 if (ok) 03002 { 03003 // Before we attempt to localise the compound's attributes let's check that they are not 03004 // already localised. 03005 03006 if (pLocalisedCompounds) 03007 { 03008 if (pLocalisedCompounds->InSet((NodeRenderableInk*)pParent)) 03009 { 03010 return TRUE; // Attributes are already localised so there is no need to localise again ! 03011 } 03012 else 03013 { 03014 pLocalisedCompounds->AddToSet((NodeRenderableInk*)pParent); // Record that the compound has been localised 03015 } 03016 } 03017 03018 03019 ok = DoLocaliseCommonAttributes((NodeRenderableInk*)pParent,// We are localising the compound's attrs 03020 FALSE, // No need to check for duplicates 03021 TRUE, // Localise globally 03022 &Set); // Only attributes of these types 03023 } 03024 03025 // The attribute type set is no longer required 03026 Set.DeleteAll(); 03027 } 03028 } 03029 return ok; 03030 }
|
|
This Do function must be called on an object prior to a set of attributes being applied to it. It globally localises those attributes which have a type in the pAffectedAttrTypes set.
pLocalisedCompounds: An optional set of compounds which have already had all attributes in the pAffectedAttrTypes localised. If Object has a parent compound which is in this set then its attributes will not need to be localised again.
After a compound object has localised its children it will be added to the pLocalisedCompounds set if this has been provided. After the attribute has been applied you should call DoFactorOutAfterAttrChange If the object discards its attribute children then the routine does nothing (eg. the caret) Note: When applying attributes, we are not always going to apply the attributes to the object itself, sometimes we need to apply them to the object's parent. Eg. when we apply a line based attribute to a text character the attributes will get applied to the parent TextLine. In this situation we do not localise the objects attributes, but its parents attributes instead. Warning ~~~~~~~ All attribute types in the AttrTypeSet must be localised on the same compound node. This means for example that the AttrType set cannot contain a Bold and a Line space attribute. If we need to do this in future then the routine will need to be changed.
Definition at line 2864 of file undoop.cpp. 02867 { 02868 CCRuntimeClass* AttrType; 02869 // Determine if the attribute will get applied to this object, or an alternative object 02870 // (probably its parent) 02871 if (pAffectedAttrTypes && (!pAffectedAttrTypes->IsEmpty())) 02872 { 02873 AttrType = ((AttrTypeItem*)pAffectedAttrTypes->GetHead())->AttributeType; 02874 ERROR3IF(!AttrType, "AttrType set contains NULL attribute type"); 02875 Object = Object->GetObjectToApplyTo(AttrType); 02876 } 02877 02878 { 02879 02880 02881 // If the object has not got a compound parent then there will be no attributes 02882 // to localise, so we need not do anything 02883 02884 Node* pParent; 02885 pParent = Object->FindParent(); 02886 ERROR3IF(!pParent, "UndoableOperation::DoLocaliseForAttrChange called on an object which has no parent"); 02887 02888 if (pParent->IsCompound()) 02889 { 02890 // Before we attempt to localise the compound's attributes let's check that they are not 02891 // already localised. 02892 02893 if (pLocalisedCompounds) 02894 { 02895 if (pLocalisedCompounds->InSet((NodeRenderableInk*)pParent)) 02896 { 02897 return TRUE; // Attributes are already localised so there is no need to localise again ! 02898 } 02899 else 02900 { 02901 pLocalisedCompounds->AddToSet((NodeRenderableInk*)pParent); // Record that the compound has been localised 02902 } 02903 } 02904 02905 return (DoLocaliseCommonAttributes((NodeRenderableInk*)pParent, // We are localising the compound's attrs 02906 FALSE, // No need to check for duplicates 02907 TRUE, // Localise globally 02908 pAffectedAttrTypes)); // Only attributes of these types 02909 } 02910 02911 } 02912 return TRUE; 02913 }
|
|
This functio will create a new nodepath and attach it in the specified direction to the context node specified. It will also copy attributes applied as children of the ConextNode to the new node if required.
Definition at line 2280 of file undoop.cpp. 02284 { 02285 // Create the node path object we will stick in the tree. 02286 NodePath* pChildNode; 02287 02288 ALLOC_WITH_FAIL(pChildNode, new NodePath(), this); 02289 02290 if (!pChildNode) 02291 return FALSE; 02292 02293 BOOL ok; 02294 // make room for the new path in the node path. 02295 CALL_WITH_FAIL 02296 ( 02297 pChildNode->SetUpPath(pParentPath->GetNumCoords(),12), 02298 this,ok 02299 ); 02300 02301 if (!ok) 02302 { 02303 delete pChildNode; 02304 return FALSE; 02305 } 02306 02307 // now copy the path data in there. 02308 pChildNode->InkPath.CopyPathDataFrom(pParentPath); 02309 02310 if (CopyAttributes) 02311 { 02312 CCAttrMap * AttribMap = NULL; 02313 AttribMap = CCAttrMap::MakeAppliedAttrMap(pParentNode); 02314 02315 if (AttribMap) 02316 { 02317 AttribMap->ApplyAttributesToNode (pChildNode); 02318 } 02319 } 02320 02321 // Now stick the new path into the tree 02322 CALL_WITH_FAIL 02323 ( 02324 DoInsertNewNode(pChildNode, pParentNode, Direction, TRUE, FALSE), 02325 this,ok 02326 ); 02327 02328 // if we've failed tidy up 02329 if (!ok) 02330 { 02331 pChildNode->CascadeDelete(); 02332 delete pChildNode; 02333 return FALSE; 02334 } 02335 return TRUE; 02336 }
|
|
This low level Do function calls the DoBecomeA virtual function on all SelectedNodes. It is the node's DoBecomeA function which is responsible for generating actions.
Definition at line 1771 of file undoop.cpp. 01772 { 01773 Node* CurrentNode = NodeRange.FindFirst(); 01774 Node* Next; 01775 01776 while (CurrentNode != NULL) 01777 { 01778 // BODGE - since the group is selected and won't be replaced by anything else, no need to reselect it 01779 // this fixes a bug where make shapes on grouped text stories/molds/blends don't leave the parent group 01780 // selected but selects the objects inside! 01781 BOOL reselect = !IS_A(CurrentNode,NodeGroup) && !IS_A(CurrentNode,NodeBlend); 01782 01783 BecomeA BecomeAPath(BECOMEA_REPLACE,CC_RUNTIME_CLASS(NodePath), this, reselect); 01784 Next = NodeRange.FindNext(CurrentNode); 01785 if (!(CurrentNode->DoBecomeA(&BecomeAPath))) 01786 { 01787 // Operation failed 01788 return FALSE; 01789 } 01790 CurrentNode = Next; 01791 } 01792 return TRUE; // Success 01793 }
|
|
This high level function moves NodeToMove from its current position in the tree, and attaches it to Destination in the direction specified by Direction.
Definition at line 968 of file undoop.cpp. 00972 { 00973 ERROR2IF(NodeToMove->IsAnAttribute() && !((NodeAttribute*)NodeToMove)->IsEffectAttribute(), FALSE, "Trying to move an attribute, this is bad"); 00974 00975 // -------------------------------------------------------------------- 00976 // We have to move attributes by copying... 00977 if (NodeToMove->IsAnAttribute()) 00978 { 00979 // Copy the attribute to the destination location 00980 // Then hide the original 00981 00982 // Copy 00983 NodeAttribute* pCopyAttr = NULL; 00984 BOOL bOK = FALSE; 00985 CALL_WITH_FAIL(((NodeAttribute*)NodeToMove)->NodeCopy((Node**)&pCopyAttr), this, bOK); 00986 if (!bOK) return FALSE; // No room to take a copy of the node 00987 00988 // Create a hide node action to hide the node when we undo 00989 pCopyAttr->AttachNode(Destination, Direction); 00990 HideNodeAction* UndoHideNodeAction; 00991 if (HideNodeAction::Init(this, this->GetUndoActions(), pCopyAttr, TRUE, (Action**)(&UndoHideNodeAction)) 00992 == AC_FAIL) 00993 { 00994 pCopyAttr->CascadeDelete(); 00995 delete pCopyAttr; 00996 return FALSE; 00997 } 00998 00999 // Hide 01000 if (!DoHideNode(NodeToMove, TRUE, NULL, TRUE)) 01001 return FALSE; 01002 01003 return TRUE; 01004 } 01005 01006 // -------------------------------------------------------------------- 01007 // Objects are physically moved, leaving a NodeHidden in the original location 01008 // with a "hyperspace" reference to the object in its final location. 01009 // 01010 // We must flag that we are only moving the node, so we don't 01011 // try and called the 'Hiding Node' function, which should only 01012 // be called when we are 'Really' hiding the node. 01013 MovingNode = TRUE; 01014 01015 // Find out if the node is selected 01016 BOOL IsSelected = NodeToMove->IsSelected(); 01017 01018 // Before we move the object determine what the source layer is 01019 Layer* pSrcLayer = NULL; 01020 if (NodeToMove->IsAnObject()) 01021 { 01022 // Only consider ink nodes 01023 pSrcLayer = (Layer*) (NodeToMove->FindParent(CC_RUNTIME_CLASS(Layer))); 01024 } 01025 01026 // Hide it 01027 HideNodeAction* UndoHideNodeAction; 01028 // NodeRenderableBounded* pBounded = NULL; 01029 01030 // hide the node 01031 if (!DoHideNode(NodeToMove, FALSE, NULL, FALSE)) 01032 goto Failed; 01033 01034 // build the action 01035 if ( HideNodeAction::Init(this, 01036 &UndoActions, 01037 NodeToMove, 01038 FALSE, // Don't include the 01039 // subtree size 01040 (Action**)(&UndoHideNodeAction), 01041 01042 FALSE) // Don't tell subtree 01043 == AC_FAIL) 01044 { 01045 goto Failed; 01046 }; 01047 01048 // Move the node to its new location 01049 NodeToMove->MoveNode(Destination, Direction); 01050 if (IsSelected) 01051 NodeToMove->SetSelected(IsSelected); 01052 01053 MovingNode = FALSE; 01054 01055 if (NodeToMove->IsAnObject()) 01056 { 01057 // If the object has moved to a new layer then we need to invalidate both old and new 01058 // layers 01059 Layer* pDestLayer = (Layer*) (NodeToMove->FindParent(CC_RUNTIME_CLASS(Layer))); 01060 if ((pSrcLayer != pDestLayer) && pSrcLayer && pDestLayer) 01061 { 01062 pSrcLayer->InvalidateBoundingRect(); 01063 pDestLayer->InvalidateBoundingRect(); 01064 } 01065 01066 if (pSrcLayer) 01067 { 01068 // Note that this layer has been edited 01069 pSrcLayer->SetEdited(TRUE); 01070 //#ifdef _DEBUG 01071 // // Tell the frame gallery to update its display of the frame 01072 // BROADCAST_TO_ALL(LayerMsg(pSrcLayer, LayerMsg::LayerReason::REDRAW_LAYER)); 01073 //#endif 01074 } 01075 01076 if (pDestLayer && (pSrcLayer != pDestLayer)) 01077 { 01078 // Note that this layer has been edited 01079 pDestLayer->SetEdited(TRUE); 01080 //#ifdef _DEBUG 01081 // // Tell the frame gallery to update its display of the frame 01082 // BROADCAST_TO_ALL(LayerMsg(pDestLayer, LayerMsg::LayerReason::REDRAW_LAYER)); 01083 //#endif 01084 } 01085 01086 } 01087 // finish happy 01088 return (TRUE); 01089 01090 Failed: 01091 MovingNode = FALSE; // Ensure we clear this is an error occurred 01092 return FALSE; 01093 }
|
|
This high level function moves the range of nodes from their current position in the tree, and attaches them to the Destination node in the direction specified by Direction.
Definition at line 902 of file undoop.cpp. 00905 { 00906 Node* Current = NodeRange.FindFirst(); // Get the first node to move 00907 ENSURE(Current != NULL, "Trying to move an empty range"); 00908 00909 Node* NextNode = NodeRange.FindNext(Current); 00910 00911 // Attach the first node in the range to the Destination node in the direction specified 00912 if (!DoMoveNode(Current, Destination, Direction)) 00913 { 00914 return FALSE; // Failed to move Current 00915 } 00916 00917 Node* PrevNode = Current; 00918 00919 // Get the next node in the range 00920 Current = NextNode; 00921 00922 // Attach all other nodes in the range 00923 while (Current != NULL) 00924 { 00925 NextNode = NodeRange.FindNext(Current); 00926 if (!DoMoveNode(Current, PrevNode, NEXT)) 00927 { 00928 return FALSE; // Failed to move Current 00929 } 00930 PrevNode = Current; 00931 Current = NextNode; 00932 } 00933 return TRUE; 00934 }
|
|
Searches the subtree and every attribute which has type AttrType is hidden. BOOL UndoableOperation::DoRemoveAttrTypeFromSubtree(Node* Subtree, RuntimeClass* AttrType, Node* pExceptThis = NULL);
Definition at line 1925 of file undoop.cpp. 01926 { 01927 // Traverse the subtree depth first 01928 Node* Current = Subtree->FindFirstDepthFirst(); 01929 Node* Next; 01930 while (Current != NULL) 01931 { 01932 Next = Current->FindNextDepthFirst(Subtree); 01933 // Determine if the Current node is to be hidden 01934 if (Current!=pExceptThis && Current->IsKindOf(CC_RUNTIME_CLASS(NodeAttribute))) 01935 { 01936 if (((NodeAttribute*)Current)->GetAttributeType() == AttrType) 01937 { 01938 if (Current->FindParent()->DiscardsAttributeChildren()) 01939 { 01940 Current->CascadeDelete(); 01941 delete Current; 01942 } 01943 else 01944 { 01945 if(!DoHideNode(Current, 01946 TRUE // Include the subtree size 01947 )) 01948 { 01949 return FALSE; // Operation failed 01950 } 01951 } 01952 } 01953 } 01954 Current = Next; 01955 } 01956 return TRUE; 01957 }
|
|
This 'Do' function reverse a path, recording undo information.
Definition at line 3960 of file undoop.cpp. 03961 { 03962 PathVerb* Verbs = NULL; 03963 PathFlags* Flags = NULL; 03964 DocCoord* Coords = NULL; 03965 ThisPath->InkPath.GetPathArrays(&Verbs, &Coords, &Flags); 03966 INT32 NumCoords = ThisPath->InkPath.GetNumCoords(); 03967 //BOOL PrevSelected = FALSE; 03968 //INT32 PrevPos = 0; 03969 03970 Document* pDocument = GetWorkingDoc(); 03971 Spread* pSpread = ThisPath->FindParentSpread(); 03972 03973 if (RedrawPath) 03974 { 03975 // Mark the region as requiring object to recache any cached 03976 // data they may be holding because the Op may have changed it 03977 DocRect Invalid = ThisPath->GetUnionBlobBoundingRect(); 03978 pDocument->ForceRedraw( pSpread, Invalid, FALSE, ThisPath ); 03979 } 03980 03981 Path* NewEditPath = new Path (); 03982 03983 if (!NewEditPath) { return (FALSE); } 03984 03985 if (!NewEditPath->Initialise(NumCoords, 24)) 03986 { 03987 return FALSE; 03988 } 03989 03990 // for the new reversed path .... 03991 03992 PathVerb* Verbs2 = NULL; 03993 PathFlags* Flags2 = NULL; 03994 DocCoord* Coords2 = NULL; 03995 NewEditPath->GetPathArrays(&Verbs2, &Coords2, &Flags2); 03996 03997 NewEditPath->CopyPathDataFrom (&(ThisPath->InkPath)); 03998 03999 // the following loop as been optimised since this is the main part of the alg 04000 // (which just reverses the supplied path) .... 04001 04002 NewEditPath->Reverse (); 04003 04004 // now lets build an undo record .... 04005 04006 ModifyPathAction* ModAction; // since thats what were doing 04007 04008 ActionCode Act; 04009 Act = ModifyPathAction::Init(this, &UndoActions, NumCoords, (Action**)(&ModAction)); 04010 if (Act == AC_FAIL) 04011 { 04012 FailAndExecute(); 04013 End(); 04014 return FALSE; 04015 } 04016 04017 // for use with the action .... 04018 04019 PathVerb* ChangedVerbs = NULL; 04020 DocCoord* ChangedCoords = NULL; 04021 PathFlags* ChangedFlags = NULL; 04022 INT32* ChangedIndices = NULL; 04023 04024 // If the function returned AC_NO_RECORD we shouldn't record any undo information in the action 04025 // NOTE - during unwind all actions return AC_OK with a NULL ModAction pointer!! 04026 if ((Act!=AC_NORECORD) && (ModAction!=NULL)) 04027 { 04028 // This next bit is a bit hellish. Any one of these four allocations can fail, in which case 04029 // we have to tidy up afterwards. Cue a lot of nested ifs and elses. 04030 04031 ALLOC_WITH_FAIL(ChangedVerbs,(PathVerb*) CCMalloc(NumCoords * sizeof(PathVerb)),this); 04032 if (ChangedVerbs) 04033 { 04034 ALLOC_WITH_FAIL(ChangedCoords,(DocCoord*) CCMalloc(NumCoords * sizeof(DocCoord)),this); 04035 if (ChangedCoords) 04036 { 04037 ALLOC_WITH_FAIL(ChangedFlags,(PathFlags*) CCMalloc(NumCoords * sizeof(PathFlags)),this); 04038 if (ChangedFlags) 04039 { 04040 ALLOC_WITH_FAIL(ChangedIndices,(INT32*) CCMalloc(NumCoords * sizeof(INT32)),this); 04041 if (!ChangedIndices) 04042 { 04043 CCFree( ChangedFlags ); 04044 CCFree( ChangedCoords ); 04045 CCFree( ChangedVerbs); 04046 FailAndExecute(); 04047 End(); 04048 return FALSE; 04049 } 04050 } 04051 else 04052 { 04053 CCFree( ChangedCoords ); 04054 CCFree( ChangedVerbs ); 04055 FailAndExecute(); 04056 End(); 04057 return FALSE; 04058 } 04059 } 04060 else 04061 { 04062 CCFree( ChangedVerbs); 04063 FailAndExecute(); 04064 End(); 04065 return FALSE; 04066 } 04067 } 04068 04069 // Now to put the undo data into the undo action 04070 for (INT32 loop = 0; loop < NumCoords; loop++) 04071 { 04072 ChangedVerbs [loop] = Verbs [loop]; 04073 ChangedFlags [loop] = Flags [loop]; 04074 ChangedCoords [loop] = Coords [loop]; 04075 ChangedIndices [loop] = loop; 04076 } 04077 04078 // Now we've allocated the arrays, let's tell the action about 'em 04079 ModAction->StoreArrays (ChangedVerbs, ChangedFlags, ChangedCoords, ChangedIndices, ThisPath);//pOrigPath); 04080 04081 } 04082 04084 04085 // now we update the supplied path with the new path .... 04086 04087 ThisPath->InkPath.CopyPathDataFrom (NewEditPath); 04088 04089 delete (NewEditPath); // and clean up 04090 04091 if (ThisPath->IsANodeBlendPath ()) 04092 { 04093 ((NodeBlendPath*) ThisPath)->DestroyCachedInformation (); 04094 } 04095 04097 04098 ThisPath->InvalidateBoundingRect(); 04099 04100 if (RedrawPath) 04101 { 04102 DocRect Invalid = ThisPath->GetUnionBlobBoundingRect(); 04103 // Mark the region as requiring object to recache any cached 04104 // data they may be holding because the Op may have changed it 04105 pDocument->ForceRedraw( pSpread, Invalid, FALSE, ThisPath ); 04106 } 04107 return (TRUE); 04108 }
|
|
This fn saves a copy of the node in the operation history. When the operation is undone the copy is restored.
Definition at line 1186 of file undoop.cpp. 01187 { 01188 ENSURE((!OpFlags.Failed), "Calling a DO function after operation has failed"); 01189 RangeControl rc( TRUE, TRUE, TRUE ); // All nodes in range 01190 Range range( Node, Node, rc ); 01191 return DoSaveCopyOfNodes( range ); 01192 }
|
|
This fn takes a copy of the nodes in the range. The copies are restored when the operation is undone.
Definition at line 1115 of file undoop.cpp. 01116 { 01117 Node* Current = NodeRange.FindFirst(); 01118 BOOL CopiedOK; 01119 Node* TheCopy; 01120 HideNodeAction* UndoHideNodeAction; 01121 while (Current != NULL) 01122 { 01123 // Salary check 01124 if (!Current->IsBounded()) 01125 { 01126 ERROR3("Current is not a NodeRenderable node"); 01127 continue; 01128 } 01129 01130 // Make a copy of Current 01131 CALL_WITH_FAIL(Current->NodeCopy(&TheCopy), this, CopiedOK); 01132 if (!CopiedOK) 01133 { 01134 return FALSE; // No room to take a copy of the node 01135 } 01136 01137 // We need to insert the new node into the tree, but we can't use DoInsertNewNode 01138 // as this will insert an unwanted NideNode action 01139 TheCopy->AttachNode(Current, PREV); 01140 TheCopy->SetSelected(FALSE); 01141 ((NodeRenderableBounded*)TheCopy)->ValidateBoundingRect(); 01142 ((NodeRenderableBounded*)TheCopy)->InvalidateBoundingRect(); 01143 01144 // Hide the copy, creating a ShowNodeAction to show the copy when we undo 01145 if (!DoHideNode(TheCopy, 01146 TRUE // The hidden node is in the operation history 01147 ) 01148 ) 01149 { 01150 return FALSE; 01151 } 01152 01153 // Create a Hide node action to hide the current node when we undo 01154 if ( HideNodeAction::Init(this, 01155 &UndoActions, 01156 Current, 01157 FALSE, 01158 (Action**)(&UndoHideNodeAction)) 01159 == AC_FAIL) 01160 { 01161 return FALSE; 01162 }; 01163 01164 Current = NodeRange.FindNext(Current); 01165 } 01166 return TRUE; 01167 }
|
|
The function selects NodeToSelect. It also generates an action which will deselect the node when executed.
Definition at line 1416 of file undoop.cpp. 01417 { 01418 SelectDeselectAction* UndoSelectDeselectAction; 01419 // Create an action to deselect the NodeToSelect when we undo. 01420 if ( SelectDeselectAction::Init(this, 01421 &UndoActions, 01422 NodeToSelect, 01423 Parent, 01424 (Action**)(&UndoSelectDeselectAction)) 01425 != AC_FAIL) 01426 { 01427 // We shall be able to deselect the object if we fail so select it. 01428 NodeToSelect->Select(FALSE); 01429 return (TRUE); 01430 } 01431 else 01432 return (FALSE); 01433 }
|
|
This function will smooth a node path given an accuracy. It will create a new node in the tree after the node specified and hide node passed if all is succesfull.
Definition at line 2213 of file undoop.cpp. 02214 { 02215 #ifndef STANDALONE 02216 02217 // Copy the nodepath and all its children, without placing the copy in the tree 02218 Node* pnode; 02219 if (!pThisNode->NodeCopy(&pnode)) 02220 return FALSE; 02221 NodePath* pSmoothNode = (NodePath*)pnode; 02222 02223 // ok, smooth the nodepaths path data 02224 if (!pSmoothNode->InkPath.SmoothRegions(smoothacc, FALSE, TRUE)) 02225 goto smoothfailed; 02226 02227 // update the smoothed paths bounding rectangle 02228 pSmoothNode->InvalidateBoundingRect(); 02229 02230 // Now stick the new path into the tree 02231 if (!DoInsertNewNode(pSmoothNode, pThisNode, NEXT, TRUE)) 02232 goto smoothfailed; 02233 02234 // Now we've formed a smoothed path, let's hide the original 02235 if (!DoHideNode(pThisNode,TRUE)) 02236 goto smoothfailed; 02237 02238 #endif 02239 02240 // return all is well 02241 return TRUE; 02242 02243 #ifndef STANDALONE 02244 02245 // failed to smooth the node so time to tidy up. 02246 smoothfailed: 02247 pSmoothNode->CascadeDelete(); 02248 delete pSmoothNode; 02249 return FALSE; 02250 02251 #endif 02252 }
|
|
This high level Do function applies the transform Trans to the NodeToTransform.
Definition at line 1389 of file undoop.cpp. 01391 { 01392 ENSURE((!OpFlags.Failed), "Calling a DO function after operation has failed"); 01393 // RangeControl rc = { TRUE, TRUE, TRUE }; // All nodes in range 01394 Range range( NodeToTransform, NodeToTransform, RangeControl( TRUE, TRUE, TRUE ) ); 01395 return( DoTransformNodes( range, Trans ) ); 01396 }
|
|
This high level Do function applies the transform Trans to each object in the range.
Don't delete the Trans object, it's deleted in TransformNodeAction slaughter method.
Definition at line 1221 of file undoop.cpp. 01223 { 01224 // If the Trans is invertible then create a Transform node action to undo the transform 01225 // Note at this point Trans is not the inverse Transformation, but it will be soon !! 01226 // Node * pParent = NULL; 01227 // Node * pNodeToTransform = NULL; 01228 01229 // DMc 17/5/99 01230 // include the parent nodes in the range if they wish to be transformed with 01231 // their children by changing the range control flags 01232 RangeControl rg = NodeRange.GetRangeControlFlags(); 01233 rg.PromoteToParent = TRUE; 01234 NodeRange.Range::SetRangeControl(rg); 01235 01236 // DoInvalidateNodesRegions(NodeRange, TRUE); 01237 DoInvalidateNodesRegions(NodeRange, TRUE, FALSE, FALSE, FALSE); // Don't forcibly recache (see bHaveTransformedAllCached) 01238 01239 if (Trans->IsInvertable()) 01240 { 01241 TransformNodeAction* UndoTransformNodeAction; 01242 01243 if ( TransformNodeAction::Init(this, 01244 &UndoActions, 01245 NodeRange, 01246 Trans, 01247 NULL, 01248 (Action**)(&UndoTransformNodeAction)) 01249 == AC_FAIL) 01250 01251 { 01252 delete Trans; // for consistency 01253 return FALSE; // Let's get out while we can 01254 }; 01255 01256 // Scan the range and transform each node 01257 Node* Current = NodeRange.FindFirst(); 01258 Node* Next; 01259 // Node* Parent = NULL; 01260 // BOOL bTransform = FALSE; 01261 while (Current != NULL) 01262 { 01263 Next = NodeRange.FindNext(Current); 01264 01265 if (Current->IsNodeRenderableClass()) 01266 { 01267 // Prepare Control and Feedback flags 01268 Trans->bHaveTransformedCached = TRUE; 01269 Trans->bHaveTransformedChildren = TRUE; 01270 Trans->bTransformYourChildren = TRUE; 01271 01272 ((NodeRenderable *)Current)->Transform(*Trans); 01273 01274 // Compute feedback flags for caller 01275 Trans->bHaveTransformedAllCached = Trans->bHaveTransformedAllCached && Trans->bHaveTransformedCached; 01276 Trans->bHaveTransformedAllChildren = Trans->bHaveTransformedAllChildren && Trans->bHaveTransformedChildren; 01277 01278 // ---------------------------------------------- 01279 // Now do smart testing to see whether we can retain any cached info the node was holding 01280 if (Current->IsBounded()) 01281 { 01282 NodeRenderableBounded* pCurrentBound = (NodeRenderableBounded*) Current; 01283 01284 // If we have transformed all cached data successfully 01285 // And 01286 // We are translating (in which case the cached data will remain usable) 01287 // Or 01288 // The node was Direct (in which case the cached data comes from outside the tree where it can't have been transformed) 01289 // Then 01290 // Don't force the recacheing of the data for this node, just its parents 01291 if (Trans->bHaveTransformedCached && (Trans->IsTranslation() || pCurrentBound->HasCachedDirectBitmap())) 01292 // Yes, we can keep our cached info but we must tell our parents we have changed 01293 pCurrentBound->ReleaseCached(TRUE, FALSE, FALSE, TRUE); // Parents and derived data only 01294 else 01295 // No we can't keep our cached info 01296 pCurrentBound->ReleaseCached(TRUE, TRUE); 01297 } 01298 // ---------------------------------------------- 01299 } 01300 01301 // JCF BODGE 01302 #ifdef _DEBUG 01303 else 01304 { 01305 TRACE( _T("Warning: UndoableOperation::DoTransformNodes: ") 01306 _T("Current node %s is not a NodeRenderableInk\n"), 01307 (LPCTSTR) Current->Name()); 01308 } 01309 #endif 01310 01311 Progress::Update(); 01312 Current = Next; 01313 } 01314 01315 // Invert the Trans which is in the TransformNodeAction 01316 ((TransInvertable*)Trans)->Invert(); 01317 } 01318 else // The Trans is not invertable 01319 { 01320 // We will have to go through all node in the range, making a copy and transforming it. 01321 // This used to use DoSaveCopyOfNodes, but this dosen't work as it is not completly undoable 01322 Node* Current = NodeRange.FindFirst(); 01323 Node* Next = NULL; 01324 while (Current != NULL) 01325 { 01326 Next = NodeRange.FindNext(Current); 01327 if (Current->IsNodeRenderableClass()) 01328 { 01329 // Make a copy of Current 01330 BOOL CopiedOK = TRUE; 01331 Node* TheCopy = NULL; 01332 CALL_WITH_FAIL(Current->NodeCopy(&TheCopy), this, CopiedOK); 01333 if (!CopiedOK) 01334 return FALSE; 01335 01336 // transform the copy 01337 ((NodeRenderable*)TheCopy)->Transform(*Trans); 01338 01339 // put the copy into the tree 01340 if (!DoInsertNewNode((NodeRenderableBounded*)TheCopy, Current, PREV, TRUE, FALSE)) 01341 { 01342 delete TheCopy; 01343 return FALSE; 01344 } 01345 01346 // Hide the original 01347 if (!DoHideNode(Current, FALSE)) 01348 return FALSE; 01349 } 01350 01351 // JCF BODGE 01352 #ifdef _DEBUG 01353 else 01354 { 01355 TRACE( _T("Warning: UndoableOperation::DoTransformNodes: ") 01356 _T("Current node %s is not a NodeRenderableInk\n"), 01357 (LPCTSTR) Current->Name()); 01358 } 01359 #endif 01360 01361 Progress::Update(); 01362 Current = Next; 01363 } 01364 } 01365 return (TRUE); // Success 01366 }
|
|
Reimplemented in SelOperation. Definition at line 520 of file undoop.h. 00520 { return FALSE; }
|
|
Transforms the node, checking if any parents need to transform too.
Definition at line 4240 of file undoop.cpp. 04241 { 04242 // do this by changing the selection, and then restoring it 04243 // first, save the current selection 04244 List * pSelList = GetApplication()->FindSelection()->MakeListOfNodes(TRUE); 04245 List * pRngList = Rng->MakeListOfNodes(FALSE); 04246 04247 NodeRenderableInk::DeselectAll(); 04248 04249 NodeListItem * pItem = (NodeListItem *)pRngList->GetHead(); 04250 Node * pParent = NULL; 04251 04252 while (pItem) 04253 { 04254 if (pItem->pNode) 04255 { 04256 if (pItem->pNode->IsRenderable()) 04257 { 04258 pItem->pNode->SetSelected(TRUE); 04259 04260 pParent = pItem->pNode->FindParent(); 04261 04262 while (pParent) 04263 { 04264 if (pParent->ShouldITransformWithChildren()) 04265 { 04266 pParent->SetSelected(TRUE); 04267 } 04268 04269 pParent = pParent->FindParent(); 04270 } 04271 } 04272 } 04273 04274 pItem = (NodeListItem *)pRngList->GetNext(pItem); 04275 } 04276 04277 pRngList->DeleteAll(); 04278 delete pRngList; 04279 04280 // update the selection range and make a copy of it 04281 GetApplication()->UpdateSelection(); 04282 04283 Range * RetnRng = new Range(*(GetApplication()->FindSelection())); 04284 04285 // restore the selection 04286 NodeRenderableInk::DeselectAll(); 04287 04288 pItem = (NodeListItem *)pSelList->GetHead(); 04289 04290 while (pItem) 04291 { 04292 if (pItem->pNode) 04293 { 04294 pItem->pNode->SetSelected(TRUE); 04295 } 04296 04297 pItem = (NodeListItem *)pSelList->GetNext(pItem); 04298 } 04299 04300 // update the selection range and make a copy of it 04301 GetApplication()->UpdateSelection(); 04302 04303 pSelList->DeleteAll(); 04304 delete pSelList; 04305 04306 // set the range control flags 04307 RangeControl rg = RetnRng->GetRangeControlFlags(); 04308 rg.PromoteToParent = TRUE; 04309 04310 RetnRng->SetRangeControl(rg); 04311 04312 return RetnRng; 04313 }
|
|
|
Moves all the actions in this operation to the end of the previous action, then deletes this action.
Definition at line 4187 of file undoop.cpp. 04188 { 04189 // Obtain a pointer to the operation history for the operation's document 04190 OperationHistory* pOpHist = &GetWorkingDoc()->GetOpHistory(); 04191 if (pOpHist == NULL) 04192 { 04193 ERROR3("There's no OpHistory!?"); 04194 return; 04195 } 04196 04197 // Ensure that we are the last operation added to the operation history 04198 if (pOpHist->FindLastOp() != this) 04199 { 04200 ERROR3("Last Op should be this op"); 04201 return; 04202 } 04203 04204 Operation* pPrevOp = pOpHist->FindPrevToLastOp(); 04205 if (pPrevOp != NULL) 04206 { 04207 // Copy all the actions from us to the end of the action list in the previous op. 04208 ActionList* pPrevActions = pPrevOp->GetUndoActionList(); 04209 ActionList* pPrevOtherActions = pPrevOp->GetRedoActionList(); 04210 if ((pPrevActions == NULL) || (pPrevOtherActions == NULL)) 04211 { 04212 ERROR3("Previous actions list pointer was NULL"); 04213 return; 04214 } 04215 04216 // Copy actions across 04217 Action* pCurrentAction = (Action*)UndoActions.RemoveHead(); 04218 while (pCurrentAction != NULL) 04219 { 04220 pCurrentAction->TransferToOtherOp(pPrevOp, pPrevActions, pPrevOtherActions); 04221 pCurrentAction = (Action*)UndoActions.RemoveHead(); 04222 } 04223 } 04224 04225 // And remove ourself 04226 pOpHist->DeleteLastOp(); 04227 }
|
|
This is *not* an override of Operation::UpdateChangedNodes(..., Document*), although it performs *almost* exactly the same job. It is provided solely for NameGallery::PostTriggerEdit to call in order to get all affected nodes to update themselves correctly after a stretch. PostTriggerEdit is itself called in response to normal UpdateChangedNodes calls, so this avoids recursion problems.
Definition at line 4389 of file undoop.cpp. 04390 { 04391 ERROR2IF(pParam == NULL, FALSE, "pParam == NULL"); 04392 ERROR2IF(pDoc == NULL, FALSE, "pDoc == NULL"); 04393 04394 BOOL ok = TRUE; 04395 Chapter* pChapter = Node::FindFirstChapter(pDoc); 04396 while (pChapter != NULL && ok) 04397 { 04398 // Now find the first child of the Chapter, because this is the level at which Spreads hang out 04399 Node* pNode = pChapter->FindFirstChild(); 04400 04401 // Update changed nodes in each of the chapter's spreads. We *don't* call 04402 // Operation::UpdateChangedNodes(..., Spread*), as that would lead to recursion... 04403 while (pNode != NULL && ok) 04404 { 04405 if (pNode->IsSpread()) 04406 { 04407 Spread* pSpread = (Spread*)pNode; 04408 ok = UpdateChangedNode(pParam, pSpread->FindFirstChild()); 04409 } 04410 04411 pNode = pNode->FindNext(); 04412 } 04413 04414 pChapter = pChapter->FindNextChapter(); 04415 } 04416 04417 return ok; 04418 }
|
|
This function gets called from the Operation::EndOp method after the operation has ended successfuly and been added to the operation history. If the operation could potentially merge itself with the previous operation then perform this merging here.
Here are some rules: 1. Note that this function cannot fail - doing so would really be quite scarry. If however you find yourself running out of memory in this function then simply tidyup (leaving things how they were) and then return. 2. After this function has been invoked the operation history size must not be greater than it was prior to the function getting called. It would be quite unimpressive if this was the case anyway. 3. In many cases you will want to delete 'this' operation from this function. so just be careful huh! The way that you merge the operation is basically up to you, however here are a few pointers. The first thing you should do on entering this function is to check that the last Operation added to the operation history is this operation. Call OperationHistory::FindLastOp to verify this within an ERROR2 Macro. Next you will probably want to check if the previous operation performed can be merged with this op. To obtain the previous op call OperationHistory::FindPrevToLastOp. Testing the runtime class of this op is probably enough for you to determine if a merge can take place or not. Usually you will want to augment the previous operation in some way so that it includes the function which was performed by this operation. This could involve changing an action in the previous operation, adding new actions etc.
Reimplemented in OpApplyAttrInteractive, OpMakeColourLocalToFrame, OpColourChange, OpNudge, OpPathNudge, OpTextKern, and OpDeleteTextStory. Definition at line 4168 of file undoop.cpp.
|
|
This function should be called from the operations Init method. It creates an OpDescriptor for the operation. static BOOL UndoableOperation::RegisterOpDescriptor( UINT32 toolID, UINT32 txID, CCRuntimeClass* RuntimeClass, TCHAR* tok, pfnGetState gs, UINT32 helpId, UINT32 bubbleID , UINT32 resourceID, UINT32 controlID, SystemBarType GroupBarID, BOOL ReceiveMessages, BOOL Smart, BOOL Clean, UINT32 OneOpenInstID, UINT32 AutoStateFlags)
Definition at line 3801 of file undoop.cpp. 03817 { 03818 // tok is going into a string which turns out to be a string 32, so do a sanity check (Neville 26/6/97) 03819 size_t len = camStrclen(tok); 03820 ERROR2IF(len > 32,FALSE,"UndoableOperation::RegisterOpDescriptor token buffer overflow!"); 03821 03822 // Try to create the OpDescriptor 03823 UndoableOpDescriptor* OpDesc = new UndoableOpDescriptor( 03824 toolID, 03825 txID, 03826 RuntimeClass, 03827 tok, 03828 gs, 03829 helpId, 03830 bubbleID, 03831 resourceID, 03832 controlID, 03833 ReceiveMessages, 03834 Smart, 03835 Clean, 03836 OneOpenInstID, 03837 AutoStateFlags 03838 ); 03839 03840 ERRORIF(!OpDesc, _R(IDE_NOMORE_MEMORY), FALSE); 03841 return TRUE; 03842 }
|
|
This function overrides its namesake in Operation, calling the base function first and then adding a call to NameGallery::PostTriggerEdit if this Op admits it may change the bounds of nodes within the tree.
Reimplemented from Operation. Definition at line 4338 of file undoop.cpp. 04339 { 04340 ERROR2IF(pParam == NULL, FALSE, "pParam == NULL"); 04341 BOOL ok = Operation::UpdateChangedNodes(pParam, pSpread); 04342 04344 // Karim MacDonald 19/01/2000. 04345 // If the call to the base class was successful, then we can try to call 04346 // NameGallery::PostTriggerEdit, to allow any nodes marked for stretching to 04347 // change in response to any bounds changes in the tree. 04348 if (ok) 04349 { 04350 // When querying the Op responsible for the change, I've decided to use 'this'. 04351 // Could've asked pParam for the Op's pointer, but 'this' is probably more reliable. 04352 UndoableOperation* pChangeOp = this;// pParam->GetOpPointer(); 04353 if (pChangeOp != NULL && pChangeOp->MayChangeNodeBounds() && NameGallery::Instance()) 04354 { 04355 NameGallery::Instance()->PostTriggerEdit(pChangeOp, pParam); 04356 } 04357 } 04359 04360 return ok; 04361 }
|
|
|
|
|