00001 // $Id: layermgr.cpp 1282 2006-06-09 09:46:49Z alex $ 00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00003 ================================XARAHEADERSTART=========================== 00004 00005 Xara LX, a vector drawing and manipulation program. 00006 Copyright (C) 1993-2006 Xara Group Ltd. 00007 Copyright on certain contributions may be held in joint with their 00008 respective authors. See AUTHORS file for details. 00009 00010 LICENSE TO USE AND MODIFY SOFTWARE 00011 ---------------------------------- 00012 00013 This file is part of Xara LX. 00014 00015 Xara LX is free software; you can redistribute it and/or modify it 00016 under the terms of the GNU General Public License version 2 as published 00017 by the Free Software Foundation. 00018 00019 Xara LX and its component source files are distributed in the hope 00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00022 See the GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with Xara LX (see the file GPL in the root directory of the 00026 distribution); if not, write to the Free Software Foundation, Inc., 51 00027 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00028 00029 00030 ADDITIONAL RIGHTS 00031 ----------------- 00032 00033 Conditional upon your continuing compliance with the GNU General Public 00034 License described above, Xara Group Ltd grants to you certain additional 00035 rights. 00036 00037 The additional rights are to use, modify, and distribute the software 00038 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00039 library and any other such library that any version of Xara LX relased 00040 by Xara Group Ltd requires in order to compile and execute, including 00041 the static linking of that library to XaraLX. In the case of the 00042 "CDraw" library, you may satisfy obligation under the GNU General Public 00043 License to provide source code by providing a binary copy of the library 00044 concerned and a copy of the license accompanying it. 00045 00046 Nothing in this section restricts any of the rights you have under 00047 the GNU General Public License. 00048 00049 00050 SCOPE OF LICENSE 00051 ---------------- 00052 00053 This license applies to this program (XaraLX) and its constituent source 00054 files only, and does not necessarily apply to other Xara products which may 00055 in part share the same code base, and are subject to their own licensing 00056 terms. 00057 00058 This license does not apply to files in the wxXtra directory, which 00059 are built into a separate library, and are subject to the wxWindows 00060 license contained within that directory in the file "WXXTRA-LICENSE". 00061 00062 This license does not apply to the binary libraries (if any) within 00063 the "libs" directory, which are subject to a separate license contained 00064 within that directory in the file "LIBS-LICENSE". 00065 00066 00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00068 ---------------------------------------------- 00069 00070 Subject to the terms of the GNU Public License (see above), you are 00071 free to do whatever you like with your modifications. However, you may 00072 (at your option) wish contribute them to Xara's source tree. You can 00073 find details of how to do this at: 00074 http://www.xaraxtreme.org/developers/ 00075 00076 Prior to contributing your modifications, you will need to complete our 00077 contributor agreement. This can be found at: 00078 http://www.xaraxtreme.org/developers/contribute/ 00079 00080 Please note that Xara will not accept modifications which modify any of 00081 the text between the start and end of this header (marked 00082 XARAHEADERSTART and XARAHEADEREND). 00083 00084 00085 MARKS 00086 ----- 00087 00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00089 designs are registered or unregistered trademarks, design-marks, and/or 00090 service marks of Xara Group Ltd. All rights in these marks are reserved. 00091 00092 00093 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00094 http://www.xara.com/ 00095 00096 =================================XARAHEADEREND============================ 00097 */ 00098 00099 /* Implementation of the following classes 00100 LyrDetails 00101 LayerManager 00102 OpLayerChange 00103 */ 00104 00105 // Include files 00106 #include "camtypes.h" 00107 #include "layermgr.h" 00108 //#include "fixst256.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00109 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00110 //#include "mainfrm.h" 00111 #include "infobar.h" 00112 //#include "simon.h" 00113 //#include "mario.h" 00114 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00115 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00116 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00117 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00118 //#include "ink.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00119 #include "bubbleid.h" 00120 //#include "sliceres.h" // for the resource id move to active layer 00121 #include "objchge.h" // for the allow op flags 00122 //#include "bars.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00123 00124 //#include "will2.h" 00125 //#include "selop.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00126 00127 DECLARE_SOURCE("$Revision: 1282 $"); 00128 00129 // Declare class for memory tracking etc 00130 CC_IMPLEMENT_DYNCREATE(OpLayerChange, UndoableOperation) 00131 CC_IMPLEMENT_DYNCREATE(ChangeLyrAttribAction, Action) 00132 CC_IMPLEMENT_MEMDUMP(LyrDetails, ListItem) 00133 CC_IMPLEMENT_DYNCREATE(OpMoveToLayer, SelOperation) 00134 #define new CAM_DEBUG_NEW 00135 00136 /******************************************************************************************** 00137 00138 > LyrDetails::LyrDetails() 00139 00140 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00141 Created: 14/1/94 00142 Inputs: - 00143 Outputs: - 00144 Returns: - 00145 Purpose: LyrDetails constructor 00146 Errors: - 00147 SeeAlso: - 00148 00149 ********************************************************************************************/ 00150 00151 LyrDetails::LyrDetails() 00152 { 00153 } 00154 00155 /******************************************************************************************** 00156 00157 > LayerManager::LayerManager() 00158 00159 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00160 Created: 10/1/94 00161 Inputs: - 00162 Outputs: - 00163 Returns: - 00164 Purpose: LayerManager Constructor, initially the LayerManager has no CurrentSpread. 00165 Errors: - 00166 SeeAlso: - 00167 00168 ********************************************************************************************/ 00169 00170 LayerManager::LayerManager() 00171 { 00172 CurrentSpread = NULL; // There is no current spread 00173 } 00174 00175 /******************************************************************************************** 00176 00177 > LayerManager::~LayerManager() 00178 00179 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00180 Created: 10/1/94 00181 Inputs: - 00182 Outputs: - 00183 Returns: - 00184 Purpose: LayerManager destructor 00185 Errors: - 00186 SeeAlso: - 00187 00188 ********************************************************************************************/ 00189 00190 LayerManager::~LayerManager() 00191 { 00192 DeleteLayerDetList(); // Delete the layer details list 00193 } 00194 00195 /******************************************************************************************** 00196 00197 > String_256 LayerManager::CreateUniqueLayerID() 00198 00199 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00200 Created: 10/1/94 00201 Inputs: - 00202 Outputs: - 00203 Returns: A LayerID which is unique for the current spread. 00204 Purpose: Used to generate a LayerID which is unique for the current spread. The name 00205 generated is normally of the form "Layer n", where n is the number of layers 00206 in the LyrDetList + 1. If "Layer n" already exists on the current spread then 00207 "Layer m" is generated where m is the smallest integer greater than n such 00208 that the id is unique. 00209 Errors: - 00210 SeeAlso: - 00211 00212 ********************************************************************************************/ 00213 00214 String_256 LayerManager::CreateUniqueLayerID() 00215 { 00216 // We can't generate a unique id if there is no current spread 00217 ENSURE(CurrentSpread != NULL, "There is no current spread"); 00218 00219 String_256 UniqueLayerID; 00220 INT32 NumLayers = 0; 00221 00222 ListItem* Lyr = LyrDetList.GetHead(); 00223 00224 // Calculate how many layers are on the current spread, we must ignore layers 00225 // which have been deleted. 00226 while (Lyr != NULL) 00227 { 00228 if (!((LyrDetails*)Lyr)->Deleted) // Don't count deleted layers 00229 { 00230 NumLayers++; 00231 } 00232 Lyr = LyrDetList.GetNext(Lyr); 00233 } 00234 00235 ENSURE(NumLayers != 0, "The current spread has no layers"); 00236 00237 00238 INT32 NewLayerNum = NumLayers+1; 00239 00240 BOOL Unique; // Flag used to indicate if the id generated is unique or not 00241 do 00242 { 00243 // Construct a first attempt at a unique layer id 'Layer n' 00244 // where n = the number of layers on the current spread + 1 00245 00246 UniqueLayerID.MakeMsg(_R(IDS_LAYERMGR_LAYERNAME),NewLayerNum); 00247 00248 // Check that UniqueLayerID is indeed unique 00249 Unique = TRUE; // Until we know better 00250 Lyr = LyrDetList.GetHead(); 00251 while (Lyr != NULL) 00252 { 00253 if (!((LyrDetails*)Lyr)->Deleted) // Ignore deleted layers 00254 { 00255 if (UniqueLayerID == ((LyrDetails*)Lyr)->Status.StringLayerID) 00256 { 00257 Unique = FALSE; 00258 00259 // UniqueLayerID is not unique so increment NewLayerNum and try again 00260 NewLayerNum++; 00261 break; 00262 } 00263 } 00264 Lyr = LyrDetList.GetNext(Lyr); // Get the next layer 00265 } 00266 00267 } while (!Unique); 00268 return(UniqueLayerID); 00269 } 00270 00271 /******************************************************************************************** 00272 00273 > BOOL LayerManager::CommitLayerChanges() 00274 00275 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00276 Created: 10/1/94 00277 Inputs: - 00278 Outputs: - 00279 Returns: Returns TRUE if successful, else InformError gets called and FALSE returned. 00280 00281 Purpose: If the layer details have changed then performs a LayerChangeOp which 00282 modifies the Camelot tree to reflect the changes made to the LyrDetList. 00283 00284 Errors: - 00285 SeeAlso: - 00286 00287 ********************************************************************************************/ 00288 00289 00290 BOOL LayerManager::CommitLayerChanges() 00291 { 00292 if (LayerDetailsChanged()) // The layer details have changed so we need to perform 00293 // a LayerChangeOp to commit the changes. 00294 { 00295 // Invoke the layer change operation 00296 // Obtain a pointer to the op descriptor for the Layer change operation 00297 OpDescriptor* OpDesc = 00298 OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpLayerChange)); 00299 // Invoke the operation. 00300 OpDesc->Invoke(); 00301 } 00302 if (RefreshLayerDetails()) // We need to refresh the layer details even if the layers were 00303 // not changed because a new layer could have been deleted 00304 { 00305 return TRUE; 00306 } 00307 else return FALSE; // Failed to refresh layer details (InformError has been called) 00308 } 00309 00310 /******************************************************************************************** 00311 00312 > BOOL LayerManager::NewCurrentSpread(Spread* NewCurrentSpread) 00313 00314 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00315 Created: 10/1/94 00316 Inputs: NewCurrentSpread 00317 Outputs: - 00318 Returns: TRUE if successful, else FALSE 00319 Purpose: Sets a new current spread. 00320 Errors: InformError gets called and FALSE is returned if we run out of memory 00321 SeeAlso: - 00322 00323 ********************************************************************************************/ 00324 00325 00326 BOOL LayerManager::NewCurrentSpread(Spread* NewCurrentSpread) 00327 { 00328 ENSURE(NewCurrentSpread != NULL, "The new current spread is NULL"); 00329 BOOL ok = TRUE; 00330 00331 if (CurrentSpread != NULL) // There is already a current spread 00332 { 00333 00334 // The LayerDetList should never be empty 00335 ENSURE(!LyrDetList.IsEmpty(), "Empty Layer details list"); 00336 00337 DeleteLayerDetList(); 00338 00339 } 00340 00341 // The LayerDetList should be empty 00342 ENSURE(LyrDetList.IsEmpty(), "Empty Layer details list"); 00343 00344 CurrentSpread = NewCurrentSpread; 00345 00346 // Read the current spread's layer details into the LyrDetList 00347 ok = ReadSpreadLayerDetails(); 00348 00349 return (ok); 00350 } 00351 00352 /******************************************************************************************** 00353 00354 > Spread* LayerManager::GetCurrentSpread() 00355 00356 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00357 Created: 18/1/94 00358 Inputs: - 00359 Outputs: - 00360 Returns: The LayerManagers current spread 00361 Purpose: For finding the current spread 00362 Errors: - 00363 SeeAlso: - 00364 00365 ********************************************************************************************/ 00366 00367 Spread* LayerManager::GetCurrentSpread() 00368 { 00369 return CurrentSpread; 00370 } 00371 00372 /******************************************************************************************** 00373 00374 > void LayerManager::UpdateInterface() 00375 00376 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00377 Created: 17/1/94 00378 Inputs: - 00379 Outputs: - 00380 Returns: - 00381 Purpose: Updates the interface after layers have changed. 00382 Errors: - 00383 SeeAlso: - 00384 00385 ********************************************************************************************/ 00386 00387 void LayerManager::UpdateInterface() 00388 { 00389 // BroadcastNewCurrentSpread(); 00390 } 00391 00392 /******************************************************************************************** 00393 00394 > void LayerManager::BroadcastNewCurrentSpread() 00395 00396 00397 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00398 Created: 10/1/94 00399 Inputs: - 00400 Outputs: - 00401 Returns: - 00402 Purpose: This private function gets called from NewCurrentSpread. It informs all 00403 subsystems (that need to know) that the Current Spread has changed. The 00404 LyrDetList contains the new current spread's details before this function is 00405 called. 00406 00407 Errors: - 00408 Scope: private 00409 SeeAlso: - 00410 00411 ********************************************************************************************/ 00412 00413 /* 00414 void LayerManager::BroadcastNewCurrentSpread() 00415 { 00416 // The InfoBar needs to know that the current spread has changed so that it can update 00417 // the layer list gadget. 00418 00419 // 4/5/94 - Markn changed this as infobar can now be NULL 00420 // ENSURE(CMainFrame::pInfoBar != NULL, "Infobar pointer is NULL in main frame"); 00421 // CMainFrame::pInfoBar->NewCurrentSpread(); 00422 00423 if (CMainFrame::pInfoBar != NULL) 00424 CMainFrame::pInfoBar->NewCurrentSpread(); 00425 } 00426 */ 00427 00428 /******************************************************************************************** 00429 00430 > BOOL LayerManager::CancelLayerChanges() 00431 00432 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00433 Created: 10/1/94 00434 Inputs: - 00435 Outputs: - 00436 Returns: TRUE if successful, FALSE otherwise 00437 Purpose: Causes the changes made to the LyrDetList to be discarded, and new values read. 00438 Errors: If memory runs out then InformError is called and the function returns FALSE 00439 SeeAlso: - 00440 00441 ********************************************************************************************/ 00442 00443 BOOL LayerManager::CancelLayerChanges() 00444 { 00445 DeleteLayerDetList(); // Delete details including any changes whioch may have been made 00446 if (ReadSpreadLayerDetails()) // Read new values 00447 { 00448 return TRUE; 00449 } 00450 else 00451 { 00452 return FALSE; 00453 } 00454 } 00455 00456 /******************************************************************************************** 00457 00458 > BOOL LayerManager::RefreshLayerDetails() 00459 00460 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00461 Created: 17/1/94 00462 Inputs: - 00463 Outputs: - 00464 Returns: Returns TRUE if successful, else calls InformError and returns FALSE 00465 Purpose: Reads in new layer details and updates the interface. 00466 Errors: - 00467 SeeAlso: - 00468 00469 ********************************************************************************************/ 00470 00471 BOOL LayerManager::RefreshLayerDetails() 00472 { 00473 // Make sure that no changes have been made 00474 DeleteLayerDetList(); // Delete details including any changes whioch may have been made 00475 if (ReadSpreadLayerDetails()) // Read new values 00476 { 00477 UpdateInterface(); 00478 return TRUE; 00479 } 00480 else return FALSE; // InformError has been called 00481 } 00482 00483 00484 /******************************************************************************************** 00485 00486 > void LayerManager::DeleteLayerDetList() 00487 00488 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00489 Created: 10/1/94 00490 Inputs: - 00491 Outputs: - 00492 Returns: - 00493 Purpose: Deletes the contents of the LyrDetList 00494 Errors: - 00495 Scope: private 00496 SeeAlso: - 00497 00498 ********************************************************************************************/ 00499 00500 void LayerManager::DeleteLayerDetList() 00501 { 00502 // Delete all current spread details 00503 ListItem* Current = LyrDetList.GetHead(); 00504 while (Current != NULL) 00505 { 00506 delete (LyrDetList.RemoveItem(Current)); 00507 Current = LyrDetList.GetHead(); 00508 } 00509 } 00510 00511 00512 /******************************************************************************************** 00513 00514 > BOOL LayerManager::ReadSpreadLayerDetails() 00515 00516 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00517 Created: 10/1/94 00518 Inputs: - 00519 Outputs: - 00520 Returns: TRUE if successful, else FALSE 00521 Purpose: Read the current spread's layer details into the LyrDetList. If 00522 memory runs out then InformError is called and FALSE is returned. 00523 00524 Errors: - 00525 Scope: private 00526 SeeAlso: - 00527 00528 ********************************************************************************************/ 00529 00530 BOOL LayerManager::ReadSpreadLayerDetails() 00531 { 00532 ENSURE(CurrentSpread != NULL, "Trying to read the details of a NULL current spread"); 00533 ENSURE(LyrDetList.IsEmpty(), "Layer details list not empty"); 00534 00535 LyrDetails* LayerDet; 00536 00537 Layer* Current = CurrentSpread->FindFirstLayer(); 00538 while (Current != NULL) 00539 { 00540 // Found a layer so record the details 00541 LayerDet = new LyrDetails(); 00542 if (LayerDet == NULL) 00543 { 00544 // Inform an error - The error will already be set by new 00545 InformError(); 00546 return FALSE; 00547 } 00548 LayerDet->Status = (Current)->GetLayerStatus(); // record the layer status 00549 LayerDet->m_pLayer = Current; 00550 LayerDet->New = FALSE; 00551 LayerDet->Deleted = FALSE; 00552 00553 LyrDetList.AddTail(LayerDet); // Add the layers details to the tail of the layer 00554 // detail list, so preserving the correct z-order. 00555 Current = Current->FindNextLayer(); 00556 } 00557 ENSURE(!LyrDetList.IsEmpty(), "No layers found on the current spread"); 00558 return TRUE; 00559 } 00560 00561 /******************************************************************************************** 00562 00563 > BOOL LayerManager::LayerDetailsChanged() 00564 00565 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00566 Created: 21/1/94 00567 Inputs: - 00568 Outputs: - 00569 Returns: TRUE if the LayerDetails list has changed 00570 Purpose: This function compares the current spread's layers against the Layer details 00571 list. If the layers have changed in any way, then the function returns TRUE. 00572 Otherwise the function returns FALSE. 00573 00574 Scope: private 00575 Errors: - 00576 SeeAlso: - 00577 00578 ********************************************************************************************/ 00579 00580 BOOL LayerManager::LayerDetailsChanged() 00581 { 00582 LyrDetails* CurrentLyrDet = (LyrDetails*)LyrDetList.GetHead(); 00583 Layer* CurrentLyr = CurrentSpread->FindFirstLayer(); // Get the first layer node 00584 00585 ENSURE(CurrentLyrDet != NULL, "There are no layer details on the layer details list"); 00586 ENSURE(CurrentLyr != NULL, "The LayerManager's current spread has no layers"); 00587 00588 while (CurrentLyrDet != NULL) 00589 { 00590 // We ignore deleted new layers because they don't change anything 00591 if (!(CurrentLyrDet->New && CurrentLyrDet->Deleted)) 00592 { 00593 if (CurrentLyr != CurrentLyrDet->m_pLayer) // z-order change 00594 { 00595 return TRUE; 00596 } 00597 else if ((CurrentLyrDet->New) || (CurrentLyrDet->Deleted)) 00598 { 00599 return TRUE; // New layer created or existing layer deleted 00600 } 00601 else if (!(CurrentLyrDet->Status == CurrentLyr->GetLayerStatus())) 00602 { 00603 // The layer's status has changed 00604 return TRUE; 00605 } 00606 CurrentLyrDet = (LyrDetails*)(LyrDetList.GetNext(CurrentLyrDet)); 00607 CurrentLyr = (CurrentLyr->FindNextLayer()); 00608 } 00609 else 00610 CurrentLyrDet = (LyrDetails*)(LyrDetList.GetNext(CurrentLyrDet)); 00611 } 00612 // Sanity check 00613 ENSURE (CurrentLyr == NULL, "CurrentLyr ptr should be NULL"); 00614 return FALSE; // Nothing has changed 00615 } 00616 00617 // Methods for the OpLayerChange 00618 00619 /******************************************************************************************** 00620 00621 > OpLayerChange::OpLayerChange() 00622 00623 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00624 Created: 29/9/93 00625 Inputs: - 00626 Outputs: - 00627 Returns: - 00628 Purpose: OpLayerChange constructor (Creates an undoable operation) 00629 Errors: - 00630 SeeAlso: - 00631 00632 ********************************************************************************************/ 00633 00634 00635 OpLayerChange::OpLayerChange(): UndoableOperation() 00636 { 00637 } 00638 00639 /******************************************************************************************** 00640 00641 > BOOL OpLayerChange::Init() 00642 00643 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00644 Created: 28/9/93 00645 Inputs: - 00646 Outputs: - 00647 Returns: TRUE if the operation could be successfully initialised 00648 FALSE if no more memory could be allocated 00649 00650 Purpose: OpLayerChange initialiser method 00651 Errors: ERROR will be called if there was insufficient memory to allocate the 00652 operation. 00653 SeeAlso: - 00654 00655 ********************************************************************************************/ 00656 00657 BOOL OpLayerChange::Init() 00658 { 00659 return (RegisterOpDescriptor( 00660 0, 00661 _R(IDS_LAYERCHANGEOP), 00662 CC_RUNTIME_CLASS(OpLayerChange), 00663 OPTOKEN_LYRCHNG, 00664 OpLayerChange::GetState, 00665 0, /* help ID */ 00666 _R(IDBBL_LAYERCHANGEOP), 00667 0 /* bitmap ID */)); 00668 } 00669 00670 /******************************************************************************************** 00671 00672 > OpState OpLayerChange::GetState(String_256*, OpDescriptor*) 00673 00674 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00675 Created: 28/9/93 00676 Inputs: - 00677 Outputs: - 00678 Returns: The state of the OpLayerChange operation 00679 Purpose: For finding the OpLayerChange's state. 00680 Errors: - 00681 SeeAlso: - 00682 00683 ********************************************************************************************/ 00684 00685 OpState OpLayerChange::GetState(String_256* UIDescription, OpDescriptor*) 00686 { 00687 OpState OpSt; 00688 return(OpSt); 00689 } 00690 00691 /******************************************************************************************** 00692 00693 > void OpLayerChange::Do(OpDescriptor*) 00694 00695 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00696 Created: 16/8/93 00697 Inputs: OpDescriptor (unused) 00698 Outputs: - 00699 Returns: - 00700 Purpose: Performs the layer change operation 00701 this operation reads the layer details list of the current documents layer 00702 manager, and changes the document tree to reflect any changes which have 00703 been made. 00704 Errors: - 00705 SeeAlso: - 00706 00707 ********************************************************************************************/ 00708 // The bounding rectangle of the current layer must be invalidated in all the following cases. 00709 00710 // If the visible status has changed 00711 // If the Quality level has changed 00712 // If the layer has been deleted 00713 // If the z-order of the layer has changed 00714 00715 00716 void OpLayerChange::Do(OpDescriptor*) 00717 { 00718 ENSURE(FALSE,"This shouldn't have been called"); 00719 /* 00720 Spread* pSpread = Document::GetCurrent()->GetLayerMgr().GetCurrentSpread(); 00721 // Find the first layer on the spread. All siblings of the first layer node should 00722 // be layer nodes 00723 Node* CurrentTreeLayer = pSpread->FindFirstLayer(); // skips over page nodes 00724 00725 ENSURE(CurrentTreeLayer->GetRuntimeClass() == CC_RUNTIME_CLASS(Layer), 00726 "A next sibling of a layer node is not a layer"); 00727 00728 00729 // Get the first layer details record 00730 LyrDetails* CurLyrDet = (LyrDetails*) 00731 (Document::GetCurrent()->GetLayerMgr()).LyrDetList.GetHead(); 00732 00733 BOOL InvalidateLayersRgn; // Flag used to decide if we should invalidate 00734 // a layers region 00735 BOOL RemoveSelections; // Flag used to indicate if we should remove all 00736 // selections from the layer 00737 00738 // loop while there are more changes to be made 00739 while (CurLyrDet != NULL) 00740 { 00741 InvalidateLayersRgn = FALSE; 00742 RemoveSelections = FALSE; 00743 00744 // We can ignore all new layers which have been deleted 00745 if (!((CurLyrDet->New) && (CurLyrDet->Deleted))) 00746 { 00747 // Is the layer a new layer ? 00748 if (CurLyrDet->New) 00749 { 00750 // Attempt to create a new layer node 00751 Layer* NewLyr; 00752 ALLOC_WITH_FAIL(NewLyr, (new Layer()), this); 00753 if (NewLyr == NULL) 00754 { 00755 goto EndOperation; // We were unable to create a new layer so 00756 // abort the operation 00757 } 00758 // Set the new layer's status 00759 NewLyr->SetLayerStatus(CurLyrDet->Status); 00760 00761 // Create a hide node action to hide the new node when we undo/redo 00762 HideNodeAction* UndoHideNodeAction; 00763 // ** Change !!! 00764 if (!HideNodeAction::Init(this, 00765 &UndoActions, 00766 NewLyr, 00767 TRUE, 00768 ( Action**)(&UndoHideNodeAction)) 00769 != AC_FAIL) 00770 { 00771 delete NewLyr; // We won't be needing this 00772 goto EndOperation; 00773 } 00774 // All is well 00775 if (CurrentTreeLayer != NULL) 00776 { 00777 // Add the new layer to the tree as a previous sibling of 00778 // the CurrentTreeLayer 00779 NewLyr->AttachNode(CurrentTreeLayer, PREV); 00780 } 00781 else 00782 { 00783 // Add the new layer as a last child of the spread 00784 NewLyr->AttachNode(Document::GetCurrent()-> 00785 GetLayerMgr().GetCurrentSpread(), LASTCHILD); 00786 } 00787 } 00788 00789 // Has the layer been deleted 00790 else if (CurLyrDet->Deleted) 00791 { 00792 if ( CurLyrDet->Layer == CurrentTreeLayer ) 00793 { 00794 // We are about to hide the CurrentTreeLayer so we need to find the 00795 // next layer before we do this 00796 CurrentTreeLayer = ((Layer*)CurrentTreeLayer)->FindNextLayer(); 00797 } 00798 00799 // If a layer has been deleted then we ignore all attribute changes 00800 // which may have been made prior to the layer being deleted. 00801 // Change 00802 if (!DoHideNode(CurLyrDet->Layer, 00803 TRUE // Include subtree size 00804 )) // Hide the node 00805 goto EndOperation; 00806 InvalidateLayersRgn = TRUE; // We will need to invalidate the hidden 00807 // layers bounding region. 00808 RemoveSelections = TRUE; 00809 } 00810 else 00811 { 00812 // Have the attributes of the layer changed 00813 if ( !(CurLyrDet->Status == CurLyrDet->Layer->GetLayerStatus()) ) 00814 { 00815 00816 // Determine if the attribute changes mean that the layer's 00817 // bounding rectangle must be invalidated. 00818 LayerStatus Old = CurLyrDet->Layer->GetLayerStatus(); 00819 LayerStatus New = CurLyrDet->Status; 00820 if ( 00821 (New.Flags.Visible != Old.Flags.Visible) || 00822 (New.LayerQualityLevel != Old.LayerQualityLevel) 00823 ) 00824 { 00825 InvalidateLayersRgn = TRUE; 00826 } 00827 00828 // Determine if the attribute changes mean that we should remove 00829 // the selections on the layer 00830 if ( 00831 ((New.Flags.Visible != Old.Flags.Visible) && 00832 (!New.Flags.Visible) 00833 ) || 00834 ((New.Flags.Locked != Old.Flags.Locked) && 00835 (New.Flags.Locked) 00836 ) 00837 ) 00838 { 00839 RemoveSelections = TRUE; 00840 } 00841 00842 // Try to create an action to restore the attribute changes we 00843 // are about to make 00844 ChangeLyrAttribAction* UndoAttribChngAction; 00845 00846 if ( ChangeLyrAttribAction::Init(this, 00847 &UndoActions, 00848 sizeof(InvalidateRegionAction), 00849 CurLyrDet->Layer->GetLayerStatus(), 00850 CurLyrDet->Layer, 00851 ( Action**)(&UndoAttribChngAction)) 00852 != AC_FAIL) 00853 { 00854 // Change the layer's attributes 00855 CurLyrDet->Layer->SetLayerStatus(CurLyrDet->Status); 00856 } 00857 else 00858 goto EndOperation; // We have failed 00859 00860 } 00861 // Has the current layers z-position changed ? 00862 if (CurLyrDet->Layer != CurrentTreeLayer) 00863 { 00864 // I don't think the CurrentTreeLayer can ever be NULL in this situation ! 00865 ENSURE(CurrentTreeLayer != NULL, "The current tree layer is NULL"); 00866 // Move the node to its correct tree position 00867 // *** Change 00868 if(!DoMoveNode(CurLyrDet->Layer, 00869 CurrentTreeLayer, 00870 PREV // The correct tree position 00871 )) 00872 { 00873 goto EndOperation; 00874 } 00875 } 00876 else // The layer is in the correct position in the tree 00877 { 00878 CurrentTreeLayer = ((Layer*)CurrentTreeLayer)->FindNextLayer(); 00879 } 00880 } 00881 // Do we want to remove the layer's selections 00882 if (RemoveSelections) 00883 { 00884 NodeRenderableInk::DeselectAllOnLayer(CurLyrDet->Layer); 00885 } 00886 00887 // Do we want to invalidate the bounding rectangle of the layer ? 00888 if (InvalidateLayersRgn) 00889 { 00890 DocRect Bounds = CurLyrDet->Layer->GetBoundingRect(); 00891 // Don't bother if the bounding rectangle is empty 00892 if (!Bounds.IsEmpty()) 00893 { 00894 // Create an InvalidateRegionAction 00895 if (!DoInvalidateNodeRegion(CurLyrDet->Layer, FALSE)) 00896 { 00897 goto EndOperation; 00898 } 00899 } 00900 } 00901 } 00902 // Process the next layer 00903 CurLyrDet = (LyrDetails*) 00904 (Document::GetCurrent()->GetLayerMgr()).LyrDetList.GetNext(CurLyrDet); 00905 } 00906 EndOperation: 00907 */ 00908 End(); 00909 } 00910 00911 /******************************************************************************************** 00912 00913 > void OpLayerChange::Undo() 00914 00915 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00916 Created: 17/1/94 00917 Inputs: - 00918 Outputs: - 00919 Returns: - 00920 Purpose: The overloaded Undo operation refreshes the layer details in the layer 00921 manager 00922 Errors: - 00923 SeeAlso: - 00924 00925 ********************************************************************************************/ 00926 00927 BOOL OpLayerChange::Undo() 00928 { 00929 BOOL Result = Operation::Undo(); 00930 if (Result) 00931 { 00932 //Document::GetCurrent()->GetLayerMgr().RefreshLayerDetails(); 00933 } 00934 return (Result); 00935 00936 } 00937 00938 /******************************************************************************************** 00939 00940 > void OpLayerChange::Redo() 00941 00942 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00943 Created: 17/1/94 00944 Inputs: - 00945 Outputs: - 00946 Returns: - 00947 Purpose: The overloaded Redo operation refreshes the layer details in the layer 00948 manager 00949 Errors: - 00950 SeeAlso: - 00951 00952 ********************************************************************************************/ 00953 00954 BOOL OpLayerChange::Redo() 00955 { 00956 BOOL Result = Operation::Redo(); 00957 if (Result) 00958 { 00959 //Document::GetCurrent()->GetLayerMgr().RefreshLayerDetails(); 00960 } 00961 return (Result); 00962 } 00963 00964 //------------------------------------------------------------------------------------------ 00965 //ChangeLyrAttribAction methods 00966 00967 /******************************************************************************************** 00968 00969 > ChangeLyrAttribAction::ChangeLyrAttribAction() 00970 00971 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00972 Created: 14/9/93 00973 Inputs: - 00974 Outputs: - 00975 Returns: - 00976 Purpose: ChangeLyrAttribAction constructor 00977 Errors: - 00978 SeeAlso: - 00979 00980 ********************************************************************************************/ 00981 00982 ChangeLyrAttribAction::ChangeLyrAttribAction() 00983 { 00984 } 00985 00986 /******************************************************************************************** 00987 00988 > ChangeLyrAttribAction::~ChangeLyrAttribAction() 00989 00990 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00991 Created: 13/1/94 00992 Inputs: - 00993 Outputs: - 00994 Returns: - 00995 Purpose: ChangeLyrAttribAction destructor 00996 Errors: - 00997 SeeAlso: - 00998 00999 ********************************************************************************************/ 01000 01001 01002 01003 ChangeLyrAttribAction::~ChangeLyrAttribAction() 01004 { 01005 01006 } 01007 01008 01009 01010 /******************************************************************************************** 01011 01012 > virtual ActionCode ChangeLyrAttribAction::Execute() 01013 01014 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01015 Created: 16/8/93 01016 Inputs: - 01017 Outputs: ActionCode indicating if the action was successfully executed or not 01018 Returns: - 01019 Purpose: Executes the ChangeLyrAttribAction 01020 Errors: - 01021 SeeAlso: - 01022 01023 01024 ********************************************************************************************/ 01025 01026 ActionCode ChangeLyrAttribAction::Execute() 01027 { 01028 ChangeLyrAttribAction ChngLyrAct; 01029 ActionCode ActCode; 01030 01031 // Create an action to restore the changes we are about to make 01032 if ((ActCode = ChangeLyrAttribAction::Init(pOperation, 01033 pOppositeActLst, 01034 sizeof(ChangeLyrAttribAction), 01035 ChangeLayer->GetLayerStatus(), // The current status 01036 ChangeLayer, 01037 ( Action**)(&ChngLyrAct))) != AC_FAIL) 01038 { 01039 // Remove the layers selection blobs if we are about to make the layer invisible, 01040 // or if we are about to lock the layer. 01041 //if ((Status.Flags.Locked) || 01042 // (!(Status.Flags.Visible))) 01043 //{ 01044 // NodeRenderableInk::DeselectAllOnLayer( ChangeLayer ); 01045 //} 01046 01047 // Preserve the Active flag of the changing layer 01048 LayerStatus CurrentStatus = ChangeLayer->GetLayerStatus(); 01049 //Status.Flags.Active = CurrentStatus.Flags.Active; 01050 01051 // Change the layer's status 01052 ChangeLayer->SetLayerStatus(Status); 01053 } 01054 return (ActCode); 01055 } 01056 01057 01058 /******************************************************************************************** 01059 01060 > static ActionCode ChangeLyrAttribAction::Init(Operation* const pOp, 01061 ActionList* pActionList, 01062 UINT32 ActionSize, 01063 LayerStatus& Status, 01064 Layer* Layer, 01065 Action** NewAction) 01066 01067 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01068 Created: 14/9/93 01069 01070 Inputs: pOp: The operation to which the action should be added 01071 01072 pActionList: The action list in the operation object 01073 01074 ActionSize: The size of the action in bytes. This should be the total 01075 size of the action (including any objects pointed to by the 01076 action). 01077 01078 Status: The status which is restored when executed 01079 Layer: The layer to change when we execute 01080 01081 01082 Outputs: NewAction: A pointer to the action if it could be allocated. 01083 01084 Returns: AC_FAIL: There was not enough room in the operation history for the 01085 action and the user did not wish to continue. Usually 01086 End() should be called in this situation. 01087 01088 AC_NORECORD: There was not enough room in the operation history for 01089 the action, but the user requested that he wished to 01090 continue without undo. 01091 01092 AC_OK : The action was successfully initialised and added to the 01093 operation. 01094 01095 01096 Purpose: To check that there is sufficient room for the action in the operation 01097 history, and if there is, then to add the action to the operations 01098 action list. 01099 01100 The function calls the Action::Init function passing the runtime class 01101 of a ChangeLyrAttribAction. 01102 Errors: - 01103 SeeAlso: Action::Init 01104 01105 ********************************************************************************************/ 01106 01107 ActionCode ChangeLyrAttribAction::Init(Operation* const pOp, 01108 ActionList* pActionList, 01109 UINT32 ActionSize, 01110 LayerStatus& Status, // The layer status which 01111 // should be restored 01112 // when we execute the action. 01113 Layer* Layer, // The layer to change when we execute 01114 01115 Action** NewAction) 01116 { 01117 01118 ActionCode Ac = (Action::Init(pOp, 01119 pActionList, 01120 ActionSize, 01121 CC_RUNTIME_CLASS(ChangeLyrAttribAction), 01122 NewAction)); 01123 01124 if (*NewAction != NULL) // The action has been allocated 01125 { 01126 ((ChangeLyrAttribAction*)(*NewAction))->ChangeLayer = Layer; 01127 ((ChangeLyrAttribAction*)(*NewAction))->Status = Status; 01128 } 01129 return (Ac); 01130 } 01131 01132 01133 01134 01135 01136 /******************************************************************************************** 01137 01138 > BOOL OpDelBar::Init() 01139 01140 Author: Simon_Knight (Xara Group Ltd) <camelotdev@xara.com> 01141 Created: 3/5/00 01142 Returns: TRUE if the operation could be successfully initialised 01143 FALSE if no more memory could be allocated 01144 Purpose: OpDelBar initialiser method 01145 Errors: ERROR will be called if there was insufficient memory to allocate the 01146 operation. 01147 SeeAlso: - 01148 01149 ********************************************************************************************/ 01150 BOOL OpMoveToLayer::Init() 01151 { 01152 return (RegisterOpDescriptor(0, 01153 _R(IDS_MOVE_SEL_TO_ACTIVE_LAYER), 01154 CC_RUNTIME_CLASS(OpMoveToLayer), 01155 OPTOKEN_MOVE_SEL_TO_ACTIVE_LAYER, 01156 OpMoveToLayer::GetState, 01157 0, // help ID 01158 0, // bubble help 01159 0, // resource ID 01160 0, // control ID 01161 SYSTEMBAR_ILLEGAL, // Bar ID 01162 TRUE, // Receive messages 01163 FALSE, 01164 FALSE, 01165 0, 01166 (GREY_WHEN_NO_CURRENT_DOC | DONT_GREY_WHEN_SELECT_INSIDE) )); 01167 } 01168 01169 01170 01171 /******************************************************************************************** 01172 01173 > OpState OpMoveToLayer::GetState(String_256* UIDescription, OpDescriptor *Bob) 01174 01175 Author: Simon_Knight (Xara Group Ltd) <camelotdev@xara.com> 01176 Created: 3/5/00 01177 Purpose: For finding the operations state. 01178 01179 ********************************************************************************************/ 01180 OpState OpMoveToLayer::GetState(String_256* UIDescription, OpDescriptor *Bob) 01181 { 01182 OpState OpSt; 01183 return(OpSt); 01184 } 01185 01186 01187 /******************************************************************************************** 01188 01189 > void OpMoveToLayer::Do(OpDescriptor*) 01190 01191 Author: Simon_Knight (Xara Group Ltd) <camelotdev@xara.com> 01192 Created: 3/5/00 01193 Purpose: This takes the selection and moves it to the active layer. This is a more 01194 powerful operation than the move forward/backward a layer 01195 01196 ********************************************************************************************/ 01197 void OpMoveToLayer::Do(OpDescriptor*) 01198 { 01199 if (DoStartSelOp(FALSE,TRUE)) 01200 { 01201 // get the selection 01202 Range Sel(*(GetApplication()->FindSelection())); 01203 01204 // set the range flags so it includes shadow and bevel manager nodes 01205 RangeControl rg = Sel.GetRangeControlFlags(); 01206 rg.PromoteToParent = TRUE; 01207 Sel.Range::SetRangeControl(rg); 01208 01209 // Prepare an ObjChangeParam so we can mark which nodes will allow this op to happen to them 01210 ObjChangeFlags cFlags; 01211 cFlags.MoveNode = TRUE; 01212 ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this); 01213 01214 // add items directly after the layer node as its first child 01215 Node * pTail = (Node *) (Document::GetCurrent()->GetInsertionPosition()); 01216 AttachNodeDirection TailAttachDirection = PREV; 01217 Spread* pSpread = Document::GetSelectedSpread(); 01218 01219 if (!pTail) 01220 { 01221 if (pSpread) 01222 { 01223 pTail = pSpread->FindActiveLayer(); 01224 // AttachNodeDirection TailAttachDirection = LASTCHILD; <--- AMB removed this and inserted the next line 2006-04-10 presuming bug 01225 TailAttachDirection = LASTCHILD; 01226 } 01227 else 01228 { 01229 FailAndExecute(); 01230 End(); 01231 return; // nowhere to put the nodes 01232 } 01233 } 01234 01235 01236 // Mark nodes that will allow this to happen, and error if no nodes will let it happen 01237 if (!Sel.AllowOp(&ObjChange)) 01238 { 01239 FailAndExecute(); 01240 End(); 01241 return; // op not allowed 01242 } 01243 01244 // get a list from which to move the nodes (fixes job #10781 - the re-selection of 01245 // moved nodes caused an infinite loop) 01246 01247 List* pNodeList = Sel.MakeListOfNodes(FALSE); 01248 NodeListItem* CurItem = (NodeListItem*)(pNodeList->GetHead()); 01249 while (CurItem) 01250 { 01251 Node* pNode = CurItem->pNode; 01252 01253 // Make sure the current owner Layer is told about the changes 01254 // and given the chance to release any cached info it may be 01255 // holding about the selected object 01256 // (I know that the original position coincides with the destination position 01257 // but this is hte simplest way to get the original parent layer uncached 01258 // and to get a record in the undo history so that the layer cacheing will 01259 // be dealt with properly during gundo/redo) 01260 DoInvalidateNodeRegion((NodeRenderableBounded*) pNode, TRUE, FALSE); 01261 01262 // localise attribs for this node 01263 DoLocaliseForAttrChange((NodeRenderableInk*) pNode, (AttrTypeSet *)NULL, (ObjectSet*) NULL); 01264 DoMoveNode(pNode, pTail, TailAttachDirection); 01265 // factor out common attribs 01266 if (pNode->IsCompound()) 01267 DoFactorOutCommonChildAttributes((NodeRenderableInk*) pNode); 01268 else 01269 DoFactorOutAfterAttrChange((NodeRenderableInk*) pNode, (AttrTypeSet *)NULL); 01270 01271 // make the nodes region be redrawn 01272 DoInvalidateNodeRegion((NodeRenderableBounded*) pNode, TRUE, FALSE); 01273 01274 CurItem = (NodeListItem*)(pNodeList->GetNext(CurItem)); 01275 } 01276 // delete the the list objects 01277 pNodeList->DeleteAll(); 01278 delete pNodeList; 01279 01280 // the selection will have changed - after all we just deleted it 01281 BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED)); 01282 GetApplication()->UpdateSelection(); 01283 01284 ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this); 01285 UpdateChangedNodes(&ObjChange); 01286 // end the op 01287 End(); 01288 01289 // update the bars 01290 DialogBarOp::SetSystemStateChanged(); 01291 DialogBarOp::UpdateStateOfAllBars(); 01292 } 01293 else 01294 { 01295 // give up and go home 01296 FailAndExecute(); 01297 End(); 01298 } 01299 }