opclip.cpp

Go to the documentation of this file.
00001 // $Id: opclip.cpp 1144 2006-05-20 18:43:14Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 //
00099 // Implementation of ClipView operations.
00100 //
00101 
00102 #include "camtypes.h"       // pre-compiled header
00103 #include "opclip.h"         // our header file
00104 #include "ophist.h"
00105 //#include "clipres.h"      // our resources
00106 //#include "phil.h"         // for _R(IDS_GREY_WHEN_SELECT_INSIDE)
00107 
00108 #include "ndclpcnt.h"       // so we can play around with NodeClipViewContainer
00109 #include "nodeclip.h"       // so we can play around with NodeClipView
00110 #include "nodepath.h"
00111 
00112 // dynamic class creation stuff.
00113 CC_IMPLEMENT_DYNCREATE(OpApplyClipView, SelOperation);
00114 CC_IMPLEMENT_DYNCREATE(OpRemoveClipView, SelOperation);
00115 
00116 DECLARE_SOURCE("$Revision: 1144 $");
00117 
00118 #define new CAM_DEBUG_NEW
00119 
00120 
00121 /********************************************************************************************
00122 
00123 >   OpApplyClipView::OpApplyClipView()
00124 
00125     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00126     Created:    01 February 2000
00127     Purpose:    Constructor.
00128     Errors:     
00129     See also:   
00130 
00131 ********************************************************************************************/
00132 OpApplyClipView::OpApplyClipView()
00133 {
00134     // empty.
00135 }
00136 
00137 
00138 
00139 /********************************************************************************************
00140 
00141 >   OpApplyClipView::~OpApplyClipView()
00142 
00143     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00144     Created:    01 February 2000
00145     Purpose:    Destructor.
00146     Errors:     
00147     See also:   
00148 
00149 ********************************************************************************************/
00150 OpApplyClipView::~OpApplyClipView()
00151 {
00152     // empty.
00153 }
00154 
00155 
00156 
00157 /********************************************************************************************
00158 
00159 >   static BOOL OpApplyClipView::Init()
00160 
00161     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00162     Created:    01 February 2000
00163     Inputs:     
00164     Outputs:    
00165     Returns:    
00166     Purpose:    
00167     Errors:     
00168     See also:   
00169 
00170 ********************************************************************************************/
00171 BOOL OpApplyClipView::Init()
00172 {
00173     return RegisterOpDescriptor(0,                              // Tool ID
00174                                 _R(IDS_APPLY_CLIPVIEW),             // String resource ID
00175                                 CC_RUNTIME_CLASS(OpApplyClipView),  // Runtime class
00176                                 OPTOKEN_APPLY_CLIPVIEW,         // Token string
00177                                 OpApplyClipView::GetState,      // GetState function
00178                                 0,                              // Help ID
00179                                 _R(IDBBL_APPLY_CLIPVIEW),           // Bubble ID
00180                                 0,                              // Resource ID
00181                                 0,                              // Control ID
00182                                 SYSTEMBAR_ILLEGAL,              // Bar ID
00183                                 TRUE,                           // Receive system messages
00184                                 FALSE,                          // Smart duplicate operation
00185                                 FALSE,                          // Clean operation
00186                                 0,                              // No vertical counterpart
00187                                 GREY_WHEN_NO_CURRENT_DOC |
00188                                 DONT_GREY_WHEN_SELECT_INSIDE);  // automatic state checking.
00189 }
00190 
00191 
00192 
00193 /********************************************************************************************
00194 
00195 >   static OpState OpApplyClipView::GetState(String_256* pstrDescription, OpDescriptor* pOpDesc)
00196 
00197     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00198     Created:    01 February 2000
00199     Inputs:     
00200     Outputs:    
00201     Returns:    
00202     Purpose:    
00203     Errors:     
00204     See also:   
00205 
00206 ********************************************************************************************/
00207 OpState OpApplyClipView::GetState(String_256* pstrDescription, OpDescriptor* pOpDesc)
00208 {
00209     // default is an unticked, *GREYED*, on-menu state.
00210     OpState OpSt;
00211     OpSt.Greyed = TRUE;
00212     *pstrDescription = String_256(_R(IDS_CLIPVIEW_NEEDS_MULTIPLE_NODES));
00213 
00214     // obtain the app's current selection.
00215     // we want to treat bevels/contours etc. as atomic objects.
00216     Range Sel(*(GetApplication()->FindSelection()));
00217     RangeControl rc = Sel.GetRangeControlFlags();
00218     rc.PromoteToParent = TRUE;
00219     Sel.Range::SetRangeControl(rc);
00220 
00221     // is there actually anything in the selection?
00222     Node* pNode = Sel.FindFirst();
00223     if (pNode != NULL)
00224     {
00225         // yes - then is it only one node?
00226         if (Sel.FindNext(pNode) == NULL)
00227         {
00228             // yes - then if that node is a NodeClipViewController, remove ourself from the menu.
00229             if (pNode->IsANodeClipViewController())
00230             {
00231                 OpSt.RemoveFromMenu = TRUE;
00232                 pstrDescription->Empty();
00233             }
00234         }
00235 
00236         // two or more nodes - that's ok, but only if there is currently no select-inside.
00237         else if (Sel.ContainsSelectInside())
00238         {
00239             *pstrDescription = String_256(_R(IDS_GREY_WHEN_SELECT_INSIDE));
00240         }
00241         else
00242         {
00243             OpSt.Greyed = FALSE;
00244             pstrDescription->Empty();
00245         }
00246     }
00247 
00248     return OpSt;
00249 }
00250 
00251 
00252 
00253 /********************************************************************************************
00254 
00255 >   virtual void OpApplyClipView::GetOpName(String_256* pstrOpName)
00256 
00257     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00258     Created:    01 February 2000
00259     Inputs:     
00260     Outputs:    
00261     Returns:    
00262     Purpose:    
00263     Errors:     
00264     See also:   
00265 
00266 ********************************************************************************************/
00267 void OpApplyClipView::GetOpName(String_256* pstrOpName)
00268 {
00269     *pstrOpName = String_256("ClipView Object(s)");
00270 }
00271 
00272 
00273 
00274 /********************************************************************************************
00275 
00276 >   virtual void OpApplyClipView::Do(OpDescriptor* pOpDesc, OpParam* pOpParam)
00277 
00278     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00279     Created:    01 February 2000
00280     Inputs:     
00281     Outputs:    
00282     Returns:    
00283     Purpose:    
00284     Errors:     
00285     See also:   
00286 
00287 ********************************************************************************************/
00288 void OpApplyClipView::Do(OpDescriptor* pOpDesc)
00289 {
00290     // obtain the current selection.
00291     Range Sel(*(GetApplication()->FindSelection()));
00292     RangeControl rc = Sel.GetRangeControlFlags();
00293     rc.PromoteToParent = TRUE;
00294     Sel.Range::SetRangeControl(rc);
00295 
00296     // check that at least two nodes are selected.
00297     Node* pNode = NULL;
00298     Node* pFirstNode = Sel.FindFirst();
00299     if (pFirstNode != NULL)
00300         pNode = Sel.FindNext(pFirstNode);
00301         
00302     if (pFirstNode == NULL || pNode == NULL)
00303     {
00304         ERROR3("OpApplyClipView invoked with less than two selected nodes. This should never occur.");
00305         End();
00306         return;
00307     }
00308 
00309     // render blobs off for tools which don't automatically redraw their blobs.
00310     Tool* pTool = Tool::GetCurrent();
00311     Spread* pSpread = Document::GetSelectedSpread();
00312     if (pSpread != NULL && pTool != NULL && !pTool->AreToolBlobsRenderedOnSelection())
00313         pTool->RenderToolBlobs(pSpread, NULL);
00314 
00315     // record the current selection state and if required, render off any selection blobs.
00316     if (!DoStartSelOp(FALSE, FALSE))
00317     {
00318         End();
00319         return;
00320     }
00321 
00322     // invalidate the region bounding the selection.
00323     // the commented code doesn't do the job properly (doesn't tackle undo)
00324     // though it should - I get the feeling I'm not using it correctly.
00325     // so we'll just have to invalidate the selection node by node.
00326 //  if (!DoInvalidateNodesRegions(Sel, TRUE, FALSE, FALSE))
00327 //  {
00328 //      End();
00329 //      return;
00330 //  }
00331     Node* pSelNode = Sel.FindFirst();
00332     while (pSelNode != NULL)
00333     {
00334         if (pSelNode->IsAnObject())
00335         {
00336             if (!DoInvalidateNodeRegion((NodeRenderableInk*)pSelNode, TRUE))
00337             {
00338                 End();
00339                 return;
00340             }
00341         }
00342         pSelNode = Sel.FindNext(pSelNode);
00343     }
00344 
00345     // we need to insert the controller node at the position of the highest
00346     // selected node in the z-order, ie last in the selection, so find it.
00347     Node* pLastNode = NULL;
00348     while (pNode != NULL)
00349     {
00350         pLastNode = pNode;
00351         pNode = Sel.FindNext(pLastNode);
00352     }   // loop terminates with pNode == NULL, pLastNode == last-node-in-sel.
00353 
00354     // create a new NodeClipViewController, which we will shortly insert into the tree;
00355     // note that ALLOC_WITH_FAIL automatically calls FailAndExecute() if things go wrong.
00356     NodeClipViewController* pClipViewController = NULL;
00357     ALLOC_WITH_FAIL(pClipViewController, new NodeClipViewController, this);
00358     BOOL ok = (pClipViewController != NULL);
00359 
00360     // put an action to hide the NodeClipViewController onto the undo action-list,
00361     // so that if the user presses undo then it will be hidden.
00362     if (ok)
00363     {
00364         HideNodeAction* pUndoHideNodeAction = NULL;
00365         ActionCode ac = HideNodeAction::Init(this,
00366                                             &UndoActions,
00367                                             pClipViewController,
00368                                             FALSE,      // don't include subtree size
00369                                             (Action**)&pUndoHideNodeAction,
00370                                             FALSE);     // don't tell subtree when undone
00371         if (ac == AC_FAIL)
00372         {
00373             delete pClipViewController;
00374             End();
00375             return;
00376         }
00377         else
00378         {
00379             // right! we've got our node, we've got our action - lets stick it in the tree
00380             // (at a position just next to the last node which will go in the group).
00381             pClipViewController->AttachNode(pLastNode, NEXT);
00382         }
00383     }
00384 
00385     // move each item from the selection into our ClipView group,
00386     // remembering to deselect them as we go.
00387     // TODO:
00388     //  sneaky suspicion I should be putting this in a Do fn in UndoableOperation...
00389     if (ok)
00390     {
00391         pNode = Sel.FindNext(pFirstNode);               // the node we're moving now.
00392         ok = DoMoveNode(pFirstNode, pClipViewController, FIRSTCHILD);
00393         if (ok)
00394             ((NodeRenderable*)pFirstNode)->DeSelect(FALSE);
00395     }
00396 
00397     Node* pNextNode     = NULL;                         // the next node to move.
00398     Node* pAnchorNode   = pFirstNode;                   // the node we've just moved.
00399     while (ok && pNode != NULL)
00400     {
00401         // get the next node to move.
00402         pNextNode = Sel.FindNext(pNode);
00403 
00404         // now move the current node next to the anchor and deselect it.
00405         ok = DoMoveNode(pNode, pAnchorNode, NEXT);
00406         if (ok)
00407             ((NodeRenderable*)pNode)->DeSelect(FALSE);
00408 
00409         // get the new anchor node and the next node to move.
00410         pAnchorNode = pNode;
00411         pNode = pNextNode;
00412     }
00413 
00414     // try and locate a suitable candidate for a keyhole node.
00415     Node* pKeyhole = NULL;
00416     if (ok)
00417     {
00418         // now get the keyhole node, which is the first object-node child of the NCVC.
00419         pKeyhole = pClipViewController->FindFirstChild();
00420         while (pKeyhole != NULL && !pKeyhole->IsAnObject())
00421         {
00422             pKeyhole = pKeyhole->FindNext();
00423         }
00424 
00425         // doh! can't find _one_ NodeRenderableInk child! I don't know...
00426         if (pKeyhole == NULL)
00427         {
00428             ok = FALSE;
00429             ERROR2RAW("ClipViewController has no object children");
00430         }
00431     }
00432 
00433     // now attach a new NodeClipView, as the immediate NEXT-sibling of the keyhole node.
00434     NodeClipView* pClipView = NULL;
00435     if (ok)
00436     {
00437         ALLOC_WITH_FAIL(pClipView, new NodeClipView(pKeyhole, NEXT), this);
00438         ok = (pClipView != NULL);
00439     }
00440 
00441     // wow - succeeded! now all we need to do is some house-keeping.
00442     if (ok)
00443     {
00444         // tell the new NodeClipViewController that its current keyhole path is now invalid.
00445         pClipViewController->MarkKeyholeInvalid();
00446 
00447         // invalidate ours and our parent's bounding rects. our bounding rect is almost
00448         // certainly already invalid, as we haven't done anything to make it valid yet.
00449         // this is why we invalidate *both* rects - just to cover all cases.
00450         pClipViewController->InvalidateBoundingRect();
00451         Node* pParent = pClipViewController->FindParent();
00452         if (pParent != NULL && pParent->IsBounded())
00453             ((NodeRenderableBounded*)pParent)->InvalidateBoundingRect();
00454 
00455         // select the new NodeClipViewController, but don't draw any blobs yet.
00456         pClipViewController->Select(FALSE);
00457 
00458         // invalidate the region bounding the selection.
00459         if (!DoInvalidateNodesRegions(*(GetApplication()->FindSelection()), TRUE, FALSE, FALSE))
00460         {
00461             End();
00462             return;
00463         }
00464 
00465         // factor out any common attributes.
00466         if (!DoFactorOutCommonChildAttributes(pClipViewController))
00467         {
00468             End();
00469             return;
00470         }
00471         
00472         // render blobs back on if the current tool doesn't automatically redraw its blobs.
00473         if (pSpread != NULL && pTool != NULL && !pTool->AreToolBlobsRenderedOnSelection())
00474             pTool->RenderToolBlobs(pSpread, NULL);
00475     }
00476     else
00477     {
00478         FailAndExecute();
00479     }
00480 
00481     // end the operation.
00482     End();
00483 }
00484 
00485 
00486 
00487 //-------------------------------------------------------------------------------------------
00488 //-------------------------------------------------------------------------------------------
00489 //-------------------------------------------------------------------------------------------
00490 //-------------------------------------------------------------------------------------------
00491 
00492 
00493 
00494 /********************************************************************************************
00495 
00496 >   OpRemoveClipView::OpRemoveClipView()
00497 
00498     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00499     Created:    01 February 2000
00500     Purpose:    Constructor.
00501     Errors:     
00502     See also:   
00503 
00504 ********************************************************************************************/
00505 OpRemoveClipView::OpRemoveClipView()
00506 {
00507     // empty.
00508 }
00509 
00510 
00511 
00512 /********************************************************************************************
00513 
00514 >   OpRemoveClipView::~OpRemoveClipView()
00515 
00516     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00517     Created:    01 February 2000
00518     Purpose:    Destructor.
00519     Errors:     
00520     See also:   
00521 
00522 ********************************************************************************************/
00523 OpRemoveClipView::~OpRemoveClipView()
00524 {
00525     // empty.
00526 }
00527 
00528 
00529 
00530 /********************************************************************************************
00531 
00532 >   static BOOL OpRemoveClipView::Init()
00533 
00534     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00535     Created:    01 February 2000
00536     Inputs:     
00537     Outputs:    
00538     Returns:    
00539     Purpose:    
00540     Errors:     
00541     See also:   
00542 
00543 ********************************************************************************************/
00544 BOOL OpRemoveClipView::Init()
00545 {
00546     return RegisterOpDescriptor(0,                              // Tool ID
00547                                 _R(IDS_REMOVE_CLIPVIEW),                // String resource ID
00548                                 CC_RUNTIME_CLASS(OpRemoveClipView), // Runtime class
00549                                 OPTOKEN_REMOVE_CLIPVIEW,            // Token string
00550                                 OpRemoveClipView::GetState,     // GetState function
00551                                 0,                              // Help ID
00552                                 _R(IDBBL_REMOVE_CLIPVIEW),          // Bubble ID
00553                                 0,                              // Resource ID
00554                                 0,                              // Control ID
00555                                 SYSTEMBAR_ILLEGAL,              // Bar ID
00556                                 TRUE,                           // Receive system messages
00557                                 FALSE,                          // Smart duplicate operation
00558                                 FALSE,                          // Clean operation
00559                                 0,                              // We can have many instances
00560                                                                 //          of this operation.
00561                                 DONT_GREY_WHEN_SELECT_INSIDE);  // We don't ever want to be
00562                                                                 // automatically greyed out.
00563 }
00564 
00565 
00566 
00567 /********************************************************************************************
00568 
00569 >   static OpState OpRemoveClipView::GetState(String_256* pstrDescription, OpDescriptor* pOpDesc)
00570 
00571     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00572     Created:    01 February 2000
00573     Inputs:     pstrDescription
00574                 pOpDesc
00575     Outputs:    
00576     Returns:    
00577     Purpose:    
00578     Errors:     
00579     See also:   
00580 
00581 ********************************************************************************************/
00582 OpState OpRemoveClipView::GetState(String_256* pstrDescription, OpDescriptor* pOpDesc)
00583 {
00584     // default is an unticked, ungreyed, *NOT* on-menu state.
00585     OpState OpSt;
00586     OpSt.RemoveFromMenu = TRUE;
00587 
00588     // obtain the app's current selection.
00589     // we want to treat bevels/contours etc. as atomic objects.
00590     Range Sel(*(GetApplication()->FindSelection()));
00591     RangeControl rc = Sel.GetRangeControlFlags();
00592     rc.PromoteToParent = TRUE;
00593     Sel.Range::SetRangeControl(rc);
00594 
00595     // we only show ourself if the selection consists of one lone NodeClipViewController.
00596     Node* pNode = Sel.FindFirst();
00597     if (pNode != NULL && pNode->IsANodeClipViewController())
00598     {
00599         if (Sel.FindNext(pNode) == NULL)
00600         {
00601             OpSt.RemoveFromMenu = FALSE;
00602 
00603             // if it's selected inside, we gray ourself and give a reason.
00604             if (Sel.ContainsSelectInside())
00605             {
00606                 OpSt.Greyed = TRUE;
00607                 *pstrDescription = String_256(_R(IDS_GREY_WHEN_SELECT_INSIDE));
00608             }
00609         }
00610     }
00611 
00612     return OpSt;
00613 }
00614 
00615 
00616 
00617 /********************************************************************************************
00618 
00619 >   virtual void OpRemoveClipView::GetOpName(String_256* pstrOpName)
00620 
00621     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00622     Created:    01 February 2000
00623     Inputs:     
00624     Outputs:    
00625     Returns:    
00626     Purpose:    
00627     Errors:     
00628     See also:   
00629 
00630 ********************************************************************************************/
00631 void OpRemoveClipView::GetOpName(String_256* pstrOpName)
00632 {
00633     *pstrOpName = String_256("Remove ClipView");
00634 }
00635 
00636 
00637 
00638 /********************************************************************************************
00639 
00640 >   virtual void OpRemoveClipView::Do(OpDescriptor* pOpDesc, OpParam* pOpParam)
00641 
00642     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00643     Created:    01 February 2000
00644     Inputs:     
00645     Outputs:    
00646     Returns:    
00647     Purpose:    
00648     Errors:     
00649     See also:   
00650 
00651 ********************************************************************************************/
00652 void OpRemoveClipView::Do(OpDescriptor* pOpDesc)
00653 {
00654     // try to record the selection state.
00655     if (DoStartSelOp(FALSE, FALSE))
00656     {
00657         // obtain the current selection.
00658         Range Sel(*(GetApplication()->FindSelection()));
00659         RangeControl rc = Sel.GetRangeControlFlags();
00660         rc.PromoteToParent = TRUE;
00661         Sel.Range::SetRangeControl(rc);
00662 
00663         // check that the selection is one lone NodeClipViewController.
00664         BOOL ok = FALSE;
00665         Node* pFirstNode = Sel.FindFirst();
00666         if (pFirstNode != NULL && pFirstNode->IsANodeClipViewController())
00667             if (Sel.FindNext(pFirstNode) == NULL)
00668                 ok = TRUE;
00669 
00670         // remove tool blobs and localise any common attributes.
00671         Tool* pTool = NULL;
00672         Spread* pSpread = NULL;
00673         if (ok)
00674         {
00675             // render blobs off for tools which don't automatically redraw their blobs.
00676             pTool = Tool::GetCurrent();
00677             pSpread = Document::GetSelectedSpread();
00678             if (pSpread != NULL && pTool != NULL && !pTool->AreToolBlobsRenderedOnSelection())
00679                 pTool->RenderToolBlobs(pSpread, NULL);
00680 
00681             // invalidate the region of screen covering the selection.
00682             DoInvalidateNodesRegions(*(GetApplication()->FindSelection()), TRUE, FALSE, FALSE);
00683 
00684             // localise any common attributes.
00685             ok = DoLocaliseCommonAttributes((NodeGroup*)pFirstNode);
00686         }
00687 
00688         // deselect and hide the NCVC.
00689         NodeHidden* pHiddenNode = NULL;
00690         if (ok)
00691         {
00692             // deselect the NCVC, but don't ask for its blobs to be redrawn.
00693             ((NodeRenderable*)pFirstNode)->DeSelect(FALSE);
00694             ERROR3IF(pFirstNode->IsSelected(), "Deselect failed to deselect current node");
00695 
00696             // hide the NodeClipViewController.
00697             ok = DoHideNode(pFirstNode, FALSE, &pHiddenNode, FALSE);
00698             ERROR3IF(!ok, "Unable to hide NodeClipViewController!");
00699         }
00700 
00701         // hide the NCVC's NodeClipView node.
00702         if (ok)
00703         {
00704             NodeHidden* pDummy;
00705             NodeClipView* pClipView = ((NodeClipViewController*)pFirstNode)->GetClipView();
00706             ok = DoHideNode(pClipView, FALSE, &pDummy, FALSE);
00707             ERROR3IF(!ok, "Unable to hide NodeClipView!");
00708         }
00709 
00710         // show and select the NCVC's children.
00711         // a straight loop-over should do, as it should skip the now-hidden NodeClipView.
00712         if (ok)
00713         {
00714             // get the first child node (the NCVC's keyhole node).
00715             Node* pChildNode = pFirstNode->FindFirstChild();
00716             if (pChildNode == NULL)
00717                 TRACEUSER( "Karim", _T("OpRemoveClipView::Do(); Found an empty NodeClipViewController!\n"));
00718 
00719             // move and select the child nodes in turn.
00720             Node* pAnchorNode = pHiddenNode;
00721             Node* pNextChildNode = NULL;
00722             while (pChildNode != NULL)
00723             {
00724                 // get the next child-node.
00725                 pNextChildNode = pChildNode->FindNext();
00726 
00727                 // if the node is not a NodeHidden then move the node to its new location in 
00728                 // the tree - there is no need to render the node.
00729                 if (!pChildNode->IsAnAttribute() && !pChildNode->IsNodeHidden())
00730                 {
00731                     // move pChildNode to be the next-sibling of the anchor node.
00732                     ok = DoMoveNode(pChildNode, pAnchorNode, NEXT);
00733                     if (!ok)
00734                         break;
00735 
00736                     pAnchorNode = pChildNode;
00737                 }
00738 
00739                 // select the child node and invalidate its bounding rect,
00740                 // but don't bother redrawing its blobs yet.
00741                 if (pChildNode->IsAnObject())
00742                 {
00743                     ((NodeRenderableInk*)pChildNode)->Select(FALSE);
00744                     ((NodeRenderableInk*)pChildNode)->InvalidateBoundingRect();
00745                     ok = this->DoInvalidateNodeRegion(((NodeRenderableInk*)pChildNode), TRUE);
00746                     if (!ok)
00747                         break;
00748                 }
00749 
00750                 pChildNode = pNextChildNode;
00751             }
00752         }
00753 
00754         // render blobs back on for tools which don't automatically redraw their blobs.
00755         if (ok)
00756         {
00757             if (pSpread != NULL && pTool != NULL && !pTool->AreToolBlobsRenderedOnSelection())
00758                 pTool->RenderToolBlobs(pSpread, NULL);
00759         }
00760 
00761         // fail gracefully if things went pear-shaped.
00762         else
00763             FailAndExecute();
00764     }
00765 
00766     End();
00767 }           
00768 
00769 
00770 
00771 //-------------------------------------------------------------------------------------------
00772 //-------------------------------------------------------------------------------------------
00773 //-------------------------------------------------------------------------------------------
00774 //-------------------------------------------------------------------------------------------
00775 
00776 
00777 
00778 

Generated on Sat Nov 10 03:47:43 2007 for Camelot by  doxygen 1.4.4