// $Id: ordlist.cpp 1282 2006-06-09 09:46:49Z alex $ /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE ================================XARAHEADERSTART=========================== Xara LX, a vector drawing and manipulation program. Copyright (C) 1993-2006 Xara Group Ltd. Copyright on certain contributions may be held in joint with their respective authors. See AUTHORS file for details. LICENSE TO USE AND MODIFY SOFTWARE ---------------------------------- This file is part of Xara LX. Xara LX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Xara LX and its component source files are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Xara LX (see the file GPL in the root directory of the distribution); if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADDITIONAL RIGHTS ----------------- Conditional upon your continuing compliance with the GNU General Public License described above, Xara Group Ltd grants to you certain additional rights. The additional rights are to use, modify, and distribute the software together with the wxWidgets library, the wxXtra library, and the "CDraw" library and any other such library that any version of Xara LX relased by Xara Group Ltd requires in order to compile and execute, including the static linking of that library to XaraLX. In the case of the "CDraw" library, you may satisfy obligation under the GNU General Public License to provide source code by providing a binary copy of the library concerned and a copy of the license accompanying it. Nothing in this section restricts any of the rights you have under the GNU General Public License. SCOPE OF LICENSE ---------------- This license applies to this program (XaraLX) and its constituent source files only, and does not necessarily apply to other Xara products which may in part share the same code base, and are subject to their own licensing terms. This license does not apply to files in the wxXtra directory, which are built into a separate library, and are subject to the wxWindows license contained within that directory in the file "WXXTRA-LICENSE". This license does not apply to the binary libraries (if any) within the "libs" directory, which are subject to a separate license contained within that directory in the file "LIBS-LICENSE". ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS ---------------------------------------------- Subject to the terms of the GNU Public License (see above), you are free to do whatever you like with your modifications. However, you may (at your option) wish contribute them to Xara's source tree. You can find details of how to do this at: http://www.xaraxtreme.org/developers/ Prior to contributing your modifications, you will need to complete our contributor agreement. This can be found at: http://www.xaraxtreme.org/developers/contribute/ Please note that Xara will not accept modifications which modify any of the text between the start and end of this header (marked XARAHEADERSTART and XARAHEADEREND). MARKS ----- Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara designs are registered or unregistered trademarks, design-marks, and/or service marks of Xara Group Ltd. All rights in these marks are reserved. Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. http://www.xara.com/ =================================XARAHEADEREND============================ */ // ordlist.cpp -- the OrderedList class /* */ #include "camtypes.h" //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "galstr.h" // For string resources #include "ordlist.h" #include "progress.h" #if TRUE CC_IMPLEMENT_DYNAMIC(OrderedList, CCObject) CC_IMPLEMENT_MEMDUMP(ComparatorInfo, ListItem) CC_IMPLEMENT_MEMDUMP(SequenceItem, ListItem) CC_IMPLEMENT_MEMDUMP(OrderSequence, ListItem) #define new CAM_DEBUG_NEW /********************************************************************************************** > ComparatorInfo::ComparatorInfo() Author: Jason_Williams (Xara Group Ltd) Created: 20/5/94 Inputs: - Outputs: - Returns: - Purpose: Constructor for a ComparatorInfo object Notes: This constructor should not really be used; if you do use it, then make sure that you set at least the SortFn and ResourceID fields of the new object to legal values, else OrderedList clients may explode. SeeAlso: OrderedList **********************************************************************************************/ ComparatorInfo::ComparatorInfo() { SortFn = NULL; CanReverse = TRUE; } /********************************************************************************************** > ComparatorInfo::ComparatorInfo(const ComparatorInfo &other) Author: Jason_Williams (Xara Group Ltd) Created: 20/5/94 Inputs: - Outputs: - Returns: - Purpose: Copy constructor for a ComparatorInfo object Notes: This constructor should not really be used; if you do use it, then make sure that you set at least the SortFn and ResourceID fields of the new object to legal values, else OrderedList clients may explode. SeeAlso: OrderedList **********************************************************************************************/ ComparatorInfo::ComparatorInfo(const ComparatorInfo &other) { SortFn = other.SortFn; SortName = other.SortName; CanReverse = other.CanReverse; } /********************************************************************************************** > ComparatorInfo::ComparatorInfo(ListComparator Compare, UINT32 SortName, BOOL Reverse = TRUE) Author: Jason_Williams (Xara Group Ltd) Created: 20/5/94 Inputs: Compare - The Comparator function used for the sort SortName - a resource ID for a string describing the sort (e.g. "Sort by Name", "Sort by Date", etc) Reverse - TRUE (the default) if the sort can be applied in reverse Outputs: - Returns: - Purpose: Constructor for a ComparatorInfo SeeAlso: OrderedList **********************************************************************************************/ ComparatorInfo::ComparatorInfo(ListComparator Compare, UINT32 SortNameID, BOOL Reverse) { SortFn = Compare; SortName.MakeMsg(SortNameID); CanReverse = Reverse; } /********************************************************************************************** > ComparatorInfo::ComparatorInfo(ListComparator Compare, const String_32 &Name, BOOL Reverse = TRUE) Author: Jason_Williams (Xara Group Ltd) Created: 20/5/94 Inputs: Compare - The Comparator function used for the sort Name - a string_32 describing the sort (e.g. "Sort by Name", "Sort by Date", etc) Reverse - TRUE (the default) if the sort can be applied in reverse Outputs: - Returns: - Purpose: Constructor for a ComparatorInfo This allows you to set the name given a String_32, which means that 'external' entities such as tools can provide sort modes. SeeAlso: OrderedList **********************************************************************************************/ ComparatorInfo::ComparatorInfo(ListComparator Compare, const String_32 &Name, BOOL Reverse) { SortFn = Compare; SortName = Name; CanReverse = Reverse; } /********************************************************************************************** > SequenceItem::SequenceItem() Author: Jason_Williams (Xara Group Ltd) Created: 18/5/94 Inputs: - Outputs: - Returns: - Purpose: Constructor for a SequenceItem SeeAlso: OrderSequence; OrderedList **********************************************************************************************/ SequenceItem::SequenceItem() { MasterItem = NULL; } /********************************************************************************************** > OrderSequence::OrderSequence() Author: Jason_Williams (Xara Group Ltd) Created: 18/5/94 Inputs: - Outputs: - Returns: - Purpose: Constructor for a OrderSequence SeeAlso: SequenceItem; OrderedList **********************************************************************************************/ OrderSequence::OrderSequence() { Comparator = NULL; Cached = FALSE; Reversed = FALSE; UsageCount = 0; } /********************************************************************************************** > OrderSequence::OrderSequence(ListComparator Compare, BOOL Reverse) Author: Jason_Williams (Xara Group Ltd) Created: 18/5/94 Inputs: Compare - A comparator function which determines the sort order Reverse - TRUE if you want the list sorted in reverse order Outputs: - Returns: - Purpose: Constructor for a OrderSequence SeeAlso: SequenceItem; OrderedList; keyword ListComparator **********************************************************************************************/ OrderSequence::OrderSequence(ListComparator Compare, BOOL Reverse) { Comparator = Compare; Cached = FALSE; Reversed = Reverse; UsageCount = 0; } /********************************************************************************************** > OrderedList::OrderedList() Author: Jason_Williams (Xara Group Ltd) Created: 16/5/94 Inputs: - Outputs: - Returns: - Purpose: OrderedList class constructor Notes: Remember to call OrderedList::Init() after creating **********************************************************************************************/ OrderedList::OrderedList() { SortOrders = NULL; // This is properly initialised in the Init() function for (INT32 i = 0; i < MaxSortKeys; i++) { SortMode[i].Info = NULL; SortMode[i].Reversed = FALSE; } } /********************************************************************************************** > OrderedList::~OrderedList() Author: Jason_Williams (Xara Group Ltd) Created: 16/5/94 Inputs: - Outputs: - Returns: - Purpose: OrderedList class destructor Errors: None **********************************************************************************************/ OrderedList::~OrderedList() { // Clear all encapsulated master and sequence items DeleteAll(); // Clear away our list of provided sort modes if (SortOrders != NULL) { SortOrders->DeleteAll(); delete SortOrders; } if (!Sequences.IsEmpty()) { #ifdef _DEBUG /* // Warn Jason that someone's being rampant JCWTRACE( _T(" ** Warning: OrderedList deleted with Sequences non-empty! Cleaning up...\n")); ListItem *Ptr = Sequences.GetHead(); while (Ptr != NULL) { // Check - if in use, somebody forgot to deselect an order. if ( ((OrderSequence *) Ptr)->UsageCount > 0 ) JCWTRACE( _T(" I was forced to delete an in-use sequence!\n")); Ptr = Sequences.GetNext(Ptr); } */ #endif Sequences.DeleteAll(); } } /********************************************************************************************** > BOOL OrderedList::Init(void) Author: Jason_Williams (Xara Group Ltd) Created: 20/5/94 Inputs: - Outputs: - Returns: FALSE if initialisation failed (lack of memory) Purpose: This initialises the OrderedList. Notes: This includes creation of a List of avaliable Sorts. NO LONGER AVAILABLE: The OrderedList base class provides only one sort method - "Unsorted" Derived classes may override this function if they don't want 'Unsorted' to be an available method. If you want this, then all you need to do is uncomment this stuff and add a string resource baclk in for its name. **********************************************************************************************/ BOOL OrderedList::Init(void) { if (SortOrders == NULL) // Only init if we have not already done so { SortOrders = new List; if (SortOrders == NULL) return(FALSE); // ComparatorInfo *SortOrder; // // SortOrder = new ComparatorInfo(Unsorted, _R(IDS_SORTBY_UNSORTED), FALSE); // if (SortOrder == NULL) // return(FALSE); // // SortOrders->AddTail(SortOrder); } return(TRUE); } /********************************************************************************************** > BOOL OrderedList::AddItem(ListItem *TheItem) Author: Jason_Williams (Xara Group Ltd) Created: 18/5/94 Inputs: ListItem - The item to add to the master list Outputs: - Returns: TRUE if it succeeds, FALSE if there isn't enough memory Purpose: Adds the given ListItem to the OrderedList. Notes This adds entries to all sequences in this OrderedList which refer to the new item in the master list. All lists will be resorted to place this item correctly the next time they are SelectOrder'd **********************************************************************************************/ BOOL OrderedList::AddItem(ListItem *TheItem) { MasterList.AddTail(TheItem); OrderSequence *TheSeq = (OrderSequence *) Sequences.GetHead(); SequenceItem *NewItem; while (TheSeq != NULL) { TheSeq->Cached = FALSE; // This sequence needs re-sorting NewItem = new SequenceItem; if (NewItem == NULL) { ENSURE(FALSE, "OrderedList::AddItem failed to allocate new SequenceItem"); return(FALSE); } NewItem->MasterItem = TheItem; // Set up the new SeqItem TheSeq->Sequence.AddTail(NewItem); // Add it to this Sequence TheSeq = (OrderSequence *) Sequences.GetNext(TheSeq); // Move on to the next sequence } return(TRUE); } /********************************************************************************************** > ListItem *OrderedList::RemoveMasterItem(ListItem *TheItem) Author: Jason_Williams (Xara Group Ltd) Created: 18/5/94 Inputs: TheItem - A pointer to the item which you want to remove Outputs: - Returns: The item that was removed (returns the pointer as passed in) Purpose: Delinks the given item from the OrderedList. TheItem is NOT deleted - it is up to you to do this when you're finished with it Notes: (Removes the item from the Master List, and deletes all reference to it from all sequence lists. TheItem is NOT deleted) **********************************************************************************************/ ListItem *OrderedList::RemoveMasterItem(ListItem *TheItem) { MasterList.RemoveItem(TheItem); OrderSequence *TheSeq = (OrderSequence *) Sequences.GetHead(); SequenceItem *SeqItem; while (TheSeq != NULL) { SeqItem = (SequenceItem *) TheSeq->Sequence.GetHead(); while (SeqItem != NULL) { if (TheItem == SeqItem->GetItem()) break; SeqItem = (SequenceItem *) TheSeq->Sequence.GetNext(SeqItem); } if (SeqItem == NULL) { ENSURE(FALSE, "OrderedList::RemoveItem- Expected SequenceItem was not found!"); return(TheItem); } TheSeq->Sequence.RemoveItem(SeqItem); delete SeqItem; TheSeq = (OrderSequence *) Sequences.GetNext(TheSeq); // Move on to the next sequence } return(TheItem); } /********************************************************************************************** > void OrderedList::DeleteAll(void) Author: Jason_Williams (Xara Group Ltd) Created: 18/5/94 Inputs: - Outputs: - Returns: - Purpose: Removes all items in the OrderedList, calling all their destructors Notes: This includes ALL items in all sequences AND THE MASTER LIST held by the OrderedList (i.e. deletes all enclosed objects) **********************************************************************************************/ void OrderedList::DeleteAll(void) { ListItem *Ptr = MasterList.GetHead(); ListItem *Next; while (Ptr != NULL) { Next = MasterList.GetNext(Ptr); RemoveMasterItem(Ptr); delete Ptr; Ptr = Next; } } /********************************************************************************************** > void OrderedList::InvalidateCaches(void) Author: Jason_Williams (Xara Group Ltd) Created: 18/5/94 Inputs: - Outputs: - Returns: - Purpose: Informs the OrderedList that something you've done to the list or a ListItem in it could possibly change the sort order. Notes: This causes all sequences to be resorted (reasonably quick if they're already almost in the correct order) the next time they are SelectOrder'd. Note that this is done automatically if you add items through the OrderedList interface, so you should only need to call this if you change data in a listitem which is (or potentially may be) used as a sort key. Note that OrderedList::InvalidateSequenceCache can be used on a single Sequence, but this should only be used if you can absolutely positively guarantee (beyond a shadow of a doubt and more certainly than a really certain certainty) that your change will only ever affect the sort order of that one sequence. SeeAlso: OrderedList::InvalidateSequenceCache **********************************************************************************************/ void OrderedList::InvalidateCaches(void) { OrderSequence *TheSeq = (OrderSequence *) Sequences.GetHead(); while (TheSeq != NULL) { TheSeq->Cached = FALSE; TheSeq = (OrderSequence *) Sequences.GetNext(TheSeq); } } /********************************************************************************************** > OrderSequence *OrderedList::FindSequence(ListComparator Compare, BOOL Reverse) Author: Jason_Williams (Xara Group Ltd) Created: 18/5/94 Inputs: Compare - A ListComparator function defining the sort order Reverse - TRUE if you want a reverse-order sort Outputs: - Returns: - Purpose: Internal list search method. This searches the list of available sequences, and returns a pointer to the first one that matches the given comparator function, or NULL if there is no such sequence available. Scope: private **********************************************************************************************/ OrderSequence *OrderedList::FindSequence(ListComparator Compare, BOOL Reverse) { if (Compare == NULL) return(NULL); OrderSequence *TheSeq = (OrderSequence *) Sequences.GetHead(); while (TheSeq != NULL) { if (TheSeq->Comparator == Compare && TheSeq->Reversed == Reverse) return((OrderSequence *) TheSeq); TheSeq = (OrderSequence *) Sequences.GetNext(TheSeq); // Move on to the next sequence } return(NULL); } /********************************************************************************************** > OrderSequence *OrderedList::CreateSequence(ListComparator Compare, BOOL Reverse) Author: Jason_Williams (Xara Group Ltd) Created: 18/5/94 Inputs: Compare - A ListComparator function defining the sort order Reverse - TRUE if you want a reverse-order sort Outputs: - Returns: - Purpose: Internal list maintenance method. If, after calling OrderedList::FindSequence, you can't find a given sequence, then you can create a new instance of that sequence by calling this function. It is added to the end of the list, and no checks for duplicates are made (if a duplicate exists, the first one created will always be used) **********************************************************************************************/ OrderSequence *OrderedList::CreateSequence(ListComparator Compare, BOOL Reverse) { if (Compare == NULL) return(NULL); OrderSequence *TheSeq; TheSeq = new OrderSequence(Compare, Reverse); if (TheSeq == NULL) return(NULL); Sequences.AddTail(TheSeq); ListItem *Ptr = MasterList.GetHead(); SequenceItem *NewItem; while (Ptr != NULL) { NewItem = new SequenceItem; if (NewItem == NULL) { ENSURE(FALSE, "OrderedList::CreateSequence failed to allocate new SequenceItem"); return(NULL); } NewItem->MasterItem = Ptr; // Set up the new SeqItem TheSeq->Sequence.AddTail(NewItem); // Add it to this Sequence Ptr = MasterList.GetNext(Ptr); } return(TheSeq); } /********************************************************************************************** > BOOL OrderedList::SortSequence(OrderSequence *TheSeq) Author: Jason_Williams (Xara Group Ltd) Created: 18/5/94 Inputs: TheSeq - The OrderSequence to be sorted Reverse - TRUE if you want it sorted into reverse order Outputs: - Returns: - Purpose: Internal list maintenance method. Sorts the given sequence into order using a sort and the user-supplied comparator function. This sounds slow, but (a) we're only intending to sort short lists, so should be fast enough, (b) It's not a completely silly implementation, and (c) the sort is only used when the sequence is created, and when it gets out of order. In the latter case, it usually means that the list is very close to correct sorted order, and only 1 or 2 passes will be needed to bring the list back to fully sorted order. (Probably if this sort turns out to be slow, it will be best to change to a faster sort for the original (creation) sort, and leave this in place for resorting the near-correct list) Just in case, SlowJob progress indicators are displayed while sorting **********************************************************************************************/ BOOL OrderedList::SortSequence(OrderSequence *TheSeq) { if (TheSeq == NULL || TheSeq->Comparator == NULL) // Error! return(FALSE); if (TheSeq->Cached) // Well, I reckon it's already sorted. Hah return(TRUE); SequenceItem *ItemA; SequenceItem *ItemB; SequenceItem *ItemC; BOOL Sorted; INT32 CompareResult; // Commented out 11/1/95 by Markn because Jason told me to. And it fixes one of my bugs. // Sometimes this gets called when there's already a slow job going (e.g. import with layers with layer gal open). // // BeginSlowJob(-1); // Show hourglass, with delay, no percentage do { Sorted = TRUE; // Assume in sorted order until we have to move an item ItemA = (SequenceItem *) TheSeq->Sequence.GetHead(); while (ItemA != NULL) { ContinueSlowJob(); ItemB = (SequenceItem *) TheSeq->Sequence.GetNext(ItemA); if (ItemB == NULL) // At end of list, so have finished this pass break; if (TheSeq->Reversed) CompareResult = TheSeq->Comparator(this, ItemB->GetItem(), ItemA->GetItem()); else CompareResult = TheSeq->Comparator(this, ItemA->GetItem(), ItemB->GetItem()); if (CompareResult > 0) { Sorted = FALSE; // Have to move an item - can't be in order yet // Delink ItemA from the list - it has to move up TheSeq->Sequence.RemoveItem(ItemA); // Search for proper position for A... ItemC = (SequenceItem *) TheSeq->Sequence.GetNext(ItemB); while (ItemC != NULL) { if (TheSeq->Reversed) CompareResult = TheSeq->Comparator(this, ItemC->GetItem(), ItemA->GetItem()); else CompareResult = TheSeq->Comparator(this, ItemA->GetItem(), ItemC->GetItem()); if (CompareResult <= 0) // Have found place to drop ItemA... break; ItemC = (SequenceItem *) TheSeq->Sequence.GetNext(ItemC); } if (ItemC == NULL) TheSeq->Sequence.AddTail(ItemA); // Belongs at end of list else TheSeq->Sequence.InsertBefore(ItemC, ItemA); // Belongs just before ItemC } ItemA = ItemB; // Loop, from the next unsorted item } } while (!Sorted); // EndSlowJob(); BeginSlowJob() statement see above TheSeq->Cached = TRUE; return(TRUE); } /********************************************************************************************** > List *OrderedList::SelectOrder(ListComparator Compare, BOOL Reversed = FALSE) Author: Jason_Williams (Xara Group Ltd) Created: 18/5/94 Inputs: Compare - a list comparator function which determines how the list will be sorted. Reversed - TRUE if you wish the list to be sorted using the comparator into reverse order. Outputs: - Returns: A pointer to a List of SequenceItems, sorted as desired, or NULL if it failed. Purpose: Selects a given order for use. Once selected, you can traverse the OrderedList much like an ordinary list (see the SeeAlso comments) only you'll find that the items are returned by GetNext/Prev in an order dicatated by the ListComparator function that you supplied on selection. Notes: Selecting has the following effects: * Increments a UsageCount (which is decremented by DeselectOrder) - While selected, a sequence cannot be DestroyOrder'd * Creates (if necessary) a new sequence within the OrderedList * Sorts (if necessary) the list using the given comparator function Sorting occurs when the sequence is first created, and thereafter when SelectOrder() is called AND it is determined that the list order may be incorrect (when item(s) have been added, or InvalidataeCache menthods have been invoked) If an 'Unsorted' order is requested, this actually returns the Master List; this can be traversed in exactly the same manner as an OrderedList (as normal ListItems also have a GetItem() method). Passing 'Compare' == NULL will ignore the 'Reversed' parameter and simply return the master list. SeeAlso: OrderedList::InvalidateCaches; OrderedList::DeselectOrder; OrderedList::DestroyOrder; Keyword ListComparator **********************************************************************************************/ List *OrderedList::SelectOrder(ListComparator Compare, BOOL Reverse) { if (Compare == NULL || Compare == Unsorted) return(&MasterList); OrderSequence *TheSeq = FindSequence(Compare, Reverse); // Find existing Seq? if (TheSeq == NULL) // No - create new one TheSeq = CreateSequence(Compare, Reverse); if (TheSeq == NULL) // Failed - argh! return(NULL); if (!TheSeq->Cached) // Needs sorting? SortSequence(TheSeq); TheSeq->UsageCount++; // Increment the usage count return(&TheSeq->Sequence); } /********************************************************************************************** > void OrderedList::ReSortOrder(ListComparator Compare, BOOL Reversed = FALSE) Author: Jason_Williams (Xara Group Ltd) Created: 18/5/94 Inputs: Compare - a list comparator function which determines how the list will be sorted. Reversed - TRUE if you wish the list to be sorted using the comparator into reverse order. Outputs: - Returns: - Purpose: Immediately (re-)sorts the given order. If no such order exists, no action is taken (a new order sequence will NOT be created, as this will happen anyway if you subsequently try to Select it) Normally, if you add an item to the order sequence, it is not sorted into its correct position until the next time the order is selected; The item will be added at the tail of the list. This allows you to continue scanning the list knowing that it has not shifted about under you. However, if adding items to the list you may want to immediately force a resort to ensure it is in order (if you are not going to SelectOrder on the list before using it again) Passing 'Compare' == NULL will ignore the 'Reversed' parameter and simply do nothing (as this asks you to resort the master list). SeeAlso: OrderedList::InvalidateCaches; OrderedList::SelectOrder; Keyword ListComparator **********************************************************************************************/ void OrderedList::ReSortOrder(ListComparator Compare, BOOL Reverse) { OrderSequence *TheSeq = FindSequence(Compare, Reverse); // Find existing Seq? if (TheSeq == NULL) // No such seq - exit return; SortSequence(TheSeq); // Force a sort } /********************************************************************************************** > void OrderedList::DeselectOrder(ListComparator Compare, BOOL Reversed = FALSE) Author: Jason_Williams (Xara Group Ltd) Created: 18/5/94 Inputs: Compare - The list comparator function which defined the sort order Reversed - TRUE if you wish to deselect the Reverse-sorted order Outputs: - Returns: - Purpose: This indicates to the OrderedList that you have finished using the given sequence (list sort-order). This unlocks the List so that the sequence may be deleted using the DestroyOrder function. Notes: Passing 'Compare' == NULL will ignore the 'Reversed' parameter and simply 'deselect' the master list (this in fact returns, doing nothing). SeeAlso: OrderedList; OrderedList::SelectOrder; OrderedList::DestroyOrder Errors: This ENSUREs that the sequence exists (has been Selected and not yet Destroy'd) and that the UsageCount is legal (that Deselect has not been called more often than Select) **********************************************************************************************/ void OrderedList::DeselectOrder(ListComparator Compare, BOOL Reversed) { if (Compare == NULL || Compare == Unsorted) return; OrderSequence *TheSeq = FindSequence(Compare, Reversed); // Find existing Seq? ENSURE(TheSeq != NULL, "OrderedList::DeselectOrder called for nonexistent sequence!"); ENSURE(TheSeq->UsageCount > 0, "OrderedList::DeselectOrder called more often than SelectOrder!"); TheSeq->UsageCount--; // Decrement the usage count } /********************************************************************************************** > void OrderedList::DestroyOrder(ListComparator Compare, BOOL Reversed = FALSE) Author: Jason_Williams (Xara Group Ltd) Created: 18/5/94 Inputs: Comparator - The comparator function which determines the sort order Reversed - TRUE if you wish to destroy the reverse-sorted order. Outputs: - Returns: - Purpose: Destroys an order sequence. This is not strictly necessary, but allows you to make the OrderedList release all memory used by the sequence if you know that you no longer need to acces that sort order. (If you may want to look at the list again, it is probably more efficient to never call Destroy, so that the cached sort order is available to you in the future, without having to re-sort the items) Notes: The sequence will ONLY be destroyed if its usage count is zero (if the order has been deselected exactly the same number of times it has been selected. This means you can call Destroy after every use of the order if you wish, and it will be deleted only if nobody else is sharing it. Passing 'Compare' == NULL will ignore the 'Reversed' parameter and simply do nothing (You can't destroy the master list). SeeAlso: OrderedList::SelectOrder; OrderedList::DeselectOrder Errors: In the debug build, this ENSURES that you don't try to destroy an order which does not exist, and that the order is not in use (selected) when you try to destroy it. In the release build, this will just delete the sequence if it can be found **********************************************************************************************/ void OrderedList::DestroyOrder(ListComparator Compare, BOOL Reversed) { if (Compare == NULL || Compare == Unsorted) return; OrderSequence *TheSeq = FindSequence(Compare, Reversed); // Find existing Seq? ENSURE(TheSeq != NULL, "OrderedList::DestroyOrder called for nonexistent sequence!"); if (TheSeq != NULL && TheSeq->UsageCount == 0) { Sequences.RemoveItem(TheSeq); TheSeq->Sequence.DeleteAll(); delete TheSeq; } } /********************************************************************************************** > INT32 OrderedList::Unsorted(OrderedList *ParentList, ListItem *Item1, ListItem *Item2) Author: Jason_Williams (Xara Group Ltd) Created: 18/5/94 Inputs: ParentList - the OrderedList in which these items are linked Item1, Item2 - the two items to be compared Outputs: - Returns: A negative value if Item1 is considered "less than" Item2 A positive value if Item1 is considered "greater than" Item2 Zero if Item1 is considered "equal to" Item2 Purpose: "Unsorted" List sort ComparatorFunction, and an example of writing ListComparators. Determines if two items in an OrderedList need to be swapped during a sort operation. The function returns a value indicating if the items were considered equal, or if one item was "greater than" or "less than" the other. Notes: This particular function always returns zero, so that it imposes no order at all upon the list, thus giving an "Unsorted" List order. Normally, we would code the function to return the 3 possible results e.g. If we wish to compare two integers to sort them into ascending order, we should return(Item1->IntegerValue - Item2->IntegerValue) NOTE, however, that care must be taken to always return an 'INT32' compatible value (i.e. if comparing INT32s, you should code to return -1, 0, or +1, using explicit < and == comparisons) In your own ListComparator functions, you should attempt to check the runtime type of the provided ListItems to ensure they are of an appropriate type to be sorted using your function. SeeAlso: ListComparator **********************************************************************************************/ INT32 OrderedList::Unsorted(OrderedList *ParentList, ListItem *Item1, ListItem *Item2) { return(0); } /********************************************************************************************** > List *OrderedList::GetSortOrders(void) Author: Jason_Williams (Xara Group Ltd) Created: 23/5/94 Inputs: - Outputs: - Returns: A pointer to a list of ComparatorInfo objects enumerating the sort orders available from this OrderedList object. Purpose: Find a list of available sorting orders. SeeAlso: ComparatorInfo; ListComparator **********************************************************************************************/ List *OrderedList::GetSortOrders(void) { return(SortOrders); } /********************************************************************************************** > void OrderedList::AddSortOrder(const ComparatorInfo &CompInfo) Author: Jason_Williams (Xara Group Ltd) Created: 25/5/94 Inputs: CompInfo - a ComparatorInfo object describing the new sort method. Note that this will be duplicated and added into the list if such a sort is not already in the list. Outputs: - Returns: - Purpose: Add a sort order to the list of those available from this OrderedList object. SeeAlso: ComparatorInfo; ListComparator **********************************************************************************************/ void OrderedList::AddSortOrder(const ComparatorInfo &CompInfo) { ComparatorInfo *Ptr; ENSURE(SortOrders != NULL, "Someone forgot to call OrderedList::Init before calling AddSortOrder"); if (SortOrders == NULL) return; Ptr = (ComparatorInfo *) SortOrders->GetHead(); while (Ptr != NULL) { if (Ptr->GetSortFn() == CompInfo.GetSortFn() && Ptr->GetSortName() == CompInfo.GetSortName()) return; // Already have this sort mode in the list Ptr = (ComparatorInfo *) SortOrders->GetNext(Ptr); } // Have failed to find this order in the list, so add it Ptr = new ComparatorInfo(CompInfo); if (Ptr != NULL) SortOrders->AddTail(Ptr); } #endif