00001 // $Id: collist.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 // collist.cpp - Implementation fo the ColourList class 00100 00101 /* 00102 */ 00103 00104 // If you get any unexplainable problems with this file - Try changing the order of the includes 00105 // It's due to a curse put on Jason's code. 00106 00107 #include "camtypes.h" 00108 00109 //#include "basedoc.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00110 //#include "colcontx.h" 00111 #include "collist.h" 00112 //#include "colormgr.h" 00113 #include "colourix.h" 00114 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00115 //#include "jason.h" 00116 00117 00118 CC_IMPLEMENT_MEMDUMP(ColourList, List) 00119 00120 // Declare smart memory handling in Debug builds 00121 #define new CAM_DEBUG_NEW 00122 00123 00124 /********************************************************************************************** 00125 00126 > ColourList::ColourList() 00127 00128 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00129 Created: 25/5/94 00130 Inputs: - 00131 Outputs: - 00132 Returns: - 00133 00134 Purpose: ColourList constructor 00135 00136 **********************************************************************************************/ 00137 00138 ColourList::ColourList() 00139 { 00140 ParentDoc = NULL; // Document containing this list 00141 ArrayParent = NULL; // Current parent of the cached array 00142 InheritanceArray = NULL; // Cached array of all offspring of ArrayParent 00143 LastUnnamedColour = 2; // Memory to optimise unnamed-colour name generation 00144 } 00145 00146 00147 00148 /********************************************************************************************** 00149 00150 > ColourList::~ColourList() 00151 00152 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00153 Created: 17/11/94 00154 Inputs: - 00155 Outputs: - 00156 Returns: - 00157 00158 Purpose: ColourList destructor 00159 00160 **********************************************************************************************/ 00161 00162 ColourList::~ColourList() 00163 { 00164 InvalidateInheritanceCache(); // Release our memory claims 00165 00166 UnnamedColours.DeleteAll(); // Delete any remaining unnamed colours 00167 // This will probably cause IxCol in use errors 00168 // as by now all colours should have been deleted 00169 // automatically when their usage reached zero. 00170 } 00171 00172 /********************************************************************************************** 00173 00174 > void ColourList::Init(BaseDocument *ParentDocument) 00175 00176 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00177 Created: 7/11/94 00178 Inputs: ParentDocument - the parent document of this colour list 00179 00180 Purpose: ColourList initialiser. MUST be called after constructing a ColourList 00181 in order to correctly initialise it. Note that if ParentDocument is not 00182 set to a useful value, some operations on colour lists (eg. the colour 00183 editor) will fail. 00184 00185 **********************************************************************************************/ 00186 00187 void ColourList::Init(BaseDocument *ParentDocument) 00188 { 00189 ERROR3IF(ParentDocument == NULL, "NULL ParentDoc in ColourList::Init()"); 00190 ParentDoc = ParentDocument; 00191 } 00192 00193 /******************************************************************************************** 00194 00195 > void ColourList::InvalidateInheritanceCache(void) 00196 00197 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00198 Created: 17/11/94 00199 00200 Purpose: Deallocates any memory used for the array of IndexedColours compiled by 00201 ColourList::CompileInheritanceArray. The next request for such an array will 00202 be regenerated from the ColourList, rather than from cache. 00203 00204 This is automatically called by the ColourManager immediately prior to 00205 a ColourChangingMsg COLOURUPDATED message broadcast. 00206 00207 SeeAlso: ColourList::CompileInheritanceArray 00208 00209 ********************************************************************************************/ 00210 00211 void ColourList::InvalidateInheritanceCache(void) 00212 { 00213 if (InheritanceArray != NULL) 00214 CCFree(InheritanceArray); 00215 00216 InheritanceArray = NULL; 00217 ArrayParent = NULL; 00218 } 00219 00220 /********************************************************************************************** 00221 00222 > void ColourList::AddHead(ListItem *ItemToAdd) 00223 00224 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00225 Created: 16/12/94 00226 00227 Purpose: Overrides the List::AddHead method to ensure that any added item has a name 00228 which is unique within this colour list 00229 00230 ERROR3's if the item is not a NAMED IndexedColour 00231 00232 SeeAlso: ColourList::AddItem 00233 00234 **********************************************************************************************/ 00235 00236 void ColourList::AddHead(ListItem *ItemToAdd) 00237 { 00238 ERROR3IF(!IS_A(ItemToAdd, IndexedColour), "You can only insert IndexedColours into ColourLists!"); 00239 00240 IndexedColour *NewColour = (IndexedColour *) ItemToAdd; 00241 00242 // Ensure the colour has a name which is unique within this colour list 00243 ERROR3IF(!NewColour->IsNamed(), "You can't Insert an unnamed colour before a named one!"); 00244 00245 // It's a named colour, so make sure its name is unique 00246 String_64 NewName; 00247 if (GenerateUniqueColourName(NewColour->GetName(), &NewName)) 00248 NewColour->SetName(NewName); 00249 00250 // And call the base class to add the item 00251 List::AddHead(ItemToAdd); 00252 } 00253 00254 00255 00256 /********************************************************************************************** 00257 00258 > void ColourList::AddTail(ListItem *ItemToAdd) 00259 00260 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00261 Created: 16/12/94 00262 00263 Purpose: Overrides the List::AddTail method to ensure that any added item has a name 00264 which is unique within this colour list 00265 00266 ERROR3's if the item is not a NAMED IndexedColour 00267 00268 SeeAlso: ColourList::AddItem 00269 00270 **********************************************************************************************/ 00271 00272 void ColourList::AddTail(ListItem *ItemToAdd) 00273 { 00274 ERROR3IF(!IS_A(ItemToAdd, IndexedColour), "You can only insert IndexedColours into ColourLists!"); 00275 00276 IndexedColour *NewColour = (IndexedColour *) ItemToAdd; 00277 00278 // Ensure the colour has a name which is unique within this colour list 00279 ERROR3IF(!NewColour->IsNamed(), "You can't Insert an unnamed colour before a named one!"); 00280 00281 // It's a named colour, so make sure its name is unique 00282 String_64 NewName; 00283 if (GenerateUniqueColourName(NewColour->GetName(), &NewName)) 00284 NewColour->SetName(NewName); 00285 00286 // And call the base class to add the item 00287 List::AddTail(ItemToAdd); 00288 } 00289 00290 00291 00292 /********************************************************************************************** 00293 00294 > BOOL ColourList::AddItem(IndexedColour *NewColour) 00295 00296 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00297 Created: 25/5/94 00298 Returns: TRUE 00299 00300 Purpose: Adds an IndexedColour item to the tail of the ColourList 00301 The name of the colour is checked, and may be changed to ensure that it 00302 is a unique identifier within the scope of this colour list. 00303 00304 This can also be used to add unnamed colours - in this case, they are just 00305 added to the list of unnamed colours held by this object. 00306 00307 SeeAlso: ColourList::GenerateUniqueColourName 00308 00309 **********************************************************************************************/ 00310 00311 BOOL ColourList::AddItem(IndexedColour *NewColour) 00312 { 00313 // Ensure the colour has a name which is unique within this colour list 00314 if (!NewColour->IsNamed()) 00315 { 00316 UnnamedColours.AddTail(NewColour); 00317 return(TRUE); 00318 } 00319 00320 // It's a named colour, then... 00321 String_64 NewName; 00322 00323 if (GenerateUniqueColourName(NewColour->GetName(), &NewName)) 00324 NewColour->SetName(NewName); 00325 00326 // And add it to the tail of the list - using the base class function, not our overrides! 00327 List::AddTail(NewColour); 00328 return(TRUE); 00329 } 00330 00331 00332 00333 /********************************************************************************************** 00334 00335 > LISTPOS ColourList::InsertBefore(LISTPOS here, ListItem* item) 00336 > ListItem *ColourList::InsertBefore(ListItem* here, ListItem* item) 00337 > LISTPOS ColourList::InsertAfter(LISTPOS here, ListItem* item) 00338 > ListItem *ColourList::InsertAfter(ListItem* here, ListItem* item) 00339 00340 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00341 Created: 2/8/95 00342 00343 Inputs: here - the list item to insert before. NULL is not allowed (List is unhelpful) 00344 item - the item to insert before/after the 'here' item 00345 00346 Returns: The position/item which was inserted 00347 00348 Purpose: Inserts a NAMED IndexedColour at a particular list position 00349 (See List base class for a further description of the actual insertion process) 00350 00351 These methods are a veneer onto the normal list calls, which ensure that 00352 all inserted colours are given unique names within this list. 00353 00354 Note: IMPORTANT: NOTE that at present, 00355 these are NOT VIRTUAL, so you MUST call them using a ColourList pointer rather 00356 than a generic List pointer! 00357 00358 SeeAlso: List; List::InsertBefore; ColourList::GenerateUniqueColourName 00359 00360 **********************************************************************************************/ 00361 00362 LISTPOS ColourList::InsertBefore(LISTPOS here, ListItem* item) 00363 { 00364 ERROR3IF(!IS_A(item, IndexedColour), "You can only insert IndexedColours into ColourLists!"); 00365 00366 IndexedColour *NewColour = (IndexedColour *) item; 00367 00368 // Ensure the colour has a name which is unique within this colour list 00369 ERROR3IF(!NewColour->IsNamed(), "You can't Insert an unnamed colour before a named one!"); 00370 00371 // It's a named colour, so make sure its name is unique 00372 String_64 NewName; 00373 if (GenerateUniqueColourName(NewColour->GetName(), &NewName)) 00374 NewColour->SetName(NewName); 00375 00376 // And add it to the tail of the list - using the base class function, not our overrides! 00377 return(List::InsertBefore(here, item)); 00378 } 00379 00380 ListItem *ColourList::InsertBefore(ListItem* here, ListItem* item) 00381 { 00382 ERROR3IF(!IS_A(item, IndexedColour), "You can only insert IndexedColours into ColourLists!"); 00383 00384 IndexedColour *NewColour = (IndexedColour *) item; 00385 00386 // Ensure the colour has a name which is unique within this colour list 00387 ERROR3IF(!NewColour->IsNamed(), "You can't Insert an unnamed colour before a named one!"); 00388 00389 // It's a named colour, so make sure its name is unique 00390 String_64 NewName; 00391 if (GenerateUniqueColourName(NewColour->GetName(), &NewName)) 00392 NewColour->SetName(NewName); 00393 00394 // And add it to the tail of the list - using the base class function, not our overrides! 00395 return(List::InsertBefore(here, item)); 00396 } 00397 00398 LISTPOS ColourList::InsertAfter(LISTPOS here, ListItem* item) 00399 { 00400 ERROR3IF(!IS_A(item, IndexedColour), "You can only insert IndexedColours into ColourLists!"); 00401 00402 IndexedColour *NewColour = (IndexedColour *) item; 00403 00404 // Ensure the colour has a name which is unique within this colour list 00405 ERROR3IF(!NewColour->IsNamed(), "You can't Insert an unnamed colour before a named one!"); 00406 00407 // It's a named colour, so make sure its name is unique 00408 String_64 NewName; 00409 if (GenerateUniqueColourName(NewColour->GetName(), &NewName)) 00410 NewColour->SetName(NewName); 00411 00412 // And add it to the tail of the list - using the base class function, not our overrides! 00413 return(List::InsertAfter(here, item)); 00414 } 00415 00416 ListItem *ColourList::InsertAfter(ListItem* here, ListItem* item) 00417 { 00418 ERROR3IF(!IS_A(item, IndexedColour), "You can only insert IndexedColours into ColourLists!"); 00419 00420 IndexedColour *NewColour = (IndexedColour *) item; 00421 00422 // Ensure the colour has a name which is unique within this colour list 00423 ERROR3IF(!NewColour->IsNamed(), "You can't Insert an unnamed colour before a named one!"); 00424 00425 // It's a named colour, so make sure its name is unique 00426 String_64 NewName; 00427 if (GenerateUniqueColourName(NewColour->GetName(), &NewName)) 00428 NewColour->SetName(NewName); 00429 00430 // And add it to the tail of the list - using the base class function, not our overrides! 00431 return(List::InsertAfter(here, item)); 00432 } 00433 00434 00435 00436 /******************************************************************************************** 00437 00438 > virtual void ColourList::DeleteAll() 00439 00440 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00441 Created: 1/6/96 00442 00443 Purpose: Deletes the list, calling the destructors of all ListItems 00444 00445 Notes: Colours are deleted carefully to be tidy with child links 00446 (As we're deleting them all this shouldn't matter, but when children 00447 of a deleted colour are deleted, they poke its ChildUsage, and Smart 00448 Heap chokes itself in dismay. The old smartheap didn't care) 00449 00450 We thus vape all colour linking before deleting the colours. We 00451 don't need to be particularly gentle about this because we are 00452 deleting them all anyway. 00453 00454 SeeAlso: List::DeleteAll 00455 00456 ********************************************************************************************/ 00457 00458 void ColourList::DeleteAll() 00459 { 00460 // Vape all colour linkages in the named colour list 00461 IndexedColour *Ptr = (IndexedColour *) GetHead(); 00462 while (Ptr != NULL) 00463 { 00464 Ptr->SetLinkedParent(NULL, COLOURTYPE_NORMAL); 00465 Ptr = (IndexedColour *) GetNext(Ptr); 00466 } 00467 00468 // And vape all colour linkages in the UNnamed colour list 00469 Ptr = (IndexedColour *) UnnamedColours.GetHead(); 00470 while (Ptr != NULL) 00471 { 00472 Ptr->SetLinkedParent(NULL, COLOURTYPE_NORMAL); 00473 Ptr = (IndexedColour *) UnnamedColours.GetNext(Ptr); 00474 } 00475 00476 // Delete all the unnamed colours now too, just to be tidy 00477 UnnamedColours.DeleteAll(); 00478 00479 // Finally, call the base class to do the actual deletions 00480 List::DeleteAll(); 00481 } 00482 00483 00484 00485 /********************************************************************************************** 00486 00487 > UINT32 ColourList::GetUndeletedCount(void) 00488 00489 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00490 Created: 3/6/94 00491 Inputs: - 00492 Outputs: - 00493 Returns: The number of IndexedColours in this ColourList which are not 00494 'deleted' so as to be hidden from view by the undo system. 00495 00496 Purpose: Count the number of non-'deleted' items in a ColourList 00497 00498 **********************************************************************************************/ 00499 00500 UINT32 ColourList::GetUndeletedCount(void) 00501 { 00502 ListItem *Ptr = GetHead(); 00503 UINT32 Count = 0; 00504 00505 while (Ptr != NULL) 00506 { 00507 if ( !((IndexedColour *)Ptr)->IsDeleted() ) 00508 Count++; 00509 00510 Ptr = GetNext(Ptr); 00511 } 00512 00513 return(Count); 00514 } 00515 00516 00517 00518 /******************************************************************************************** 00519 00520 > IndexedColour *ColourList::FindUndeletedItem(INT32 Index) 00521 00522 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00523 Created: 3/6/94 00524 Inputs: ColourIndex - essentially a LISTPOS of the item in the Palette list 00525 00526 Returns: NULL if the index is past the end of the list 00527 else a pointer to the referenced IndexedColour ListItem 00528 00529 Purpose: The same as the conventional List FindItem() function, except 00530 that it treats 'deleted' colours as if they are not in the list. 00531 00532 ********************************************************************************************/ 00533 00534 IndexedColour *ColourList::FindUndeletedItem(INT32 Index) 00535 { 00536 IndexedColour *Ptr = (IndexedColour *) GetHead(); 00537 00538 while (Ptr != NULL) 00539 { 00540 if (!Ptr->IsDeleted() && --Index < 0) 00541 return(Ptr); 00542 00543 Ptr = (IndexedColour *) GetNext(Ptr); 00544 } 00545 00546 return(NULL); 00547 } 00548 00549 00550 00551 /******************************************************************************************** 00552 00553 > IndexedColour *ColourList::GetUndeletedHead(void) 00554 00555 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00556 Created: 6/3/95 00557 00558 Returns: NULL if the list contains no 'live' (non-deleted) colours 00559 else a pointer to the first IndexedColour ListItem in the list 00560 00561 Purpose: The same as the conventional List GetHead() function, except 00562 that it treats 'deleted' colours as if they are not in the list. 00563 00564 ********************************************************************************************/ 00565 00566 IndexedColour *ColourList::GetUndeletedHead(void) 00567 { 00568 IndexedColour *Ptr = (IndexedColour *) GetHead(); 00569 00570 while (Ptr != NULL && Ptr->IsDeleted()) 00571 Ptr = (IndexedColour *) GetNext(Ptr); 00572 00573 return(Ptr); 00574 } 00575 00576 00577 00578 /******************************************************************************************** 00579 00580 > IndexedColour *ColourList::GetUndeletedNext(IndexedColour *ThisItem) 00581 00582 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00583 Created: 6/3/95 00584 00585 Returns: NULL if the list contains no more 'live' (non-deleted) colours 00586 else a pointer to the next 'live' IndexedColour in the list 00587 00588 Purpose: The same as the conventional List GetNext() function, except 00589 that it treats 'deleted' colours as if they are not in the list. 00590 00591 ********************************************************************************************/ 00592 00593 IndexedColour *ColourList::GetUndeletedNext(IndexedColour *ThisItem) 00594 { 00595 ERROR2IF(ThisItem == NULL, NULL, 00596 "ColourList::GetUndeletedNext - NULL parameter is illegal"); 00597 00598 IndexedColour *Ptr = (IndexedColour *) GetNext(ThisItem); 00599 00600 while (Ptr != NULL && Ptr->IsDeleted()) 00601 Ptr = (IndexedColour *) GetNext(Ptr); 00602 00603 return(Ptr); 00604 } 00605 00606 00607 00608 /******************************************************************************************** 00609 00610 > IndexedColour **ColourList::CompileInheritanceArray(IndexedColour *Parent) 00611 00612 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00613 Created: 17/11/94 00614 Inputs: Parent - The colour for which you want an inheritance array 00615 00616 Returns: If NO error occurred, this returns a pointer to a NULL terminated array of 00617 IndexedColours, with Array[0] == Parent. 00618 If an error did occur, the error is reported, and NULL is returned 00619 00620 Purpose: Compiles a NULL-terminated array of pointers to ALL colours which are linked 00621 to this, both directly and indirectly (i.e. an array listing the entire 00622 inheritance 'subtree' from 'Parent', *including* 'Parent', and including 00623 named, unnamed, and 'deleted' colours). 00624 00625 This array is cached so that the cost of generating it several times in a 00626 row (as may be necessary for different clients of the ColourChangingMsg) 00627 is minimised. 00628 00629 Notes: The array is NULL terminated 00630 00631 The array INCLUDES Parent as its first member (Array[0]) 00632 00633 The array is owned (allocated and deallocated) by the ColourList. 00634 It MUST be treated as a read-only shared array. 00635 00636 The array includes ALL affected indexed colours. Use IsDeleted() and 00637 IsNamed() to sort out named/unnamed colours, and deleted (hidden for 00638 undo) colours. 00639 00640 This is expected to be called mainly as a result of COLOURUPDATED 00641 ColourChangingMsg broadcasts. The cache is flushed automatically 00642 by the colour manager just prior to these broadcasts. If you want to 00643 use this function outside these message broadcasts, then you must 00644 invalidate the cache at an appropriate time. 00645 00646 SeeAlso: ColourList::InvalidateInheritanceCache; 00647 IndexedColour::IsADescendantOf; 00648 ColourManager::ColourHasChanged 00649 00650 ********************************************************************************************/ 00651 00652 IndexedColour **ColourList::CompileInheritanceArray(IndexedColour *Parent) 00653 { 00654 if (Parent != ArrayParent) 00655 { 00656 InvalidateInheritanceCache(); // Throw away any existing array 00657 00658 // Generate the array 00659 INT32 ColourArraySize = 32; 00660 InheritanceArray = (IndexedColour**) CCMalloc(ColourArraySize * sizeof(IndexedColour *)); 00661 00662 if (InheritanceArray == NULL) 00663 { 00664 InformError(); // Out of memory - inform the user 00665 return(NULL); 00666 } 00667 00668 INT32 ListEnd = 1; // Initialise array to just the Parent 00669 InheritanceArray[0] = Parent; 00670 InheritanceArray[1] = NULL; 00671 00672 // Do all the Named colours 00673 IndexedColour *Ptr = (IndexedColour *) GetHead(); 00674 while (Ptr != NULL) 00675 { 00676 if (Ptr != Parent && Ptr->IsADescendantOf(Parent)) 00677 { 00678 // Is a descendant: add this item to the end of the list 00679 if (ListEnd >= ColourArraySize - 1) 00680 { 00681 // We've filled the array - must increase the size 00682 ColourArraySize += 32; 00683 IndexedColour **TempArray = (IndexedColour **) CCRealloc(InheritanceArray, 00684 ColourArraySize * sizeof(IndexedColour *)); 00685 if (TempArray == NULL) 00686 { 00687 InvalidateInheritanceCache(); // Free our existing memory claim 00688 InformError(); 00689 return(NULL); 00690 } 00691 00692 InheritanceArray = TempArray; // It worked- set our ptr to the new block 00693 } 00694 00695 InheritanceArray[ListEnd++] = Ptr; // Add the item and a new NULL terminator 00696 InheritanceArray[ListEnd] = 0; // to the end of the list 00697 } 00698 00699 Ptr = (IndexedColour *) GetNext(Ptr); 00700 } 00701 00702 00703 // And likewise with all unnamed colours 00704 IndexedColour *Next; 00705 Ptr = (IndexedColour *) UnnamedColours.GetHead(); 00706 while (Ptr != NULL) 00707 { 00708 // Allow for deleting this colour from underneath ourselves 00709 Next = (IndexedColour *) UnnamedColours.GetNext(Ptr); 00710 00711 if (Ptr->IsInUse()) 00712 { 00713 if (Ptr->IsADescendantOf(Parent)) 00714 { 00715 // Is a descendant: add this item to the end of the list 00716 if (ListEnd >= ColourArraySize - 1) 00717 { 00718 // We've filled the array - must increase the size 00719 ColourArraySize += 32; 00720 IndexedColour **TempArray = (IndexedColour **) CCRealloc(InheritanceArray, 00721 ColourArraySize * sizeof(IndexedColour *)); 00722 if (TempArray == NULL) 00723 { 00724 InvalidateInheritanceCache(); // Free our existing memory claim 00725 InformError(); 00726 return(NULL); 00727 } 00728 00729 InheritanceArray = TempArray; // It worked- set our ptr to the new block 00730 } 00731 00732 InheritanceArray[ListEnd++] = Ptr; // Add the item and a new NULL terminator 00733 InheritanceArray[ListEnd] = 0; // to the end of the list 00734 } 00735 } 00736 else 00737 { 00738 // We've found an unnamed IndexedColour which is not in use, so we can vape it 00739 TRACEUSER( "Jason", _T("CIA: Deleting unnamed colour which is not in use [%p]\n"), Ptr ); 00740 // UnnamedColours.RemoveItem(Ptr); 00741 // delete Ptr; 00742 } 00743 00744 Ptr = Next; 00745 } 00746 00747 00748 ArrayParent = Parent; 00749 } 00750 00751 TRACEUSER( "Jason", _T("\n")); 00752 00753 return(InheritanceArray); 00754 } 00755 00756 00757 00758 /******************************************************************************************** 00759 00760 > void ColourList::RemoveLinksToColour(IndexedColour *DeadColour) 00761 00762 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00763 Created: 18/11/94 00764 00765 Inputs: DeadColour - The colour for which all ParentColour references are to be 00766 removed. 00767 00768 Purpose: Scans the entire ColourList for any colours which reference the given 00769 IndexedColour. All these colours are converted into standalone 00770 representation of their former definition, so that all child-links of 00771 this colour are removed. It is then safe to delete the colour. 00772 00773 This is done automatically for colours deleted by the HideColours 00774 method of the colour manager; however, deletion only occurs for real 00775 when the undo record containing the deleted colours is deleted. 00776 00777 NOTE that this does NOT remove the colour from the ColourList 00778 It also does NOT delete the colour. 00779 00780 SeeAlso: ColourManager::HideColours 00781 00782 ********************************************************************************************/ 00783 00784 void ColourList::RemoveLinksToColour(IndexedColour *DeadColour) 00785 { 00786 // Search through the named colours 00787 IndexedColour *Ptr = (IndexedColour *) GetHead(); 00788 00789 while (Ptr != NULL) // For all colours in the list... 00790 { 00791 if (Ptr->FindLastLinkedParent() == DeadColour) // If they reference DeadColour... 00792 { 00793 IndexedColourType TheType = COLOURTYPE_NORMAL; 00794 00795 if (Ptr->GetType() == COLOURTYPE_SPOT) 00796 TheType = COLOURTYPE_SPOT; 00797 00798 Ptr->SetLinkedParent(NULL, TheType); // Convert to unlinked (normal/spot) colour 00799 } 00800 00801 Ptr = (IndexedColour *) GetNext(Ptr); 00802 } 00803 00804 00805 // And drag through the unnamed colours as well 00806 Ptr = (IndexedColour *) UnnamedColours.GetHead(); 00807 IndexedColour *Next; 00808 00809 while (Ptr != NULL) // For all colours in the list... 00810 { 00811 Next = (IndexedColour *) UnnamedColours.GetNext(Ptr); 00812 if (Ptr->FindLastLinkedParent() == DeadColour) // If they reference DeadColour... 00813 { 00814 IndexedColourType TheType = COLOURTYPE_NORMAL; 00815 00816 if (Ptr->GetType() == COLOURTYPE_SPOT) 00817 TheType = COLOURTYPE_SPOT; 00818 00819 Ptr->SetLinkedParent(NULL, TheType); // Convert to unlinked (normal/spot) colour 00820 } 00821 // This could be dangerous - what if the deleted colour is in the inheritance array? 00822 // if (!Ptr->IsInUse()) 00823 // { 00824 // // We've found an unnamed colour which is not in use - we can vape it 00825 //TRACEUSER( "Jason", _T("RLTC: Deleting unnamed colour which is not in use [%x]\n"), (INT32)Ptr); 00826 // UnnamedColours.RemoveItem(Ptr); 00827 // delete Ptr; 00828 // } 00829 00830 Ptr = Next; 00831 } 00832 } 00833 00834 00835 00836 /******************************************************************************************** 00837 00838 > BOOL ColourList::IsColourInUseInDoc(IndexedColour *TheColour, BOOL IgnoreColourGallery = FALSE) 00839 00840 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00841 Created: 27/6/95 00842 Inputs: TheColour - Points to the colour to check 00843 IgnoreColourGallery - TRUE to ignore usage in the colour gallery. DO NOT USE this 00844 parameter. It is a special-case for the colour gallery to use to ignore the 00845 usage that that gallery has of the colour. 00846 00847 Returns: TRUE if the colour is in use in the document 00848 00849 Purpose: Determine if a colour is used in the parent document. This is similar to 00850 IndexedColour::IsInUse(), but it also traverses the linking hierarchy 00851 to see if a colour is in use indirectly (e.g. A parent of a colour that 00852 is in use is needed for the document even if it is not used directly in\the 00853 document. 00854 00855 SeeAlso: IndexedColour::IsInUse 00856 00857 ********************************************************************************************/ 00858 00859 BOOL ColourList::IsColourInUseInDoc(IndexedColour *TheColour, BOOL IgnoreColourGallery) 00860 { 00861 ERROR3IF(TheColour == NULL, "Illegal NULL param"); 00862 00863 // First, is it directly in-use? 00864 if (TheColour->IsInUse(IgnoreColourGallery)) 00865 return(TRUE); 00866 00867 // Is it a parent of other colours? If not, then it is not in use 00868 if (!TheColour->IsNamed() || !TheColour->HasLinkedChildren()) 00869 return(FALSE); 00870 00871 // It has descendants, so scan the inheritance tree to determine if any of them are in use 00872 // Scan through the named colours (NOTE: We also scan 'deleted' colours, as a parent colour 00873 // may be indirectly in use in the undo record) 00874 IndexedColour *Ptr = (IndexedColour *) GetHead(); 00875 while (Ptr != NULL) // For all colours in the list... 00876 { 00877 if (Ptr != TheColour && Ptr->IsADescendantOf(TheColour)) // If this one is a descendant... 00878 { 00879 if (Ptr->IsInUse(IgnoreColourGallery)) // and it's in use, then we are 00880 return(TRUE); // in use, and can return now. 00881 } 00882 00883 Ptr = (IndexedColour *) GetNext(Ptr); 00884 } 00885 00886 // And scan through the unnamed colours as well 00887 Ptr = (IndexedColour *) UnnamedColours.GetHead(); 00888 while (Ptr != NULL) // For all colours in the list... 00889 { 00890 if (Ptr != TheColour && Ptr->IsADescendantOf(TheColour)) // If this one is a descendant... 00891 { 00892 if (Ptr->IsInUse()) // and it's in use, then we are 00893 return(TRUE); // in use, and can return now. 00894 } 00895 00896 Ptr = (IndexedColour *) UnnamedColours.GetNext(Ptr); 00897 } 00898 00899 // OK, we're obviously not in use then 00900 return(FALSE); 00901 } 00902 00903 00904 00905 /******************************************************************************************** 00906 00907 > BOOL ColourList::NamedColourExists(const char *pName) 00908 00909 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> (Jason copied this code here from colcomp.cpp) 00910 Created: 08/08/94 (19/12/94) 00911 Inputs: pName - the name to look for. 00912 Returns: TRUE if the name is already in use; 00913 FALSE otherwise. 00914 Purpose: Determine if a colour name is already in use by any colours stored 00915 in this colour list 00916 SeeAlso: ColourList::GenerateUniqueColourName 00917 00918 ********************************************************************************************/ 00919 00920 BOOL ColourList::NamedColourExists( PCTSTR pName ) 00921 { 00922 IndexedColour *pItem = (IndexedColour *) GetHead(); 00923 00924 while (pItem != NULL) 00925 { 00926 if (!pItem->IsDeleted() && pItem->IsNamed() && 00927 (pItem->GetName()->IsIdentical(pName)) ) 00928 { 00929 // The name is the same - it's a match 00930 return(TRUE); 00931 } 00932 00933 // Try the next colour 00934 pItem = (IndexedColour *) GetNext(pItem); 00935 } 00936 00937 // No match for this name 00938 return(FALSE); 00939 } 00940 00941 00942 00943 /******************************************************************************************** 00944 00945 > BOOL ColourList::NamedColourExists(const StringBase *pName) 00946 00947 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00948 Created: 19/12/94 00949 Inputs: pName - the name to look for. 00950 Returns: TRUE if the name is already in use; 00951 FALSE otherwise. 00952 Purpose: Determine if a colour name is already in use by any colours stored 00953 in this colour list 00954 SeeAlso: ColourList::GenerateUniqueColourName 00955 00956 ********************************************************************************************/ 00957 00958 BOOL ColourList::NamedColourExists(const StringBase *pName) 00959 { 00960 return(NamedColourExists((const TCHAR *)(*pName))); 00961 } 00962 00963 00964 00965 /******************************************************************************************** 00966 00967 > BOOL ColourList::GenerateUniqueColourName(const StringBase *pPrefix, String_64 *pResult) 00968 00969 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> (From code by Tim) 00970 Created: 16/12/94 (8/8/94) 00971 00972 Inputs: pPrefix - Points to the suggested name for this colour. This may be NULL, 00973 in which case a name based on the string "Unnamed" will be generated 00974 00975 Outputs: pResult - is filled in with a unique name 00976 NOTE that this is a String_64, the maximum length for a colour name. If 00977 the input pPrefix string is longer than will fit, it will be truncated. 00978 If truncation was necessary, this will have no effect on the return value. 00979 (IndexedColour::SetName will truncate strings longer than 64 chars as well) 00980 00981 Returns: TRUE if the pResult contains a different string from that supplied in 00982 pPrefix. (pResult will always contain a valid result, but checking this flag 00983 may save you the bother of copying the string over) 00984 00985 Purpose: Scans the entire ColourList to determine if the suggested name is unique 00986 within this document. If it is not, the name is altered (currently by 00987 truncating to 50 characters and appending a decimal number) to provide 00988 a unique name, which is returned in the supplied string. 00989 00990 This method can be called whenever you wish to generate a unique name for 00991 a colour. However, note that it is called automatically for every colour 00992 which is added to the colour list with the AddItem() method 00993 00994 Notes: Name matching is done using StringBase::IsIdentical, so see that method 00995 to determine the rules by which strings are matched 00996 00997 If the colour is unnamed (pPrefix == NULL, *pPrefix is a NULL string, 00998 or the name is "Unnamed" (_R(IDS_UNNAMEDCOLOUR)), then the code is optimised 00999 to provide a new name for it extra fast. 01000 01001 SeeAlso: ColourList::AddItem; IndexedColour::SetName; StringBase::IsIdentical 01002 01003 ********************************************************************************************/ 01004 01005 BOOL ColourList::GenerateUniqueColourName(const StringBase *pPrefix, String_64 *pResult) 01006 { 01007 if (pResult == NULL) 01008 { 01009 ERROR3("ColourList::GenerateUniqueColourName: pResult is NULL!"); 01010 return(FALSE); 01011 } 01012 01013 if (pPrefix != NULL && !NamedColourExists(pPrefix)) 01014 { 01015 // Either the List is empty, or this name is unique, so return it (ensuring < 64 chars) 01016 pPrefix->Left(pResult, 63); 01017 return(FALSE); 01018 } 01019 01020 // Copy the prefix into this string. 01021 String_64 NewName; 01022 BOOL Unnamed = FALSE; // Remember if it is 'unnamed' 01023 01024 if (pPrefix != NULL) 01025 pPrefix->Left(&NewName, 50); // Copy into NewName, truncating 01026 01027 String_64 NoName(_R(IDS_UNNAMEDCOLOUR)); 01028 if ((pPrefix == NULL) || (NewName.Length() == 0)) // Has no name, so call it "Unnamed" 01029 { 01030 Unnamed = TRUE; 01031 NewName = NoName; 01032 } 01033 else if (NewName.IsIdentical(NoName)) // Is called 'Unnamed', so remember that 01034 { 01035 Unnamed = TRUE; 01036 } 01037 01038 INT32 PrefixLen = NewName.Length(); 01039 if (PrefixLen > 50) 01040 { 01041 // Limit prefix length to 50 chars - this means we can add numbers up to 01042 // 10-odd digits long in order to make it unique - should be enough! 01043 PrefixLen = 50; 01044 } 01045 01046 01047 TCHAR *pPrefixEnd = (TCHAR *) NewName; 01048 pPrefixEnd += PrefixLen; 01049 01050 // Is this name ok? 01051 if (!NamedColourExists(NewName)) 01052 { 01053 (*pResult) = NewName; // Yes - return it. 01054 return(TRUE); 01055 } 01056 01057 // Start adding numbers to make it unique 01058 INT32 i = (Unnamed) ? LastUnnamedColour : 2; 01059 01060 while (TRUE) 01061 { 01062 // If this doesn't terminate [Tim] will eat [his] Archimedes! 01063 camSnprintf( pPrefixEnd, 64, _T(" %ld"), i++ ); 01064 01065 // Is this name ok? 01066 if (!NamedColourExists(NewName)) 01067 { 01068 (*pResult) = NewName; // Yes - return it 01069 01070 if (Unnamed) // Update unnamed colour generation number 01071 LastUnnamedColour = i; 01072 01073 return(TRUE); 01074 } 01075 } 01076 01077 *pResult = NewName; // Ensure stable return, though this should never happen 01078 return(TRUE); 01079 }