00001 // $Id: ordlist.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 // ordlist.cpp -- the OrderedList class 00100 00101 /* 00102 */ 00103 00104 00105 #include "camtypes.h" 00106 00107 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00108 //#include "galstr.h" // For string resources 00109 #include "ordlist.h" 00110 #include "progress.h" 00111 00112 00113 #if TRUE 00114 CC_IMPLEMENT_DYNAMIC(OrderedList, CCObject) 00115 CC_IMPLEMENT_MEMDUMP(ComparatorInfo, ListItem) 00116 CC_IMPLEMENT_MEMDUMP(SequenceItem, ListItem) 00117 CC_IMPLEMENT_MEMDUMP(OrderSequence, ListItem) 00118 00119 00120 #define new CAM_DEBUG_NEW 00121 00122 00123 /********************************************************************************************** 00124 00125 > ComparatorInfo::ComparatorInfo() 00126 00127 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00128 Created: 20/5/94 00129 Inputs: - 00130 Outputs: - 00131 Returns: - 00132 Purpose: Constructor for a ComparatorInfo object 00133 Notes: This constructor should not really be used; if you do use it, then make 00134 sure that you set at least the SortFn and ResourceID fields of the new 00135 object to legal values, else OrderedList clients may explode. 00136 SeeAlso: OrderedList 00137 00138 **********************************************************************************************/ 00139 00140 ComparatorInfo::ComparatorInfo() 00141 { 00142 SortFn = NULL; 00143 CanReverse = TRUE; 00144 } 00145 00146 00147 /********************************************************************************************** 00148 00149 > ComparatorInfo::ComparatorInfo(const ComparatorInfo &other) 00150 00151 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00152 Created: 20/5/94 00153 Inputs: - 00154 Outputs: - 00155 Returns: - 00156 Purpose: Copy constructor for a ComparatorInfo object 00157 Notes: This constructor should not really be used; if you do use it, then make 00158 sure that you set at least the SortFn and ResourceID fields of the new 00159 object to legal values, else OrderedList clients may explode. 00160 SeeAlso: OrderedList 00161 00162 **********************************************************************************************/ 00163 00164 ComparatorInfo::ComparatorInfo(const ComparatorInfo &other) 00165 { 00166 SortFn = other.SortFn; 00167 SortName = other.SortName; 00168 CanReverse = other.CanReverse; 00169 } 00170 00171 00172 00173 /********************************************************************************************** 00174 00175 > ComparatorInfo::ComparatorInfo(ListComparator Compare, UINT32 SortName, BOOL Reverse = TRUE) 00176 00177 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00178 Created: 20/5/94 00179 Inputs: Compare - The Comparator function used for the sort 00180 SortName - a resource ID for a string describing the sort 00181 (e.g. "Sort by Name", "Sort by Date", etc) 00182 Reverse - TRUE (the default) if the sort can be applied in reverse 00183 Outputs: - 00184 Returns: - 00185 Purpose: Constructor for a ComparatorInfo 00186 SeeAlso: OrderedList 00187 00188 **********************************************************************************************/ 00189 00190 ComparatorInfo::ComparatorInfo(ListComparator Compare, UINT32 SortNameID, BOOL Reverse) 00191 { 00192 SortFn = Compare; 00193 SortName.MakeMsg(SortNameID); 00194 CanReverse = Reverse; 00195 } 00196 00197 00198 00199 /********************************************************************************************** 00200 00201 > ComparatorInfo::ComparatorInfo(ListComparator Compare, const String_32 &Name, 00202 BOOL Reverse = TRUE) 00203 00204 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00205 Created: 20/5/94 00206 Inputs: Compare - The Comparator function used for the sort 00207 Name - a string_32 describing the sort 00208 (e.g. "Sort by Name", "Sort by Date", etc) 00209 Reverse - TRUE (the default) if the sort can be applied in reverse 00210 Outputs: - 00211 Returns: - 00212 Purpose: Constructor for a ComparatorInfo 00213 This allows you to set the name given a String_32, which means that 00214 'external' entities such as tools can provide sort modes. 00215 SeeAlso: OrderedList 00216 00217 **********************************************************************************************/ 00218 00219 ComparatorInfo::ComparatorInfo(ListComparator Compare, const String_32 &Name, BOOL Reverse) 00220 { 00221 SortFn = Compare; 00222 SortName = Name; 00223 CanReverse = Reverse; 00224 } 00225 00226 00227 00228 00229 00230 00231 00232 00233 00234 00235 00236 00237 00238 /********************************************************************************************** 00239 00240 > SequenceItem::SequenceItem() 00241 00242 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00243 Created: 18/5/94 00244 Inputs: - 00245 Outputs: - 00246 Returns: - 00247 Purpose: Constructor for a SequenceItem 00248 SeeAlso: OrderSequence; OrderedList 00249 00250 **********************************************************************************************/ 00251 00252 SequenceItem::SequenceItem() 00253 { 00254 MasterItem = NULL; 00255 } 00256 00257 00258 00259 00260 00261 00262 00263 00264 00265 00266 00267 00268 00269 00270 /********************************************************************************************** 00271 00272 > OrderSequence::OrderSequence() 00273 00274 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00275 Created: 18/5/94 00276 Inputs: - 00277 Outputs: - 00278 Returns: - 00279 Purpose: Constructor for a OrderSequence 00280 SeeAlso: SequenceItem; OrderedList 00281 00282 **********************************************************************************************/ 00283 00284 OrderSequence::OrderSequence() 00285 { 00286 Comparator = NULL; 00287 Cached = FALSE; 00288 Reversed = FALSE; 00289 UsageCount = 0; 00290 } 00291 00292 00293 00294 /********************************************************************************************** 00295 00296 > OrderSequence::OrderSequence(ListComparator Compare, BOOL Reverse) 00297 00298 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00299 Created: 18/5/94 00300 Inputs: Compare - A comparator function which determines the sort order 00301 Reverse - TRUE if you want the list sorted in reverse order 00302 Outputs: - 00303 Returns: - 00304 Purpose: Constructor for a OrderSequence 00305 SeeAlso: SequenceItem; OrderedList; keyword ListComparator 00306 00307 **********************************************************************************************/ 00308 00309 OrderSequence::OrderSequence(ListComparator Compare, BOOL Reverse) 00310 { 00311 Comparator = Compare; 00312 Cached = FALSE; 00313 Reversed = Reverse; 00314 UsageCount = 0; 00315 } 00316 00317 00318 00319 00320 00321 00322 00323 00324 00325 00326 00327 00328 00329 00330 00331 00332 00333 00334 /********************************************************************************************** 00335 00336 > OrderedList::OrderedList() 00337 00338 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00339 Created: 16/5/94 00340 Inputs: - 00341 Outputs: - 00342 Returns: - 00343 Purpose: OrderedList class constructor 00344 Notes: Remember to call OrderedList::Init() after creating 00345 00346 **********************************************************************************************/ 00347 00348 OrderedList::OrderedList() 00349 { 00350 SortOrders = NULL; // This is properly initialised in the Init() function 00351 00352 00353 for (INT32 i = 0; i < MaxSortKeys; i++) 00354 { 00355 SortMode[i].Info = NULL; 00356 SortMode[i].Reversed = FALSE; 00357 } 00358 } 00359 00360 00361 00362 /********************************************************************************************** 00363 00364 > OrderedList::~OrderedList() 00365 00366 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00367 Created: 16/5/94 00368 Inputs: - 00369 Outputs: - 00370 Returns: - 00371 Purpose: OrderedList class destructor 00372 Errors: None 00373 00374 **********************************************************************************************/ 00375 00376 OrderedList::~OrderedList() 00377 { 00378 // Clear all encapsulated master and sequence items 00379 DeleteAll(); 00380 00381 // Clear away our list of provided sort modes 00382 if (SortOrders != NULL) 00383 { 00384 SortOrders->DeleteAll(); 00385 delete SortOrders; 00386 } 00387 00388 if (!Sequences.IsEmpty()) 00389 { 00390 #ifdef _DEBUG 00391 /* 00392 // Warn Jason that someone's being rampant 00393 JCWTRACE( _T(" ** Warning: OrderedList deleted with Sequences non-empty! Cleaning up...\n")); 00394 00395 ListItem *Ptr = Sequences.GetHead(); 00396 while (Ptr != NULL) 00397 { 00398 // Check - if in use, somebody forgot to deselect an order. 00399 if ( ((OrderSequence *) Ptr)->UsageCount > 0 ) 00400 JCWTRACE( _T(" I was forced to delete an in-use sequence!\n")); 00401 Ptr = Sequences.GetNext(Ptr); 00402 } 00403 */ 00404 #endif 00405 00406 Sequences.DeleteAll(); 00407 } 00408 } 00409 00410 00411 00412 /********************************************************************************************** 00413 00414 > BOOL OrderedList::Init(void) 00415 00416 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00417 Created: 20/5/94 00418 Inputs: - 00419 Outputs: - 00420 Returns: FALSE if initialisation failed (lack of memory) 00421 00422 Purpose: This initialises the OrderedList. 00423 00424 Notes: This includes creation of a List of avaliable Sorts. 00425 00426 NO LONGER AVAILABLE: 00427 The OrderedList base class provides only one sort method - "Unsorted" 00428 Derived classes may override this function if they don't want 'Unsorted' 00429 to be an available method. 00430 If you want this, then all you need to do is uncomment this stuff and 00431 add a string resource baclk in for its name. 00432 00433 **********************************************************************************************/ 00434 00435 BOOL OrderedList::Init(void) 00436 { 00437 if (SortOrders == NULL) // Only init if we have not already done so 00438 { 00439 SortOrders = new List; 00440 if (SortOrders == NULL) 00441 return(FALSE); 00442 00443 // ComparatorInfo *SortOrder; 00444 // 00445 // SortOrder = new ComparatorInfo(Unsorted, _R(IDS_SORTBY_UNSORTED), FALSE); 00446 // if (SortOrder == NULL) 00447 // return(FALSE); 00448 // 00449 // SortOrders->AddTail(SortOrder); 00450 } 00451 00452 return(TRUE); 00453 } 00454 00455 00456 00457 /********************************************************************************************** 00458 00459 > BOOL OrderedList::AddItem(ListItem *TheItem) 00460 00461 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00462 Created: 18/5/94 00463 Inputs: ListItem - The item to add to the master list 00464 Outputs: - 00465 Returns: TRUE if it succeeds, FALSE if there isn't enough memory 00466 Purpose: Adds the given ListItem to the OrderedList. 00467 Notes This adds entries to all sequences in this OrderedList which refer 00468 to the new item in the master list. All lists will be resorted to 00469 place this item correctly the next time they are SelectOrder'd 00470 00471 **********************************************************************************************/ 00472 00473 BOOL OrderedList::AddItem(ListItem *TheItem) 00474 { 00475 MasterList.AddTail(TheItem); 00476 00477 OrderSequence *TheSeq = (OrderSequence *) Sequences.GetHead(); 00478 SequenceItem *NewItem; 00479 00480 while (TheSeq != NULL) 00481 { 00482 TheSeq->Cached = FALSE; // This sequence needs re-sorting 00483 00484 NewItem = new SequenceItem; 00485 if (NewItem == NULL) 00486 { 00487 ENSURE(FALSE, "OrderedList::AddItem failed to allocate new SequenceItem"); 00488 return(FALSE); 00489 } 00490 00491 NewItem->MasterItem = TheItem; // Set up the new SeqItem 00492 TheSeq->Sequence.AddTail(NewItem); // Add it to this Sequence 00493 00494 TheSeq = (OrderSequence *) Sequences.GetNext(TheSeq); // Move on to the next sequence 00495 } 00496 00497 return(TRUE); 00498 } 00499 00500 00501 /********************************************************************************************** 00502 00503 > ListItem *OrderedList::RemoveMasterItem(ListItem *TheItem) 00504 00505 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00506 Created: 18/5/94 00507 Inputs: TheItem - A pointer to the item which you want to remove 00508 Outputs: - 00509 Returns: The item that was removed (returns the pointer as passed in) 00510 Purpose: Delinks the given item from the OrderedList. TheItem is NOT 00511 deleted - it is up to you to do this when you're finished with it 00512 00513 Notes: (Removes the item from the Master List, and deletes all 00514 reference to it from all sequence lists. TheItem is NOT deleted) 00515 00516 **********************************************************************************************/ 00517 00518 ListItem *OrderedList::RemoveMasterItem(ListItem *TheItem) 00519 { 00520 MasterList.RemoveItem(TheItem); 00521 00522 OrderSequence *TheSeq = (OrderSequence *) Sequences.GetHead(); 00523 SequenceItem *SeqItem; 00524 00525 while (TheSeq != NULL) 00526 { 00527 SeqItem = (SequenceItem *) TheSeq->Sequence.GetHead(); 00528 while (SeqItem != NULL) 00529 { 00530 if (TheItem == SeqItem->GetItem()) 00531 break; 00532 00533 SeqItem = (SequenceItem *) TheSeq->Sequence.GetNext(SeqItem); 00534 } 00535 00536 00537 if (SeqItem == NULL) 00538 { 00539 ENSURE(FALSE, "OrderedList::RemoveItem- Expected SequenceItem was not found!"); 00540 return(TheItem); 00541 } 00542 00543 TheSeq->Sequence.RemoveItem(SeqItem); 00544 delete SeqItem; 00545 00546 TheSeq = (OrderSequence *) Sequences.GetNext(TheSeq); // Move on to the next sequence 00547 } 00548 00549 return(TheItem); 00550 } 00551 00552 00553 00554 /********************************************************************************************** 00555 00556 > void OrderedList::DeleteAll(void) 00557 00558 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00559 Created: 18/5/94 00560 Inputs: - 00561 Outputs: - 00562 Returns: - 00563 Purpose: Removes all items in the OrderedList, calling all their destructors 00564 Notes: This includes ALL items in all sequences AND THE MASTER LIST held 00565 by the OrderedList (i.e. deletes all enclosed objects) 00566 00567 **********************************************************************************************/ 00568 00569 void OrderedList::DeleteAll(void) 00570 { 00571 ListItem *Ptr = MasterList.GetHead(); 00572 ListItem *Next; 00573 00574 while (Ptr != NULL) 00575 { 00576 Next = MasterList.GetNext(Ptr); 00577 RemoveMasterItem(Ptr); 00578 delete Ptr; 00579 00580 Ptr = Next; 00581 } 00582 } 00583 00584 00585 00586 /********************************************************************************************** 00587 00588 > void OrderedList::InvalidateCaches(void) 00589 00590 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00591 Created: 18/5/94 00592 Inputs: - 00593 Outputs: - 00594 Returns: - 00595 Purpose: Informs the OrderedList that something you've done to the list or a 00596 ListItem in it could possibly change the sort order. 00597 00598 Notes: This causes all sequences to be resorted (reasonably quick if they're 00599 already almost in the correct order) the next time they are SelectOrder'd. 00600 Note that this is done automatically if you add items through the 00601 OrderedList interface, so you should only need to call this if you change 00602 data in a listitem which is (or potentially may be) used as a sort key. 00603 Note that OrderedList::InvalidateSequenceCache can be used on a single 00604 Sequence, but this should only be used if you can absolutely positively 00605 guarantee (beyond a shadow of a doubt and more certainly than a really 00606 certain certainty) that your change will only ever affect the sort order 00607 of that one sequence. 00608 00609 SeeAlso: OrderedList::InvalidateSequenceCache 00610 00611 **********************************************************************************************/ 00612 00613 void OrderedList::InvalidateCaches(void) 00614 { 00615 OrderSequence *TheSeq = (OrderSequence *) Sequences.GetHead(); 00616 00617 while (TheSeq != NULL) 00618 { 00619 TheSeq->Cached = FALSE; 00620 TheSeq = (OrderSequence *) Sequences.GetNext(TheSeq); 00621 } 00622 } 00623 00624 00625 00626 /********************************************************************************************** 00627 00628 > OrderSequence *OrderedList::FindSequence(ListComparator Compare, BOOL Reverse) 00629 00630 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00631 Created: 18/5/94 00632 Inputs: Compare - A ListComparator function defining the sort order 00633 Reverse - TRUE if you want a reverse-order sort 00634 Outputs: - 00635 Returns: - 00636 Purpose: Internal list search method. This searches the list of available 00637 sequences, and returns a pointer to the first one that matches 00638 the given comparator function, or NULL if there is no such sequence 00639 available. 00640 Scope: private 00641 00642 **********************************************************************************************/ 00643 00644 OrderSequence *OrderedList::FindSequence(ListComparator Compare, BOOL Reverse) 00645 { 00646 if (Compare == NULL) 00647 return(NULL); 00648 00649 OrderSequence *TheSeq = (OrderSequence *) Sequences.GetHead(); 00650 00651 while (TheSeq != NULL) 00652 { 00653 if (TheSeq->Comparator == Compare && TheSeq->Reversed == Reverse) 00654 return((OrderSequence *) TheSeq); 00655 00656 TheSeq = (OrderSequence *) Sequences.GetNext(TheSeq); // Move on to the next sequence 00657 } 00658 00659 return(NULL); 00660 } 00661 00662 00663 /********************************************************************************************** 00664 00665 > OrderSequence *OrderedList::CreateSequence(ListComparator Compare, BOOL Reverse) 00666 00667 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00668 Created: 18/5/94 00669 Inputs: Compare - A ListComparator function defining the sort order 00670 Reverse - TRUE if you want a reverse-order sort 00671 Outputs: - 00672 Returns: - 00673 Purpose: Internal list maintenance method. If, after calling 00674 OrderedList::FindSequence, you can't find a given sequence, then 00675 you can create a new instance of that sequence by calling this function. 00676 It is added to the end of the list, and no checks for duplicates are made 00677 (if a duplicate exists, the first one created will always be used) 00678 00679 **********************************************************************************************/ 00680 00681 OrderSequence *OrderedList::CreateSequence(ListComparator Compare, BOOL Reverse) 00682 { 00683 if (Compare == NULL) 00684 return(NULL); 00685 00686 OrderSequence *TheSeq; 00687 00688 TheSeq = new OrderSequence(Compare, Reverse); 00689 if (TheSeq == NULL) 00690 return(NULL); 00691 00692 Sequences.AddTail(TheSeq); 00693 00694 ListItem *Ptr = MasterList.GetHead(); 00695 SequenceItem *NewItem; 00696 00697 while (Ptr != NULL) 00698 { 00699 NewItem = new SequenceItem; 00700 if (NewItem == NULL) 00701 { 00702 ENSURE(FALSE, "OrderedList::CreateSequence failed to allocate new SequenceItem"); 00703 return(NULL); 00704 } 00705 00706 NewItem->MasterItem = Ptr; // Set up the new SeqItem 00707 TheSeq->Sequence.AddTail(NewItem); // Add it to this Sequence 00708 00709 Ptr = MasterList.GetNext(Ptr); 00710 } 00711 00712 return(TheSeq); 00713 } 00714 00715 00716 00717 /********************************************************************************************** 00718 00719 > BOOL OrderedList::SortSequence(OrderSequence *TheSeq) 00720 00721 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00722 Created: 18/5/94 00723 Inputs: TheSeq - The OrderSequence to be sorted 00724 Reverse - TRUE if you want it sorted into reverse order 00725 Outputs: - 00726 Returns: - 00727 Purpose: Internal list maintenance method. Sorts the given sequence into 00728 order using a sort and the user-supplied comparator function. 00729 This sounds slow, but (a) we're only intending to sort short lists, so 00730 should be fast enough, (b) It's not a completely silly implementation, and 00731 (c) the sort is only used when the sequence is created, and when it gets 00732 out of order. In the latter case, it usually means that the list is very 00733 close to correct sorted order, and only 1 or 2 passes will be needed to 00734 bring the list back to fully sorted order. 00735 (Probably if this sort turns out to be slow, it will be best to change 00736 to a faster sort for the original (creation) sort, and leave this in place 00737 for resorting the near-correct list) 00738 Just in case, SlowJob progress indicators are displayed while sorting 00739 00740 **********************************************************************************************/ 00741 00742 BOOL OrderedList::SortSequence(OrderSequence *TheSeq) 00743 { 00744 if (TheSeq == NULL || TheSeq->Comparator == NULL) // Error! 00745 return(FALSE); 00746 00747 if (TheSeq->Cached) // Well, I reckon it's already sorted. Hah 00748 return(TRUE); 00749 00750 SequenceItem *ItemA; 00751 SequenceItem *ItemB; 00752 SequenceItem *ItemC; 00753 00754 BOOL Sorted; 00755 INT32 CompareResult; 00756 00757 // Commented out 11/1/95 by Markn because Jason told me to. And it fixes one of my bugs. 00758 // Sometimes this gets called when there's already a slow job going (e.g. import with layers with layer gal open). 00759 // 00760 // BeginSlowJob(-1); // Show hourglass, with delay, no percentage 00761 00762 do 00763 { 00764 Sorted = TRUE; // Assume in sorted order until we have to move an item 00765 ItemA = (SequenceItem *) TheSeq->Sequence.GetHead(); 00766 00767 while (ItemA != NULL) 00768 { 00769 ContinueSlowJob(); 00770 00771 ItemB = (SequenceItem *) TheSeq->Sequence.GetNext(ItemA); 00772 if (ItemB == NULL) // At end of list, so have finished this pass 00773 break; 00774 00775 if (TheSeq->Reversed) 00776 CompareResult = TheSeq->Comparator(this, ItemB->GetItem(), ItemA->GetItem()); 00777 else 00778 CompareResult = TheSeq->Comparator(this, ItemA->GetItem(), ItemB->GetItem()); 00779 00780 if (CompareResult > 0) 00781 { 00782 Sorted = FALSE; // Have to move an item - can't be in order yet 00783 00784 // Delink ItemA from the list - it has to move up 00785 TheSeq->Sequence.RemoveItem(ItemA); 00786 00787 // Search for proper position for A... 00788 ItemC = (SequenceItem *) TheSeq->Sequence.GetNext(ItemB); 00789 while (ItemC != NULL) 00790 { 00791 if (TheSeq->Reversed) 00792 CompareResult = TheSeq->Comparator(this, ItemC->GetItem(), ItemA->GetItem()); 00793 else 00794 CompareResult = TheSeq->Comparator(this, ItemA->GetItem(), ItemC->GetItem()); 00795 00796 if (CompareResult <= 0) // Have found place to drop ItemA... 00797 break; 00798 00799 ItemC = (SequenceItem *) TheSeq->Sequence.GetNext(ItemC); 00800 } 00801 00802 if (ItemC == NULL) 00803 TheSeq->Sequence.AddTail(ItemA); // Belongs at end of list 00804 else 00805 TheSeq->Sequence.InsertBefore(ItemC, ItemA); // Belongs just before ItemC 00806 } 00807 00808 ItemA = ItemB; // Loop, from the next unsorted item 00809 } 00810 } while (!Sorted); 00811 00812 // EndSlowJob(); BeginSlowJob() statement see above 00813 00814 TheSeq->Cached = TRUE; 00815 return(TRUE); 00816 } 00817 00818 00819 00820 /********************************************************************************************** 00821 00822 > List *OrderedList::SelectOrder(ListComparator Compare, BOOL Reversed = FALSE) 00823 00824 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00825 Created: 18/5/94 00826 Inputs: Compare - a list comparator function which determines how the list 00827 will be sorted. 00828 Reversed - TRUE if you wish the list to be sorted using the comparator into 00829 reverse order. 00830 Outputs: - 00831 Returns: A pointer to a List of SequenceItems, sorted as desired, or 00832 NULL if it failed. 00833 00834 Purpose: Selects a given order for use. 00835 00836 Once selected, you can traverse the OrderedList much like an ordinary 00837 list (see the SeeAlso comments) only you'll find that the items are 00838 returned by GetNext/Prev in an order dicatated by the ListComparator 00839 function that you supplied on selection. 00840 00841 Notes: Selecting has the following effects: 00842 * Increments a UsageCount (which is decremented by DeselectOrder) 00843 - While selected, a sequence cannot be DestroyOrder'd 00844 * Creates (if necessary) a new sequence within the OrderedList 00845 * Sorts (if necessary) the list using the given comparator function 00846 00847 Sorting occurs when the sequence is first created, and thereafter when 00848 SelectOrder() is called AND it is determined that the list order may be 00849 incorrect (when item(s) have been added, or InvalidataeCache menthods 00850 have been invoked) 00851 00852 If an 'Unsorted' order is requested, this actually returns the Master 00853 List; this can be traversed in exactly the same manner as an OrderedList 00854 (as normal ListItems also have a GetItem() method). 00855 00856 Passing 'Compare' == NULL will ignore the 'Reversed' parameter and 00857 simply return the master list. 00858 00859 SeeAlso: OrderedList::InvalidateCaches; OrderedList::DeselectOrder; 00860 OrderedList::DestroyOrder; Keyword ListComparator 00861 00862 **********************************************************************************************/ 00863 00864 List *OrderedList::SelectOrder(ListComparator Compare, BOOL Reverse) 00865 { 00866 if (Compare == NULL || Compare == Unsorted) 00867 return(&MasterList); 00868 00869 OrderSequence *TheSeq = FindSequence(Compare, Reverse); // Find existing Seq? 00870 00871 if (TheSeq == NULL) // No - create new one 00872 TheSeq = CreateSequence(Compare, Reverse); 00873 00874 if (TheSeq == NULL) // Failed - argh! 00875 return(NULL); 00876 00877 if (!TheSeq->Cached) // Needs sorting? 00878 SortSequence(TheSeq); 00879 00880 TheSeq->UsageCount++; // Increment the usage count 00881 00882 return(&TheSeq->Sequence); 00883 } 00884 00885 00886 /********************************************************************************************** 00887 00888 > void OrderedList::ReSortOrder(ListComparator Compare, BOOL Reversed = FALSE) 00889 00890 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00891 Created: 18/5/94 00892 Inputs: Compare - a list comparator function which determines how the list 00893 will be sorted. 00894 Reversed - TRUE if you wish the list to be sorted using the comparator into 00895 reverse order. 00896 Outputs: - 00897 Returns: - 00898 Purpose: Immediately (re-)sorts the given order. If no such order exists, no 00899 action is taken (a new order sequence will NOT be created, as this will 00900 happen anyway if you subsequently try to Select it) 00901 Normally, if you add an item to the order sequence, it is not sorted into its 00902 correct position until the next time the order is selected; The item will be 00903 added at the tail of the list. This allows you to continue scanning the list 00904 knowing that it has not shifted about under you. However, if adding items to 00905 the list you may want to immediately force a resort to ensure it is in order 00906 (if you are not going to SelectOrder on the list before using it again) 00907 00908 Passing 'Compare' == NULL will ignore the 'Reversed' parameter and 00909 simply do nothing (as this asks you to resort the master list). 00910 00911 00912 SeeAlso: OrderedList::InvalidateCaches; OrderedList::SelectOrder; 00913 Keyword ListComparator 00914 00915 **********************************************************************************************/ 00916 00917 void OrderedList::ReSortOrder(ListComparator Compare, BOOL Reverse) 00918 { 00919 OrderSequence *TheSeq = FindSequence(Compare, Reverse); // Find existing Seq? 00920 00921 if (TheSeq == NULL) // No such seq - exit 00922 return; 00923 00924 SortSequence(TheSeq); // Force a sort 00925 } 00926 00927 00928 00929 /********************************************************************************************** 00930 00931 > void OrderedList::DeselectOrder(ListComparator Compare, BOOL Reversed = FALSE) 00932 00933 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00934 Created: 18/5/94 00935 Inputs: Compare - The list comparator function which defined the sort order 00936 Reversed - TRUE if you wish to deselect the Reverse-sorted order 00937 Outputs: - 00938 Returns: - 00939 Purpose: This indicates to the OrderedList that you have finished using the given 00940 sequence (list sort-order). This unlocks the List so that the sequence may 00941 be deleted using the DestroyOrder function. 00942 Notes: Passing 'Compare' == NULL will ignore the 'Reversed' parameter and 00943 simply 'deselect' the master list (this in fact returns, doing nothing). 00944 00945 SeeAlso: OrderedList; OrderedList::SelectOrder; OrderedList::DestroyOrder 00946 Errors: This ENSUREs that the sequence exists (has been Selected and not yet Destroy'd) 00947 and that the UsageCount is legal (that Deselect has not been called more often 00948 than Select) 00949 00950 **********************************************************************************************/ 00951 00952 void OrderedList::DeselectOrder(ListComparator Compare, BOOL Reversed) 00953 { 00954 if (Compare == NULL || Compare == Unsorted) 00955 return; 00956 00957 OrderSequence *TheSeq = FindSequence(Compare, Reversed); // Find existing Seq? 00958 00959 ENSURE(TheSeq != NULL, "OrderedList::DeselectOrder called for nonexistent sequence!"); 00960 ENSURE(TheSeq->UsageCount > 0, "OrderedList::DeselectOrder called more often than SelectOrder!"); 00961 00962 TheSeq->UsageCount--; // Decrement the usage count 00963 } 00964 00965 00966 00967 /********************************************************************************************** 00968 00969 > void OrderedList::DestroyOrder(ListComparator Compare, BOOL Reversed = FALSE) 00970 00971 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00972 Created: 18/5/94 00973 Inputs: Comparator - The comparator function which determines the sort order 00974 Reversed - TRUE if you wish to destroy the reverse-sorted order. 00975 Outputs: - 00976 Returns: - 00977 Purpose: Destroys an order sequence. This is not strictly necessary, but allows 00978 you to make the OrderedList release all memory used by the sequence if 00979 you know that you no longer need to acces that sort order. (If you may 00980 want to look at the list again, it is probably more efficient to never 00981 call Destroy, so that the cached sort order is available to you in the 00982 future, without having to re-sort the items) 00983 00984 Notes: The sequence will ONLY be destroyed if its usage count is zero (if the 00985 order has been deselected exactly the same number of times it has been 00986 selected. This means you can call Destroy after every use of the order 00987 if you wish, and it will be deleted only if nobody else is sharing it. 00988 00989 Passing 'Compare' == NULL will ignore the 'Reversed' parameter and 00990 simply do nothing (You can't destroy the master list). 00991 00992 SeeAlso: OrderedList::SelectOrder; OrderedList::DeselectOrder 00993 Errors: In the debug build, this ENSURES that you don't try to destroy an order 00994 which does not exist, and that the order is not in use (selected) when you 00995 try to destroy it. In the release build, this will just delete the sequence 00996 if it can be found 00997 00998 **********************************************************************************************/ 00999 01000 void OrderedList::DestroyOrder(ListComparator Compare, BOOL Reversed) 01001 { 01002 if (Compare == NULL || Compare == Unsorted) 01003 return; 01004 01005 OrderSequence *TheSeq = FindSequence(Compare, Reversed); // Find existing Seq? 01006 01007 ENSURE(TheSeq != NULL, "OrderedList::DestroyOrder called for nonexistent sequence!"); 01008 01009 if (TheSeq != NULL && TheSeq->UsageCount == 0) 01010 { 01011 Sequences.RemoveItem(TheSeq); 01012 TheSeq->Sequence.DeleteAll(); 01013 delete TheSeq; 01014 } 01015 } 01016 01017 01018 01019 01020 /********************************************************************************************** 01021 01022 > INT32 OrderedList::Unsorted(OrderedList *ParentList, ListItem *Item1, ListItem *Item2) 01023 01024 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01025 Created: 18/5/94 01026 Inputs: ParentList - the OrderedList in which these items are linked 01027 Item1, Item2 - the two items to be compared 01028 Outputs: - 01029 Returns: A negative value if Item1 is considered "less than" Item2 01030 01031 A positive value if Item1 is considered "greater than" Item2 01032 01033 Zero if Item1 is considered "equal to" Item2 01034 01035 Purpose: "Unsorted" List sort ComparatorFunction, and an example of writing 01036 ListComparators. 01037 01038 Determines if two items in an OrderedList need to be swapped during 01039 a sort operation. The function returns a value indicating if the 01040 items were considered equal, or if one item was "greater than" or 01041 "less than" the other. 01042 01043 Notes: This particular function always returns zero, so that it imposes no order 01044 at all upon the list, thus giving an "Unsorted" List order. 01045 01046 Normally, we would code the function to return the 3 possible results 01047 e.g. If we wish to compare two integers to sort them into ascending 01048 order, we should return(Item1->IntegerValue - Item2->IntegerValue) 01049 NOTE, however, that care must be taken to always return an 'INT32' 01050 compatible value (i.e. if comparing INT32s, you should code to 01051 return -1, 0, or +1, using explicit < and == comparisons) 01052 01053 In your own ListComparator functions, you should attempt to check the 01054 runtime type of the provided ListItems to ensure they are of an 01055 appropriate type to be sorted using your function. 01056 01057 SeeAlso: ListComparator 01058 01059 **********************************************************************************************/ 01060 01061 INT32 OrderedList::Unsorted(OrderedList *ParentList, ListItem *Item1, ListItem *Item2) 01062 { 01063 return(0); 01064 } 01065 01066 01067 01068 /********************************************************************************************** 01069 01070 > List *OrderedList::GetSortOrders(void) 01071 01072 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01073 Created: 23/5/94 01074 Inputs: - 01075 Outputs: - 01076 Returns: A pointer to a list of ComparatorInfo objects enumerating the 01077 sort orders available from this OrderedList object. 01078 Purpose: Find a list of available sorting orders. 01079 SeeAlso: ComparatorInfo; ListComparator 01080 01081 **********************************************************************************************/ 01082 01083 List *OrderedList::GetSortOrders(void) 01084 { 01085 return(SortOrders); 01086 } 01087 01088 01089 01090 /********************************************************************************************** 01091 01092 > void OrderedList::AddSortOrder(const ComparatorInfo &CompInfo) 01093 01094 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01095 Created: 25/5/94 01096 Inputs: CompInfo - a ComparatorInfo object describing the new sort method. 01097 Note that this will be duplicated and added into the list if such 01098 a sort is not already in the list. 01099 Outputs: - 01100 Returns: - 01101 Purpose: Add a sort order to the list of those available from this 01102 OrderedList object. 01103 SeeAlso: ComparatorInfo; ListComparator 01104 01105 **********************************************************************************************/ 01106 01107 void OrderedList::AddSortOrder(const ComparatorInfo &CompInfo) 01108 { 01109 ComparatorInfo *Ptr; 01110 01111 ENSURE(SortOrders != NULL, 01112 "Someone forgot to call OrderedList::Init before calling AddSortOrder"); 01113 01114 if (SortOrders == NULL) 01115 return; 01116 01117 Ptr = (ComparatorInfo *) SortOrders->GetHead(); 01118 while (Ptr != NULL) 01119 { 01120 if (Ptr->GetSortFn() == CompInfo.GetSortFn() && 01121 Ptr->GetSortName() == CompInfo.GetSortName()) 01122 return; // Already have this sort mode in the list 01123 01124 Ptr = (ComparatorInfo *) SortOrders->GetNext(Ptr); 01125 } 01126 01127 // Have failed to find this order in the list, so add it 01128 Ptr = new ComparatorInfo(CompInfo); 01129 if (Ptr != NULL) 01130 SortOrders->AddTail(Ptr); 01131 } 01132 01133 01134 #endif