collist.cpp

Go to the documentation of this file.
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 }

Generated on Sat Nov 10 03:44:51 2007 for Camelot by  doxygen 1.4.4