BOOL OpRetroFit::BuildUndo(NodePath* pPreviousNode, NodePath* pNewNode) { // A few quick error checks ENSURE(pPreviousNode!=NULL, "Previous Node was NULL in RetroFit::BuildUndo()"); ENSURE(pPreviousNode->IsKindOf(CC_RUNTIME_CLASS(NodePath)), "Previous Node not a path"); ENSURE(pNewNode!=NULL, "New Node was NULL in RetroFit::BuildUndo()"); ENSURE(pNewNode->IsKindOf(CC_RUNTIME_CLASS(NodePath)), "New Node not a path"); // Falg to see if it has worked BOOL IsOperationOk = TRUE; // Start the undo of the selected item IsOperationOk = DoStartSelOp(FALSE); // Will the node allow this op to take place? ObjChangeFlags cFlags; cFlags.ReplaceNode = TRUE; ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,pPreviousNode,this); if (IsOperationOk) IsOperationOk = pPreviousNode->AllowOp(&ObjChange); // insert our new object if (IsOperationOk) { // Insert the new node into the tree IsOperationOk = DoInsertNewNode(pNewNode, pPreviousNode, NEXT, TRUE); } // Invalidate the region covered by the old node if (IsOperationOk) IsOperationOk = DoInvalidateNodeRegion(pPreviousNode, TRUE); // Make sure everything has worked if (IsOperationOk) { // Remove the old node IsOperationOk = DoHideNode(pPreviousNode, TRUE); } ObjChange.Define(OBJCHANGE_FINISHED,cFlags,pPreviousNode,this); IsOperationOk = UpdateChangedNodes(&ObjChange); // If something went wrong then fail if (!IsOperationOk) FailAndExecute(); // End the operation properly End(); // return a value back to the caller return IsOperationOk; }
/******************************************************************************************** > virtual void OpRemoveClipView::Do(OpDescriptor* pOpDesc, OpParam* pOpParam) Author: Karim_MacDonald (Xara Group Ltd) <*****@*****.**> Created: 01 February 2000 Inputs: Outputs: Returns: Purpose: Errors: See also: ********************************************************************************************/ void OpRemoveClipView::Do(OpDescriptor* pOpDesc) { // try to record the selection state. if (DoStartSelOp(FALSE, FALSE)) { // obtain the current selection. Range Sel(*(GetApplication()->FindSelection())); RangeControl rc = Sel.GetRangeControlFlags(); rc.PromoteToParent = TRUE; Sel.Range::SetRangeControl(rc); // check that the selection is one lone NodeClipViewController. BOOL ok = FALSE; Node* pFirstNode = Sel.FindFirst(); if (pFirstNode != NULL && pFirstNode->IsANodeClipViewController()) if (Sel.FindNext(pFirstNode) == NULL) ok = TRUE; // remove tool blobs and localise any common attributes. Tool* pTool = NULL; Spread* pSpread = NULL; if (ok) { // render blobs off for tools which don't automatically redraw their blobs. pTool = Tool::GetCurrent(); pSpread = Document::GetSelectedSpread(); if (pSpread != NULL && pTool != NULL && !pTool->AreToolBlobsRenderedOnSelection()) pTool->RenderToolBlobs(pSpread, NULL); // invalidate the region of screen covering the selection. DoInvalidateNodesRegions(*(GetApplication()->FindSelection()), TRUE, FALSE, FALSE); // localise any common attributes. ok = DoLocaliseCommonAttributes((NodeGroup*)pFirstNode); } // deselect and hide the NCVC. NodeHidden* pHiddenNode = NULL; if (ok) { // deselect the NCVC, but don't ask for its blobs to be redrawn. ((NodeRenderable*)pFirstNode)->DeSelect(FALSE); ERROR3IF(pFirstNode->IsSelected(), "Deselect failed to deselect current node"); // hide the NodeClipViewController. ok = DoHideNode(pFirstNode, FALSE, &pHiddenNode, FALSE); ERROR3IF(!ok, "Unable to hide NodeClipViewController!"); } // hide the NCVC's NodeClipView node. if (ok) { NodeHidden* pDummy; NodeClipView* pClipView = ((NodeClipViewController*)pFirstNode)->GetClipView(); ok = DoHideNode(pClipView, FALSE, &pDummy, FALSE); ERROR3IF(!ok, "Unable to hide NodeClipView!"); } // show and select the NCVC's children. // a straight loop-over should do, as it should skip the now-hidden NodeClipView. if (ok) { // get the first child node (the NCVC's keyhole node). Node* pChildNode = pFirstNode->FindFirstChild(); if (pChildNode == NULL) TRACEUSER( "Karim", _T("OpRemoveClipView::Do(); Found an empty NodeClipViewController!\n")); // move and select the child nodes in turn. Node* pAnchorNode = pHiddenNode; Node* pNextChildNode = NULL; while (pChildNode != NULL) { // get the next child-node. pNextChildNode = pChildNode->FindNext(); // if the node is not a NodeHidden then move the node to its new location in // the tree - there is no need to render the node. if (!pChildNode->IsAnAttribute() && !pChildNode->IsNodeHidden()) { // move pChildNode to be the next-sibling of the anchor node. ok = DoMoveNode(pChildNode, pAnchorNode, NEXT); if (!ok) break; pAnchorNode = pChildNode; } // select the child node and invalidate its bounding rect, // but don't bother redrawing its blobs yet. if (pChildNode->IsAnObject()) { ((NodeRenderableInk*)pChildNode)->Select(FALSE); ((NodeRenderableInk*)pChildNode)->InvalidateBoundingRect(); ok = this->DoInvalidateNodeRegion(((NodeRenderableInk*)pChildNode), TRUE); if (!ok) break; } pChildNode = pNextChildNode; } } // render blobs back on for tools which don't automatically redraw their blobs. if (ok) { if (pSpread != NULL && pTool != NULL && !pTool->AreToolBlobsRenderedOnSelection()) pTool->RenderToolBlobs(pSpread, NULL); } // fail gracefully if things went pear-shaped. else FailAndExecute(); } End(); }
void OpBreakAtPoints::Do(OpDescriptor*) { // Obtain the current selections SelRange* Selected = GetApplication()->FindSelection(); NodePath* pSplitNode; // Now, because we're going to be doing mad things to the selection, we have to make a list // of all the selected nodes, so that adding nodes into the tree won't confuse us List* NodeList = Selected->MakeListOfNodes(); NodeListItem* CurItem = (NodeListItem*)(NodeList->GetHead()); if (!CurItem) goto FailAndDeleteList; if (!DoStartSelOp(TRUE,TRUE)) goto FailAndDeleteList; while (CurItem) { // get a pointer to the NodePath NodePath* pThisNode = (NodePath*)(CurItem->pNode); // Only interested in NodePaths that have a sub selection, and that will allow the op to happen if ((IS_A(pThisNode,NodePath) || IS_A(pThisNode,NodeBlendPath)) && pThisNode->InkPath.IsSubSelection()) { // Find out how many nodes this op will reproduce INT32 NumSplinters = pThisNode->InkPath.NumSplinters(); BOOL DoThisNode = FALSE; if (NumSplinters > 0) { // We need to ask the effected nodes if they (and their parents) can handle this node being replaced ObjChangeFlags cFlags; if (NumSplinters > 1) cFlags.MultiReplaceNode = TRUE; // Node will be replaced with more than one node. else cFlags.ReplaceNode = TRUE; // Node will be replaced with one node only. ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this); DoThisNode = pThisNode->AllowOp(&ObjChange); } if (DoThisNode) { BOOL ok; Node* pnode; // Copy the nodepath and all its children, without placing the copy in the tree CALL_WITH_FAIL(pThisNode->NodeCopy(&pnode), this, ok); if (!ok) goto DeleteList; pSplitNode = (NodePath*)pnode; // remove the fill from this path as we're about to open it pSplitNode->InkPath.IsFilled = FALSE; // Now stick the new path into the tree CALL_WITH_FAIL ( DoInsertNewNode(pSplitNode, pThisNode, NEXT, TRUE, FALSE), this,ok ); if (!ok) goto DeleteListAndPath; // Now breakup this copy of the path where necessary Path* pChildPath; INT32 split; do { // Create a new path, ready for split ALLOC_WITH_FAIL(pChildPath, new Path, this); if (!pChildPath) goto DeleteList; // Now split the path, possibly into two pieces. split = pSplitNode->InkPath.BreakInTwo(pChildPath); if (split==-1) { InformError(_R(IDS_OUT_OF_MEMORY), _R(IDS_OK)); delete pChildPath; goto FailAndDeleteList; } /* Karim 05/12/2000 No longer required - see code addition at the bottom of this loop. if (split==1) { delete pChildPath; continue; } */ if (split>1) { // update the split paths bounding rectangle pSplitNode->InvalidateBoundingRect(); // Create a new nodepath. NodePath* pChildNode; ALLOC_WITH_FAIL(pChildNode, new NodePath(), this); if (!pChildNode) { delete pChildPath; goto DeleteList; } // make room for the new path in the node path. CALL_WITH_FAIL ( pChildNode->SetUpPath(pChildPath->GetNumCoords(),12), this,ok ); if (!ok) { delete pChildNode; delete pChildPath; goto DeleteList; } // now copy the path data in there. pChildNode->InkPath.CopyPathDataFrom(pChildPath); delete pChildPath; // Clear the selection flag from the first element in both the split // and child paths. All others apart from the last will be unselected // by definition. Also select the last element in the child (pSplitNode->InkPath.GetFlagArray())[0].IsSelected = FALSE; (pChildNode->InkPath.GetFlagArray())[0].IsSelected = FALSE; (pChildNode->InkPath.GetFlagArray())[(pChildNode->InkPath.GetNumCoords()-1)].IsSelected = TRUE; pChildNode->InkPath.IsFilled = FALSE; // now, copy all attributes from the parent split to the child split Node* pAttr = pSplitNode->FindFirstChild(); while (pAttr != NULL) { if (pAttr->IsKindOf(CC_RUNTIME_CLASS(NodeAttribute))) { Node* pAttrCopy; CALL_WITH_FAIL(pAttr->NodeCopy(&pAttrCopy), this,ok); if (!ok) { pChildNode->CascadeDelete(); delete pChildNode; goto DeleteList; } pAttrCopy->AttachNode(pChildNode, FIRSTCHILD); } pAttr = pAttr->FindNext(); } for (INT32 loop = 0; loop < pChildNode->InkPath.GetNumCoords(); loop ++) { pChildNode->InkPath.GetVerbArray()[loop] = pChildNode->InkPath.GetVerbArray()[loop] & ~PT_CLOSEFIGURE; } // Now stick the new path into the tree CALL_WITH_FAIL ( DoInsertNewNode(pChildNode, pSplitNode, NEXT, TRUE, FALSE), this,ok ); if (!ok) { pChildNode->CascadeDelete(); delete pChildNode; goto DeleteList; } pSplitNode = pChildNode; } // Karim 05/12/2000 // Fix for memory leak. else { delete pChildPath; } } while (split); // Clear out any remaining closefigures on the last bit of the path for (INT32 loop = 0; loop < pSplitNode->InkPath.GetNumCoords(); loop ++) { pSplitNode->InkPath.GetVerbArray()[loop] = pSplitNode->InkPath.GetVerbArray()[loop] & ~PT_CLOSEFIGURE; } // Now we've broken up this path, let's hide it CALL_WITH_FAIL(DoHideNode(pThisNode,TRUE), this, ok) if (!ok) goto DeleteList; } } CurItem = (NodeListItem*)(NodeList->GetNext(CurItem)); }