Adium

Changeset 24087

Show
Ignore:
Timestamp:
06/28/2008 05:52:57 PM (5 months ago)
Author:
evands
Message:

Wow, ordering was a mess, especially as objects moved between groups.

Previously, an object was responsible for its order index, a value which followed it wherever it went. This goes horribly wrong when a contact changes containing objects (groups or metacontacts), as it may have the same order index as one of its siblings after moving. Same order index means rather arbitrary sorting behavior.

This sort of association would also break down if an object could be in multiple groups.

A containing object is now responsible for keeping track of objects within it. This should fix many obscure problems with sorting. We do a one-time upgrade from the old (possibly incorrect) order index preference as needed.

Fixes #10028

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/Frameworks/Adium Framework/Source/AIListGroup.h

    r20924 r24087  
    2525    BOOL                                expanded;                       //Exanded/Collapsed state of this object 
    2626        BOOL                            loadedExpanded; 
    27  
    28         float                           largestOrder; 
    29         float                           smallestOrder; 
    3027} 
    3128 
  • trunk/Frameworks/Adium Framework/Source/AIListGroup.m

    r24033 r24087  
    3333                expanded = YES; 
    3434 
    35                 largestOrder = 1.0; 
    36                 smallestOrder = 1.0; 
    37  
    3835                //Default invisible 
    3936                visibleCount = 0; 
     
    192189        return object; 
    193190} 
     191 
     192- (float)smallestOrder 
     193{ 
     194        return [super smallestOrder]; 
     195} 
     196 
     197- (float)largestOrder 
     198{ 
     199        return [super largestOrder]; 
     200} 
     201 
     202- (void)listObject:(AIListObject *)listObject didSetOrderIndex:(float)inOrderIndex 
     203{ 
     204        return [super listObject:listObject didSetOrderIndex:inOrderIndex]; 
     205} 
     206 
     207- (float)orderIndexForObject:(AIListObject *)listObject 
     208{ 
     209        return [super orderIndexForObject:listObject]; 
     210} 
     211 
    194212 
    195213/*! 
     
    345363} 
    346364 
    347 //Order index 
    348 - (void)listObject:(AIListObject *)listObject didSetOrderIndex:(float)inOrderIndex 
    349 { 
    350         AILogWithSignature(@"%@: %@ is now at %f", self, listObject, inOrderIndex); 
    351  
    352         if (inOrderIndex > largestOrder) { 
    353                 largestOrder = inOrderIndex; 
    354         } else if (inOrderIndex < smallestOrder) { 
    355                 smallestOrder = inOrderIndex; 
    356         } 
    357 } 
    358  
    359 - (float)smallestOrder 
    360 { 
    361         return smallestOrder; 
    362 } 
    363  
    364 - (float)largestOrder 
    365 { 
    366         return largestOrder; 
    367 } 
    368  
    369365#pragma mark Applescript 
    370366- (NSScriptObjectSpecifier *)objectSpecifier 
  • trunk/Frameworks/Adium Framework/Source/AIListObject.h

    r23556 r24087  
    4343- (AIListObject *)objectWithService:(AIService *)inService UID:(NSString *)inUID; 
    4444 
     45- (float)smallestOrder; 
     46- (float)largestOrder; 
     47- (void)listObject:(AIListObject *)listObject didSetOrderIndex:(float)inOrderIndex; 
     48- (float)orderIndexForObject:(AIListObject *)listObject; 
     49 
    4550//Should list each list contact only once (for groups, this is the same as the objectEnumerator) 
    4651- (NSArray *)listContacts; 
     
    5459- (BOOL)isExpanded; 
    5560- (BOOL)isExpandable; 
    56 - (float)smallestOrder; 
    57 - (float)largestOrder; 
    58 - (void)listObject:(AIListObject *)listObject didSetOrderIndex:(float)inOrderIndex; 
    5961- (unsigned)visibleCount; 
    6062@end 
     
    7779    id <AIContainingObject, AIListObject>       containingObject;               //The group/metacontact this object is in 
    7880        float                                                                   orderIndex;                             //Placement of this contact within a group 
     81         
     82        //For AIContainingObject-compliant subclasses 
     83        float                           largestOrder; 
     84        float                           smallestOrder; 
    7985} 
    8086 
     
    163169 
    164170@end 
     171 
     172/*! 
     173 * AIContainingObjectInheritableMethods methods are part of the AIContainingObject protocol 
     174 * but are implemented by AIListObject (which does not conform to the protocol) for the convenience 
     175 * of subclasses. 
     176 */ 
     177@interface AIListObject (AIContainingObjectInheritableMethods) 
     178- (float)smallestOrder; 
     179- (float)largestOrder; 
     180- (void)listObject:(AIListObject *)listObject didSetOrderIndex:(float)inOrderIndex; 
     181- (float)orderIndexForObject:(AIListObject *)listObject; 
     182@end 
  • trunk/Frameworks/Adium Framework/Source/AIListObject.m

    r24033 r24087  
    3434#define AlwaysVisible           @"AlwaysVisible" 
    3535 
    36 @interface AIListObject (PRIVATE) 
    37 - (void)determineOrderIndex; 
    38 @end 
    39  
    4036/*! 
    4137 * @class AIListObject 
     
    5854                visible = YES; 
    5955                orderIndex = 0; 
     56 
     57                largestOrder = 1.0; 
     58                smallestOrder = 1.0; 
    6059 
    6160                [[adium preferenceController] addObserver:self 
     
    239238{ 
    240239    if (containingObject != inGroup) { 
    241            [containingObject release]; 
    242            containingObject = [inGroup retain]; 
    243  
    244            //Always set the current orderIndex in the containingObject. 
    245            [(AIListObject<AIContainingObject> *)containingObject listObject:self  
    246                                                                                                            didSetOrderIndex:[self orderIndex]]; 
     240                [containingObject release]; 
     241                containingObject = [inGroup retain]; 
     242 
     243                //Reset then redetermine our order index         
     244                orderIndex = 0; 
    247245        } 
    248246} 
     
    253251- (float)orderIndex 
    254252{ 
    255         if (!orderIndex) [self determineOrderIndex]; 
     253        if (!orderIndex)  
     254                orderIndex = [[self containingObject] orderIndexForObject:self]; 
    256255         
    257256        return orderIndex; 
    258 } 
    259  
    260 - (void)determineOrderIndex 
    261 {        
    262         //Load the order index for this object (which will be appropriate for the last group it was in) 
    263         NSNumber        *orderIndexNumber = [self preferenceForKey:KEY_ORDER_INDEX 
    264                                                                                                          group:ObjectStatusCache  
    265                                                                          ignoreInheritedValues:YES]; 
    266         if (orderIndexNumber) { 
    267                 float storedOrderIndex; 
    268                  
    269                 storedOrderIndex = [orderIndexNumber floatValue]; 
    270                  
    271                 //Evan: I don't know how we got up to infinity.. perhaps pref corruption in a previous version? 
    272                 //In any case, check against it; if we stored it, reset to a reasonable number. 
    273                 if (storedOrderIndex < INFINITY) { 
    274                         orderIndex = storedOrderIndex; 
    275                 } 
    276         } 
    277  
    278         if (!orderIndex) { 
    279                 [self setOrderIndex:([[self containingObject] largestOrder] + 1)]; 
    280         } 
    281          
    282         if (!orderIndex) { 
    283                 AILog(@"WARNING: %@ could not determine its order index. Containing object: %@; preference yields %@",self,[self containingObject],orderIndexNumber); 
    284         } 
    285257} 
    286258 
     
    294266        orderIndex = inIndex; 
    295267        [[self containingObject] listObject:self didSetOrderIndex:orderIndex]; 
    296          
    297         //Save it 
    298         [self setPreference:[NSNumber numberWithFloat:orderIndex] forKey:KEY_ORDER_INDEX group:ObjectStatusCache]; 
    299          
    300         AILogWithSignature(@"%@: %f", self, inIndex); 
    301         //Sort the contained object 
    302 //      [[adium contactController] sortListObject:self]; 
    303268} 
    304269 
     
    750715} 
    751716 
     717#pragma mark Methods for AIContainingObject-compliant classes to inherit 
     718- (void)listObject:(AIListObject *)listObject didSetOrderIndex:(float)orderIndexForObject 
     719{ 
     720        NSDictionary            *dict = [self preferenceForKey:@"OrderIndexDictionary" 
     721                                                                                   group:ObjectStatusCache  
     722                                                   ignoreInheritedValues:YES]; 
     723        NSMutableDictionary *newDict = (dict ? [[dict mutableCopy] autorelease] : [NSMutableDictionary dictionary]); 
     724        NSNumber *orderIndexForObjectNumber = [NSNumber numberWithFloat:orderIndexForObject]; 
     725         
     726        //Prevent setting an order index which we already have 
     727        NSArray *existingKeys = [dict allKeysForObject:orderIndexForObjectNumber]; 
     728        if ([existingKeys count] && ![existingKeys isEqualToArray:[NSArray arrayWithObject:[listObject internalObjectID]]]) { 
     729                AILogWithSignature(@"*** Warning: %@ had order index %f, but %@ already had an object with that order index. Setting to %f instead.", 
     730                                                   listObject, orderIndexForObject, self, (largestOrder + 1)); 
     731                orderIndexForObject = ++largestOrder; 
     732                orderIndexForObjectNumber = [NSNumber numberWithFloat:orderIndexForObject]; 
     733        } 
     734 
     735        [newDict setObject:orderIndexForObjectNumber 
     736                                forKey:[listObject internalObjectID]]; 
     737         
     738        [self setPreference:newDict 
     739                                 forKey:@"OrderIndexDictionary" 
     740                                  group:ObjectStatusCache]; 
     741         
     742        //Keep track of our largest and smallest order indexes for quick access 
     743        if (orderIndexForObject > largestOrder) { 
     744                largestOrder = orderIndexForObject; 
     745        } else if (orderIndexForObject < smallestOrder) { 
     746                smallestOrder = orderIndexForObject; 
     747        } 
     748} 
     749 
     750//Order index 
     751- (float)orderIndexForObject:(AIListObject *)listObject 
     752{ 
     753        NSDictionary *dict = [self preferenceForKey:@"OrderIndexDictionary" 
     754                                                                                  group:ObjectStatusCache  
     755                                                  ignoreInheritedValues:YES]; 
     756        NSNumber *orderIndexForObjectNumber = [dict objectForKey:[listObject internalObjectID]]; 
     757        float orderIndexForObject = (orderIndexForObjectNumber ? [orderIndexForObjectNumber floatValue] : 0); 
     758         
     759        //Evan: I don't know how we got up to infinity.. perhaps pref corruption in a previous version? 
     760        //In any case, check against it; if we stored it, reset to a reasonable number. 
     761        //XXX is this still needed? 
     762        if  (!(orderIndexForObject < INFINITY)) orderIndexForObject = 0; 
     763 
     764        /* XXX Upgrade code from Adium 1.2 and below: Load the order index from the object itself, if it has one. 
     765         * Remove me for 1.4 
     766         */      
     767        if (!orderIndexForObject) { 
     768                orderIndexForObjectNumber = [listObject preferenceForKey:KEY_ORDER_INDEX 
     769                                                                                                                   group:ObjectStatusCache  
     770                                                                                   ignoreInheritedValues:YES]; 
     771                orderIndexForObject = (orderIndexForObjectNumber ? [orderIndexForObjectNumber floatValue] : 0); 
     772                 
     773                //Clear the old preference and save the new one 
     774                if (orderIndexForObjectNumber) { 
     775                        [listObject setPreference:nil 
     776                                                           forKey:KEY_ORDER_INDEX 
     777                                                                group:ObjectStatusCache]; 
     778                } 
     779                 
     780                if (orderIndexForObject && orderIndexForObject < INFINITY) { 
     781                        [listObject setOrderIndex:orderIndexForObject]; 
     782                } 
     783        } 
     784 
     785        if (orderIndexForObject) { 
     786                //Keep track of our largest and smallest order indexes for quick access 
     787                if (orderIndexForObject > largestOrder) { 
     788                        largestOrder = orderIndexForObject; 
     789                } else if (orderIndexForObject < smallestOrder) { 
     790                        smallestOrder = orderIndexForObject; 
     791                } 
     792                 
     793        } else { 
     794                //Assign it to our current largest order + 1 
     795                orderIndexForObject = ++largestOrder; 
     796                [listObject setOrderIndex:orderIndexForObject]; 
     797        } 
     798         
     799        return orderIndexForObject; 
     800} 
     801 
     802- (float)smallestOrder 
     803{ 
     804        return smallestOrder; 
     805} 
     806 
     807- (float)largestOrder 
     808{ 
     809        return largestOrder; 
     810} 
     811 
     812 
    752813#pragma mark Comparison 
    753814/* 
  • trunk/Frameworks/Adium Framework/Source/AIMetaContact.h

    r23766 r24087  
    3838    BOOL                                        expanded;                       //Exanded/Collapsed state of this object 
    3939        BOOL                                    isExpandable; 
    40  
    41         float                                   largestOrder; 
    42         float                                   smallestOrder; 
    4340} 
    4441 
  • trunk/Frameworks/Adium Framework/Source/AIMetaContact.m

    r24033 r24087  
    7070                delayContainedObjectSorting = NO; 
    7171                saveGroupingChanges = YES; 
    72                  
    73                 largestOrder = 1.0; 
    74                 smallestOrder = 1.0; 
    7572        } 
    7673        return self; 
     
    12281225} 
    12291226 
    1230 //Order index 
     1227- (float)smallestOrder 
     1228
     1229        return [super smallestOrder]; 
     1230
     1231 
     1232- (float)largestOrder 
     1233
     1234        return [super largestOrder]; 
     1235
     1236 
     1237- (float)orderIndexForObject:(AIListObject *)listObject 
     1238
     1239        return [super orderIndexForObject:listObject]; 
     1240
     1241 
    12311242- (void)listObject:(AIListObject *)listObject didSetOrderIndex:(float)inOrderIndex 
    12321243{ 
    1233         AILogWithSignature(@"%@: %@ is now at %f", self, listObject, inOrderIndex); 
    1234  
    1235         if (inOrderIndex > largestOrder) { 
    1236                 largestOrder = inOrderIndex; 
    1237         } else if (inOrderIndex < smallestOrder) { 
    1238                 smallestOrder = inOrderIndex; 
    1239         } 
     1244        [super listObject:listObject didSetOrderIndex:inOrderIndex]; 
    12401245 
    12411246        //We're no longer positive of our preferredContact, so clear the cache 
    12421247        containedObjectsNeedsSort = YES; 
    12431248 
    1244         [self clearContainedObjectInfoCache]; 
    1245 
    1246  
    1247 - (float)smallestOrder 
    1248 
    1249         return smallestOrder; 
    1250 
    1251  
    1252 - (float)largestOrder 
    1253 
    1254         return largestOrder; 
     1249        [self clearContainedObjectInfoCache];    
    12551250} 
    12561251