adium 5453:3db86d54b08b: Finally fix #14468. Group chat particip...

commits at adium.im commits at adium.im
Wed May 1 23:12:30 UTC 2013


details:	http://hg.adium.im/adium/rev/3db86d54b08b
revision:	5453:3db86d54b08b
branch:		adium-1.6
author:		Thijs Alkemade <me at thijsalkema.de>
date:		Thu May 02 01:11:44 2013 +0200

Finally fix #14468. Group chat participants are now tracked by nick, and lookup is nick->contact and nick->flags.

This includes the following changes:

AIContentObjects now contain the sourceNick, in addition to the source.
AIProxyObjects now alos keep the nick they apply to. This is pretty hackish, but it works.

diffs (truncated from 1391 to 1000 lines):

diff -r 1bfcbf06c354 -r 3db86d54b08b Frameworks/Adium Framework/Source/AIAbstractListController.m
--- a/Frameworks/Adium Framework/Source/AIAbstractListController.m	Sun Apr 28 15:19:21 2013 -0400
+++ b/Frameworks/Adium Framework/Source/AIAbstractListController.m	Thu May 02 01:11:44 2013 +0200
@@ -610,11 +610,20 @@
 		id<AIContainingObject> listObject = (id<AIContainingObject>)(item.listObject);
 		proxyListObject = [AIProxyListObject proxyListObjectForListObject:[listObject visibleObjectAtIndex:idx]
 															 inListObject:listObject];
-
-	} else if (hideRoot)
-		proxyListObject = [AIProxyListObject proxyListObjectForListObject:[contactList visibleObjectAtIndex:idx]
-															 inListObject:contactList];
-	else
+		
+	} else if (hideRoot) {
+		if ([contactList isKindOfClass:[AIGroupChat class]]) {
+			NSString *nick = [(AIGroupChat *)contactList visibleObjectAtIndex:idx];
+			AIListObject *listObject = [(AIGroupChat *)contactList contactForNick:nick];
+			
+			proxyListObject = [AIProxyListObject proxyListObjectForListObject:listObject
+																 inListObject:contactList
+																	 withNick:nick];
+		} else {
+			proxyListObject = [AIProxyListObject proxyListObjectForListObject:[contactList visibleObjectAtIndex:idx]
+																 inListObject:contactList];
+		}
+	} else
 		proxyListObject = [AIProxyListObject proxyListObjectForListObject:contactList
 															 inListObject:nil];
 	
diff -r 1bfcbf06c354 -r 3db86d54b08b Frameworks/Adium Framework/Source/AIChat.m
--- a/Frameworks/Adium Framework/Source/AIChat.m	Sun Apr 28 15:19:21 2013 -0400
+++ b/Frameworks/Adium Framework/Source/AIChat.m	Thu May 02 01:11:44 2013 +0200
@@ -641,6 +641,7 @@
 		AIContentMessage	*messageContent;
 		messageContent = [AIContentMessage messageInChat:self
 											  withSource:self.account
+											  sourceNick:nil
 											 destination:self.listObject
 													date:nil
 												 message:attributedMessage
diff -r 1bfcbf06c354 -r 3db86d54b08b Frameworks/Adium Framework/Source/AIContentMessage.h
--- a/Frameworks/Adium Framework/Source/AIContentMessage.h	Sun Apr 28 15:19:21 2013 -0400
+++ b/Frameworks/Adium Framework/Source/AIContentMessage.h	Thu May 02 01:11:44 2013 +0200
@@ -45,7 +45,15 @@
 		 withSource:(id)inSource
 		destination:(id)inDest
 			   date:(NSDate *)inDate
-			message:(NSAttributedString *)inMessage 
+			message:(NSAttributedString *)inMessage
+		  autoreply:(BOOL)inAutoReply;
+
++ (id)messageInChat:(AIChat *)inChat
+		 withSource:(id)inSource
+		 sourceNick:(NSString *)inSourceNick
+		destination:(id)inDest
+			   date:(NSDate *)inDate
+			message:(NSAttributedString *)inMessage
 		  autoreply:(BOOL)inAutoreply;
 
 /*!	@brief	Create an AIContentMessage.
@@ -56,6 +64,7 @@
  */
 - (id)initWithChat:(AIChat *)inChat
 			source:(id)inSource
+		sourceNick:(NSString *)inSourceNick
 	   destination:(id)inDest
 			  date:(NSDate *)inDate
 		   message:(NSAttributedString *)inMessage
diff -r 1bfcbf06c354 -r 3db86d54b08b Frameworks/Adium Framework/Source/AIContentMessage.m
--- a/Frameworks/Adium Framework/Source/AIContentMessage.m	Sun Apr 28 15:19:21 2013 -0400
+++ b/Frameworks/Adium Framework/Source/AIContentMessage.m	Thu May 02 01:11:44 2013 +0200
@@ -23,7 +23,6 @@
 
 @implementation AIContentMessage
 
-//Create a content message
 + (id)messageInChat:(AIChat *)inChat
 		 withSource:(id)inSource
 		destination:(id)inDest
@@ -31,8 +30,27 @@
 			message:(NSAttributedString *)inMessage
 		  autoreply:(BOOL)inAutoReply
 {
+	return [[[self alloc] initWithChat:inChat
+								source:inSource
+							sourceNick:nil
+						   destination:inDest
+								  date:inDate
+							   message:inMessage
+							 autoreply:inAutoReply] autorelease];
+}
+
+//Create a content message
++ (id)messageInChat:(AIChat *)inChat
+		 withSource:(id)inSource
+		 sourceNick:(NSString *)inSourceNick
+		destination:(id)inDest
+			   date:(NSDate *)inDate
+			message:(NSAttributedString *)inMessage
+		  autoreply:(BOOL)inAutoReply
+{
     return [[[self alloc] initWithChat:inChat
 								source:inSource
+							sourceNick:inSourceNick
 						   destination:inDest
 								  date:inDate
 							   message:inMessage
@@ -48,12 +66,13 @@
 //Init
 - (id)initWithChat:(AIChat *)inChat
 			source:(id)inSource
+		sourceNick:(NSString *)inSourceNick
 	   destination:(id)inDest
 			  date:(NSDate *)inDate
 		   message:(NSAttributedString *)inMessage
 		 autoreply:(BOOL)inAutoReply
 {
-	if ((self = [super initWithChat:inChat source:inSource destination:inDest date:inDate message:inMessage])) {
+	if ((self = [super initWithChat:inChat source:inSource sourceNick:inSourceNick destination:inDest date:inDate message:inMessage])) {
 		isAutoreply = inAutoReply;
 		encodedMessage = nil;
 		encodedMessageAccountData = nil;
@@ -78,7 +97,7 @@
 	[classes addObject:@"message"];
 	if(isAutoreply) [classes addObject:@"autoreply"];
 	if(self.chat.isGroupChat) {
-		AIGroupChatFlags flags = [(AIGroupChat *)self.chat flagsForContact:(AIListContact *)self.source];
+		AIGroupChatFlags flags = [(AIGroupChat *)self.chat flagsForNick:self.sourceNick];
 		if (flags & AIGroupChatOp)
 			[classes addObject:@"op"];
 		if (flags & AIGroupChatHalfOp)
@@ -95,7 +114,7 @@
 {
     if (!self.chat.isGroupChat) return @"";
     
-	AIGroupChatFlags flags = [(AIGroupChat *)self.chat flagsForContact:(AIListContact *)self.source];
+	AIGroupChatFlags flags = [(AIGroupChat *)self.chat flagsForNick:self.sourceNick];
 	
 	if ((flags & AIGroupChatFounder) == AIGroupChatFounder) {
 		return @"~";
diff -r 1bfcbf06c354 -r 3db86d54b08b Frameworks/Adium Framework/Source/AIContentObject.h
--- a/Frameworks/Adium Framework/Source/AIContentObject.h	Sun Apr 28 15:19:21 2013 -0400
+++ b/Frameworks/Adium Framework/Source/AIContentObject.h	Thu May 02 01:11:44 2013 +0200
@@ -38,6 +38,7 @@
     AIChat				*chat;
     AIListObject		*source;
     AIListObject		*destination;
+	NSString			*sourceNick;
     BOOL				outgoing;
     
 	NSAttributedString	*message;
@@ -86,6 +87,13 @@
 			  date:(NSDate*)inDate
 		   message:(NSAttributedString *)inMessage;
 
+- (id)initWithChat:(AIChat *)inChat
+			source:(AIListObject *)inSource
+		sourceNick:(NSString *)inSourceNick
+	   destination:(AIListObject *)inDest
+			  date:(NSDate*)inDate
+		   message:(NSAttributedString *)inMessage;
+
 /*!	@brief	The type of content.
  *
  *	@par	There is at least one type defined for every concrete subclass of \c AIContentObject.
@@ -254,4 +262,6 @@
  */
 @property (nonatomic) BOOL postProcessContent;
 
+ at property (nonatomic, retain) NSString *sourceNick;
+
 @end
diff -r 1bfcbf06c354 -r 3db86d54b08b Frameworks/Adium Framework/Source/AIContentObject.m
--- a/Frameworks/Adium Framework/Source/AIContentObject.m	Sun Apr 28 15:19:21 2013 -0400
+++ b/Frameworks/Adium Framework/Source/AIContentObject.m	Thu May 02 01:11:44 2013 +0200
@@ -24,7 +24,7 @@
 @implementation AIContentObject
 
 @synthesize source, destination, date, isOutgoing = outgoing, chat, message, userInfo;
- at synthesize filterContent, trackContent, displayContent, displayContentImmediately, sendContent, postProcessContent;
+ at synthesize filterContent, trackContent, displayContent, displayContentImmediately, sendContent, postProcessContent, sourceNick;
 
 - (id)initWithChat:(AIChat *)inChat
 			source:(AIListObject *)inSource
@@ -33,12 +33,23 @@
 {
 	return [self initWithChat:inChat source:inSource destination:inDest date:inDate message:nil];
 }
+
 - (id)initWithChat:(AIChat *)inChat
 			source:(AIListObject *)inSource
 	   destination:(AIListObject *)inDest
 			  date:(NSDate*)inDate
 		   message:(NSAttributedString *)inMessage
 {
+	return [self initWithChat:inChat source:inSource sourceNick:nil destination:inDest date:inDate message:inMessage];
+}
+
+- (id)initWithChat:(AIChat *)inChat
+			source:(AIListObject *)inSource
+		sourceNick:(NSString *)inSourceNick
+	   destination:(AIListObject *)inDest
+			  date:(NSDate*)inDate
+		   message:(NSAttributedString *)inMessage
+{
     if ((self = [super init]))
 	{
 		//Default Behavior
@@ -51,6 +62,7 @@
 	
 		//Store source, dest, chat, ...
 		source = [inSource retain];
+		sourceNick = [inSourceNick retain];
 		destination = [inDest retain];
 		message = [inMessage retain];
 		date = [(inDate ? inDate : [NSDate date]) retain];
@@ -66,6 +78,7 @@
 - (void)dealloc
 {
     [source release]; source = nil;
+	[sourceNick release]; sourceNick = nil;
     [destination release]; destination = nil;
 	[date release]; date = nil;
 	[message release]; message = nil;
diff -r 1bfcbf06c354 -r 3db86d54b08b Frameworks/Adium Framework/Source/AIContentTopic.h
--- a/Frameworks/Adium Framework/Source/AIContentTopic.h	Sun Apr 28 15:19:21 2013 -0400
+++ b/Frameworks/Adium Framework/Source/AIContentTopic.h	Thu May 02 01:11:44 2013 +0200
@@ -27,8 +27,9 @@
 
 + (id)topicInChat:(AIChat *)inChat
 	   withSource:(id)inSource
+	   sourceNick:(NSString *)inSourceNick
 	  destination:(id)inDest
-			 date:(NSDate *)inDate 
+			 date:(NSDate *)inDate
 		  message:(NSAttributedString *)inMessage;
 
 @property (nonatomic) BOOL actuallyBlank;
diff -r 1bfcbf06c354 -r 3db86d54b08b Frameworks/Adium Framework/Source/AIContentTopic.m
--- a/Frameworks/Adium Framework/Source/AIContentTopic.m	Sun Apr 28 15:19:21 2013 -0400
+++ b/Frameworks/Adium Framework/Source/AIContentTopic.m	Thu May 02 01:11:44 2013 +0200
@@ -20,12 +20,14 @@
 @implementation AIContentTopic
 + (id)topicInChat:(AIChat *)inChat
 	   withSource:(id)inSource
+	   sourceNick:(NSString *)inSourceNick
 	  destination:(id)inDest
 			 date:(NSDate *)inDate 
 		  message:(NSAttributedString *)inMessage
 {
 	return [super messageInChat:inChat
 					 withSource:inSource
+					 sourceNick:inSourceNick
 					destination:inDest
 						   date:inDate
 						message:inMessage
diff -r 1bfcbf06c354 -r 3db86d54b08b Frameworks/Adium Framework/Source/AIGroupChat.h
--- a/Frameworks/Adium Framework/Source/AIGroupChat.h	Sun Apr 28 15:19:21 2013 -0400
+++ b/Frameworks/Adium Framework/Source/AIGroupChat.h	Thu May 02 01:11:44 2013 +0200
@@ -20,9 +20,9 @@
 	NSString			*topic;
     AIListContact		*topicSetter;
 	
-	NSMutableDictionary	*participatingContactsFlags;
-	NSMutableDictionary	*participatingContactsAliases;
-	NSMutableArray		*participatingContacts;
+	NSMutableDictionary	*participatingNicksFlags;
+	NSMutableDictionary	*participatingNicksContacts;
+	NSMutableArray		*participatingNicks;
 	
 	BOOL				showJoinLeave;
 	BOOL				expanded;
@@ -34,26 +34,35 @@
 
 @property (readonly, nonatomic) BOOL supportsTopic;
 
-- (void)updateTopic:(NSString *)inTopic withSource:(AIListContact *)contact;
+- (void)updateTopic:(NSString *)inTopic withSource:(NSString *)contact;
 - (void)setTopic:(NSString *)inTopic;
 
 @property (readwrite, copy, nonatomic) NSDate *lastMessageDate;
 
 // Group chat participants.
-- (NSString *)displayNameForContact:(AIListObject *)contact;
-- (AIGroupChatFlags)flagsForContact:(AIListObject *)contact;
-- (NSString *)aliasForContact:(AIListObject *)contact;
-- (void)setFlags:(AIGroupChatFlags)flags forContact:(AIListObject *)contact;
-- (void)setAlias:(NSString *)alias forContact:(AIListObject *)contact;
-- (void)removeSavedValuesForContactUID:(NSString *)contactUID;
+//- (NSString *)displayNameForContact:(AIListObject *)contact;
+//- (AIGroupChatFlags)flagsForContact:(AIListObject *)contact;
+//- (NSString *)aliasForContact:(AIListObject *)contact;
+//- (void)setFlags:(AIGroupChatFlags)flags forContact:(AIListObject *)contact;
+//- (void)setAlias:(NSString *)alias forContact:(AIListObject *)contact;
 
-- (void)addParticipatingListObject:(AIListContact *)inObject notify:(BOOL)notify;
-- (void)addParticipatingListObjects:(NSArray *)inObjects notify:(BOOL)notify;
+- (AIListContact *)contactForNick:(NSString *)nick;
+- (AIGroupChatFlags)flagsForNick:(NSString *)nick;
+- (void)setFlags:(AIGroupChatFlags)flags forNick:(NSString *)nick;
+- (void)setContact:(AIListContact *)contact forNick:(NSString *)nick;
+- (void)changeNick:(NSString *)from to:(NSString *)to;
+- (void)removeSavedValuesForNick:(NSString *)nick;
+- (NSArray *)nicksForContact:(AIListContact *)contact;
+
+- (void)addParticipatingNick:(NSString *)inObject notify:(BOOL)notify;
+- (void)addParticipatingNicks:(NSArray *)inObjects notify:(BOOL)notify;
 - (void)removeAllParticipatingContactsSilently;
-- (void)removeObject:(AIListObject *)inObject;
+- (void)removeObject:(NSString *)inObject;
 
 - (BOOL)inviteListContact:(AIListContact *)inObject withMessage:(NSString *)inviteMessage;
 
 - (void)resortParticipants;
 
+- (NSString *)visibleObjectAtIndex:(NSUInteger)idx;
+
 @end
diff -r 1bfcbf06c354 -r 3db86d54b08b Frameworks/Adium Framework/Source/AIGroupChat.m
--- a/Frameworks/Adium Framework/Source/AIGroupChat.m	Sun Apr 28 15:19:21 2013 -0400
+++ b/Frameworks/Adium Framework/Source/AIGroupChat.m	Thu May 02 01:11:44 2013 +0200
@@ -32,7 +32,6 @@
 @interface AIGroupChat ()
 
 - (void)contentObjectAdded:(NSNotification *)notification;
-- (AIListContact *)visibleObjectAtIndex:(NSUInteger)idx;
 
 @end
 
@@ -47,9 +46,9 @@
     if ((self = [super initForAccount:inAccount])) {
         showJoinLeave = YES;
 		expanded = YES;
-        participatingContacts = [[NSMutableArray alloc] init];
-		participatingContactsFlags = [[NSMutableDictionary alloc] init];
-		participatingContactsAliases = [[NSMutableDictionary alloc] init];
+        participatingNicks = [[NSMutableArray alloc] init];
+		participatingNicksFlags = [[NSMutableDictionary alloc] init];
+		participatingNicksContacts = [[NSMutableDictionary alloc] init];
 
         
 		[[NSNotificationCenter defaultCenter] addObserver:self
@@ -68,9 +67,9 @@
 	[self removeAllParticipatingContactsSilently];
     
     [lastMessageDate release];
-	[participatingContacts release];
-	[participatingContactsFlags release];
-	[participatingContactsAliases release];
+	[participatingNicks release];
+	[participatingNicksFlags release];
+	[participatingNicksContacts release];
     
     [super dealloc];
 }
@@ -127,20 +126,6 @@
 	[super object:inObject didChangeValueForProperty:key notify:notify];
 }
 
-/*!
- * @brief The alias for a given contact
- */
-- (NSString *)aliasForContact:(AIListObject *)contact
-{
-	NSString *alias = [participatingContactsAliases objectForKey:contact.UID];
-	
-	if (!alias) {
-		alias = [self.account fallbackAliasForContact:(AIListContact *)contact inChat:self];
-	}
-	
-	return alias;
-}
-
 AIGroupChatFlags highestFlag(AIGroupChatFlags flags)
 {
 	if ((flags & AIGroupChatFounder) == AIGroupChatFounder)
@@ -204,15 +189,20 @@
 /*!
  * @brief Update the topic.
  */
-- (void)updateTopic:(NSString *)inTopic withSource:(AIListContact *)contact
+- (void)updateTopic:(NSString *)inTopic withSource:(NSString *)nick
 {
+	NSParameterAssert([nick isKindOfClass:[NSString class]]);
+	
+	AIListContact *contact = [self contactForNick:nick];
+	
 	[self setValue:inTopic forProperty:KEY_TOPIC notify:NotifyNow];
 	
-	[self setValue:contact forProperty:KEY_TOPIC_SETTER notify:NotifyNow];
+	[self setValue:nick forProperty:KEY_TOPIC_SETTER notify:NotifyNow];
 	
 	// Apply the new topic to the message view
 	AIContentTopic *contentTopic = [AIContentTopic topicInChat:self
 													withSource:contact
+													sourceNick:nick
 												   destination:nil
 														  date:[NSDate date]
 													   message:[NSAttributedString stringWithString:[self valueForProperty:KEY_TOPIC] ?: @""]];
@@ -260,15 +250,15 @@
  */
 - (void)resortParticipants
 {
-	[participatingContacts sortUsingComparator:^(id objectA, id objectB){
-		AIGroupChatFlags flagA = highestFlag([self flagsForContact:objectA]), flagB = highestFlag([self flagsForContact:objectB]);
+	[participatingNicks sortUsingComparator:^(id objectA, id objectB){
+		AIGroupChatFlags flagA = highestFlag([self flagsForNick:objectA]), flagB = highestFlag([self flagsForNick:objectB]);
 		
 		if(flagA > flagB) {
 			return (NSComparisonResult)NSOrderedAscending;
 		} else if (flagA < flagB) {
 			return (NSComparisonResult)NSOrderedDescending;
 		} else {
-			return [[self displayNameForContact:objectA] localizedCaseInsensitiveCompare:[self displayNameForContact:objectB]];
+			return [objectA localizedCaseInsensitiveCompare:objectB];
 		}
 	}];
 }
@@ -276,46 +266,42 @@
 //Participating ListObjects --------------------------------------------------------------------------------------------
 #pragma mark Participating ListObjects
 
-/*!
- * @brief The display name for the contact in this chat.
- *
- * @param contact The AIListObject whose display name should be created
- *
- * If the user has an alias set, the alias is used, otherwise the display name.
- *
- * @returns Display name
- */
-- (NSString *)displayNameForContact:(AIListObject *)contact
+- (AIListObject *)contactForNick:(NSString *)nick
 {
-	return [self aliasForContact:contact] ?: contact.displayName;
+	return [participatingNicksContacts objectForKey:nick];
 }
 
-/*!
- * @brief The flags for a given contact.
- */
-- (AIGroupChatFlags)flagsForContact:(AIListObject *)contact
+- (AIGroupChatFlags)flagsForNick:(NSString *)nick
 {
-	return [(NSNumber *)[participatingContactsFlags objectForKey:contact.UID] intValue];
+	return [[participatingNicksFlags objectForKey:nick] intValue];
 }
 
-/*!
- * @brief Set the flags for a contact
- *
- * Note that this doesn't set the bitwise or; this directly sets the value passed.
- */
-- (void)setFlags:(AIGroupChatFlags)flags forContact:(AIListObject *)contact
+- (void)setFlags:(AIGroupChatFlags)flags forNick:(NSString *)nick
 {
-	[participatingContactsFlags setObject:[NSNumber numberWithInteger:flags]
-								   forKey:contact.UID];
+	[participatingNicksFlags setObject:@(flags)
+								forKey:nick];
 }
 
-/*!
- * @brief Set the alias for a contact.
- */
-- (void)setAlias:(NSString *)alias forContact:(AIListObject *)contact
+- (void)setContact:(AIListContact *)contact forNick:(NSString *)nick
 {
-	[participatingContactsAliases setObject:alias
-									 forKey:contact.UID];
+	NSParameterAssert(contact != nil);
+	
+	[participatingNicksContacts setObject:contact
+								   forKey:nick];
+}
+
+- (void)changeNick:(NSString *)from to:(NSString *)to
+{
+	[participatingNicks removeObject:from];
+	[participatingNicks addObject:to];
+	
+	NSNumber *flags = [participatingNicksFlags objectForKey:from];
+	[participatingNicksFlags removeObjectForKey:from];
+	if (flags) [participatingNicksFlags setObject:flags forKey:to];
+	
+	AIListObject *contact = [participatingNicksContacts objectForKey:from];
+	[participatingNicksContacts removeObjectForKey:from];
+	if (contact) [participatingNicksContacts setObject:contact forKey:to];
 }
 
 /*!
@@ -324,36 +310,41 @@
  * Removes any values which are dependent upon the contact, such as
  * its flags or alias.
  */
-- (void)removeSavedValuesForContactUID:(NSString *)contactUID
+- (void)removeSavedValuesForNick:(NSString *)nick
 {
-	[participatingContactsFlags removeObjectForKey:contactUID];
-	[participatingContactsAliases removeObjectForKey:contactUID];
+	[participatingNicksFlags removeObjectForKey:nick];
+	[participatingNicksContacts removeObjectForKey:nick];
 }
 
-- (void)addParticipatingListObject:(AIListContact *)inObject notify:(BOOL)notify
+- (NSArray *)nicksForContact:(AIListContact *)contact
 {
-	[self addParticipatingListObjects:[NSArray arrayWithObject:inObject] notify:notify];
+	NSMutableArray *nicks = [NSMutableArray array];
+	
+	for (NSString *nick in participatingNicks) {
+		if ([[participatingNicksContacts objectForKey:nick] isEqual:contact]) {
+			[nicks addObject:nick];
+		}
+	}
+	
+	return nicks;
 }
 
-- (void)addParticipatingListObjects:(NSArray *)inObjects notify:(BOOL)notify
+- (void)addParticipatingNick:(NSString *)inObject notify:(BOOL)notify
 {
-	NSMutableArray *contacts = [inObjects mutableCopy];
-    
-	for (AIListObject *obj in inObjects) {
-		if ([self containsObject:obj] || ![self canContainObject:obj])
-			[contacts removeObject:obj];
-	}
-	
-	[participatingContacts addObjectsFromArray:contacts];
-	[adium.chatController chat:self addedListContacts:contacts notify:notify];
-	[contacts release];
+	[self addParticipatingNicks:[NSArray arrayWithObject:inObject] notify:notify];
 }
 
-- (BOOL)addObject:(AIListObject *)inObject
+- (void)addParticipatingNicks:(NSArray *)inObjects notify:(BOOL)notify
 {
-	NSParameterAssert([inObject isKindOfClass:[AIListContact class]]);
+	[participatingNicks addObjectsFromArray:inObjects];
+	[adium.chatController chat:self addedListContacts:inObjects notify:notify];
+}
+
+- (BOOL)addObject:(NSString *)inObject
+{
+	NSParameterAssert([inObject isKindOfClass:[NSString class]]);
     
-	[self addParticipatingListObject:(AIListContact *)inObject notify:YES];
+	[self addParticipatingNick:inObject notify:YES];
 	return YES;
 }
 
@@ -363,78 +354,91 @@
 	return ([self.account inviteContact:inContact toChat:self withMessage:inviteMessage]);
 }
 
-#pragma mark AIContainingObject protocol
+- (NSArray *)containedObjects
+{
+	return [participatingNicksContacts allValues];
+}
+
 - (NSArray *)visibleContainedObjects
 {
 	return self.containedObjects;
 }
-- (NSArray *)containedObjects
-{
-	return participatingContacts;
-}
+
 - (NSUInteger)countOfContainedObjects
 {
-	return [participatingContacts count];
+	return [participatingNicks count];
 }
 
 - (BOOL)containsObject:(AIListObject *)inObject
 {
-	return [participatingContacts containsObjectIdenticalTo:inObject];
+	return [[participatingNicksContacts allValues] containsObjectIdenticalTo:inObject];
 }
 
-- (AIListContact *)visibleObjectAtIndex:(NSUInteger)idx
+- (NSString *)visibleObjectAtIndex:(NSUInteger)idx
 {
-	return [participatingContacts objectAtIndex:idx];
+	return [participatingNicks objectAtIndex:idx];
 }
 
 - (NSUInteger)visibleIndexOfObject:(AIListObject *)obj
 {
 	if(![[AIContactHidingController sharedController] visibilityOfListObject:obj inContainer:self])
 		return NSNotFound;
-	return [participatingContacts indexOfObject:obj];
+	for (NSString *nick in participatingNicks) {
+		if ([[participatingNicksContacts objectForKey:nick] isEqual:obj]) {
+			return [participatingNicks indexOfObject:nick];
+		}
+	}
+	
+	return NSNotFound;
 }
 
 - (NSArray *)uniqueContainedObjects
 {
-	return self.containedObjects;
+	NSMutableArray *contacts = [NSMutableArray array];
+	
+	for (AIListContact *contact in [participatingNicksContacts allValues]) {
+		if (![contacts containsObject:contacts]) {
+			[contacts addObject:contact];
+		}
+	}
+		
+	return contacts;
 }
 
-- (void)removeObject:(AIListObject *)inObject
+- (void)removeObject:(NSString *)inObject
 {
-	if ([self containsObject:inObject]) {
-		AIListContact *contact = (AIListContact *)inObject; //if we contain it, it has to be an AIListContact
+	AIListContact *contact = [participatingNicksContacts valueForKey:inObject];
+	
+	//make sure removing it from the array doesn't deallocate it immediately, since we need it for -chat:removedListContact:
+	[contact retain];
+	
+	[participatingNicks removeObject:inObject];
+	
+	[self removeSavedValuesForNick:inObject];
+	
+	[adium.chatController chat:self removedListContact:contact];
+	
+	if (contact.isStranger &&
+		![adium.chatController allGroupChatsContainingContact:contact.parentContact].count &&
+		![adium.chatController existingChatWithContact:contact.parentContact]) {
 		
-		//make sure removing it from the array doesn't deallocate it immediately, since we need it for -chat:removedListContact:
-		[inObject retain];
-		
-		[participatingContacts removeObject:inObject];
-		
-		[self removeSavedValuesForContactUID:inObject.UID];
-        
-		[adium.chatController chat:self removedListContact:contact];
-        
-		if (contact.isStranger &&
-			![adium.chatController allGroupChatsContainingContact:contact.parentContact].count &&
-			![adium.chatController existingChatWithContact:contact.parentContact]) {
-			
-			[[AIContactObserverManager sharedManager] delayListObjectNotifications];
-			[adium.contactController accountDidStopTrackingContact:contact];
-			[[AIContactObserverManager sharedManager] endListObjectNotificationsDelaysImmediately];
-		}
-		
-		[inObject release];
+		[[AIContactObserverManager sharedManager] delayListObjectNotifications];
+		[adium.contactController accountDidStopTrackingContact:contact];
+		[[AIContactObserverManager sharedManager] endListObjectNotificationsDelaysImmediately];
 	}
+	
+	[contact release];
 }
 
-- (void)removeObjectAfterAccountStopsTracking:(AIListObject *)object
+- (void)removeObjectAfterAccountStopsTracking:(NSString *)object
 {
-	[self removeObject:object]; //does nothing if we've already removed it
+	assert(FALSE);
 }
 
 - (void)removeAllParticipatingContactsSilently
 {
 	/* Note that allGroupChatsContainingContact won't count this chat if it's already marked as not open */
-	for (AIListContact *listContact in self) {
+	for (AIListContact *listContact in [participatingNicksContacts allValues]) {
 		if (listContact.isStranger &&
 			![adium.chatController existingChatWithContact:listContact.parentContact] &&
 			([adium.chatController allGroupChatsContainingContact:listContact.parentContact].count == 0)) {
@@ -442,9 +446,9 @@
 		}
 	}
     
-	[participatingContacts removeAllObjects];
-	[participatingContactsFlags removeAllObjects];
-	[participatingContactsAliases removeAllObjects];
+	[participatingNicks removeAllObjects];
+	[participatingNicksFlags removeAllObjects];
+	[participatingNicksContacts removeAllObjects];
     
 	[[NSNotificationCenter defaultCenter] postNotificationName:Chat_ParticipatingListObjectsChanged
                                                         object:self];
@@ -464,7 +468,7 @@
 
 - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
 {
-	return [self.containedObjects countByEnumeratingWithState:state objects:stackbuf count:len];
+	return [participatingNicks countByEnumeratingWithState:state objects:stackbuf count:len];
 }
 
 - (BOOL) canContainObject:(id)obj
diff -r 1bfcbf06c354 -r 3db86d54b08b Frameworks/Adium Framework/Source/AIListContactGroupChatCell.m
--- a/Frameworks/Adium Framework/Source/AIListContactGroupChatCell.m	Sun Apr 28 15:19:21 2013 -0400
+++ b/Frameworks/Adium Framework/Source/AIListContactGroupChatCell.m	Thu May 02 01:11:44 2013 +0200
@@ -22,6 +22,7 @@
 @implementation AIListContactGroupChatCell
 
 @synthesize chat;
+
 - (void)dealloc
 {
 	[chat release];
@@ -30,11 +31,10 @@
 
 - (NSString *)labelString
 {
-	AIListObject *listObject = [proxyObject listObject];
 	NSString *label;
 	
-	if (chat && [chat displayNameForContact:listObject]) {
-		label = [chat displayNameForContact:listObject];
+	if (proxyObject.nick) {
+		label = proxyObject.nick;
 	} else {
 		label = [super labelString];
 	}
@@ -44,23 +44,21 @@
 
 - (NSImage *)statusImage
 {
-    AIListObject    *listObject = [proxyObject listObject];
-	return [[AIGroupChatStatusIcons sharedIcons] imageForFlag:[chat flagsForContact:listObject]];
+	return [[AIGroupChatStatusIcons sharedIcons] imageForFlag:[chat flagsForNick:proxyObject.nick]];
 }
 
 - (NSImage *)serviceImage
 {
 	// We can't use [listObject statusIcon] because it will show unknown for strangers.
-    AIListObject    *listObject = [proxyObject listObject];
-	return [AIStatusIcons statusIconForListObject:listObject
+    AIListContact    *listObject = [chat contactForNick:proxyObject.nick];
+	return [AIStatusIcons statusIconForListObject:(AIListObject *)listObject
 											 type:AIStatusIconTab
 										direction:AIIconFlipped];
 }
 
 - (NSColor *)textColor
 {
-    AIListObject    *listObject = [proxyObject listObject];
-	return [[AIGroupChatStatusIcons sharedIcons] colorForFlag:[chat flagsForContact:listObject]];
+	return [[AIGroupChatStatusIcons sharedIcons] colorForFlag:[chat flagsForNick:proxyObject.nick]];
 }
 
 - (float)imageOpacityForDrawing
diff -r 1bfcbf06c354 -r 3db86d54b08b Frameworks/Adium Framework/Source/AIProxyListObject.h
--- a/Frameworks/Adium Framework/Source/AIProxyListObject.h	Sun Apr 28 15:19:21 2013 -0400
+++ b/Frameworks/Adium Framework/Source/AIProxyListObject.h	Thu May 02 01:11:44 2013 +0200
@@ -25,6 +25,7 @@
 	NSAttributedString *cachedDisplayName;
 	NSDictionary *cachedLabelAttributes;
 	NSSize cachedDisplayNameSize;
+	NSString *nick;
 }
 @property (nonatomic, copy) NSDictionary *cachedLabelAttributes;
 @property (nonatomic, retain) NSString *cachedDisplayNameString;
@@ -32,6 +33,7 @@
 @property (nonatomic) NSSize cachedDisplayNameSize;
 
 @property (nonatomic, retain) NSString *key;
+ at property (nonatomic, retain) NSString *nick;
 
 @property (nonatomic, assign) AIListObject *listObject;
 @property (nonatomic, assign) ESObjectWithProperties <AIContainingObject> * containingObject;
diff -r 1bfcbf06c354 -r 3db86d54b08b Frameworks/Adium Framework/Source/AIProxyListObject.m
--- a/Frameworks/Adium Framework/Source/AIProxyListObject.m	Sun Apr 28 15:19:21 2013 -0400
+++ b/Frameworks/Adium Framework/Source/AIProxyListObject.m	Thu May 02 01:11:44 2013 +0200
@@ -25,7 +25,7 @@
 @implementation AIProxyListObject
 
 @synthesize key, cachedDisplayName, cachedDisplayNameString, cachedLabelAttributes, cachedDisplayNameSize;
- at synthesize listObject, containingObject;
+ at synthesize listObject, containingObject, nick;
 
 
 static inline NSMutableDictionary *_getProxyDict() {
@@ -52,10 +52,21 @@
 + (AIProxyListObject *)proxyListObjectForListObject:(AIListObject *)inListObject
 									   inListObject:(ESObjectWithProperties <AIContainingObject>*)inContainingObject
 {
+	return [self proxyListObjectForListObject:inListObject inListObject:inContainingObject withNick:nil];
+}
+
++ (AIProxyListObject *)proxyListObjectForListObject:(AIListObject *)inListObject
+									   inListObject:(ESObjectWithProperties <AIContainingObject>*)inContainingObject
+										   withNick:(NSString *)inNick
+{
 	AIProxyListObject *proxy;
 	NSString *key = (inContainingObject ? 
 					 [NSString stringWithFormat:@"%@-%@", inListObject.internalObjectID, inContainingObject.internalObjectID] :
 					 inListObject.internalObjectID);
+	
+	if (inNick) {
+		key = [key stringByAppendingFormat:@"-%@", inNick];
+	}
 
 	proxy = [proxyDict objectForKey:key];
 
@@ -73,6 +84,7 @@
 		proxy.listObject = inListObject;
 		proxy.containingObject = inContainingObject;
 		proxy.key = key;
+		proxy.nick = inNick;
 		[inListObject noteProxyObject:proxy];
 		[proxyDict setObject:proxy
 					  forKey:key];
diff -r 1bfcbf06c354 -r 3db86d54b08b Frameworks/Adium Framework/Source/ESFileTransfer.m
--- a/Frameworks/Adium Framework/Source/ESFileTransfer.m	Sun Apr 28 15:19:21 2013 -0400
+++ b/Frameworks/Adium Framework/Source/ESFileTransfer.m	Thu May 02 01:11:44 2013 +0200
@@ -71,6 +71,7 @@
 	}
     if ((self = [super initWithChat:aChat
 							 source:s
+						 sourceNick:nil
 						destination:d
 							   date:[NSDate date]
 							message:[[[NSAttributedString alloc] initWithString:@""] autorelease]
diff -r 1bfcbf06c354 -r 3db86d54b08b Plugins/Dual Window Interface/AIMessageViewController.m
--- a/Plugins/Dual Window Interface/AIMessageViewController.m	Sun Apr 28 15:19:21 2013 -0400
+++ b/Plugins/Dual Window Interface/AIMessageViewController.m	Thu May 02 01:11:44 2013 +0200
@@ -848,22 +848,23 @@
 	return charRange;
 }
 
-- (NSArray *)contactsMatchingBeginningString:(NSString *)partialWord
+- (NSArray *)nicksMatchingBeginningString:(NSString *)partialWord
 {
-	NSMutableArray *contacts = [NSMutableArray array];
+	NSMutableArray *nicks = [NSMutableArray array];
 	
-	for (AIListContact *listContact in (AIGroupChat *)self.chat) {
+	for (NSString *nick in (AIGroupChat *)self.chat) {
+		AIListContact *listContact = [(AIGroupChat *)self.chat contactForNick:nick];
 		// Add to the list if it matches: (1) The display name for the chat (alias fallback to default display name), 
 		// (2) The UID, or (3) the display name
-		if ([[(AIGroupChat *)self.chat displayNameForContact:listContact] rangeOfString:partialWord options:(NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound
+		if ([nick rangeOfString:partialWord options:(NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound
 			|| [listContact.UID rangeOfString:partialWord options:(NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound
 			|| [listContact.displayName rangeOfString:partialWord options:(NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound) {
-			[contacts addObject:listContact];
-			AILogWithSignature(@"Added match %@ with nick %@; UID: %@; formattedUID: %@; displayName: %@", listContact, [(AIGroupChat *)self.chat aliasForContact:listContact], listContact.UID, listContact.formattedUID, listContact.displayName);
+			[nicks addObject:nick];
+			AILogWithSignature(@"Added match %@ with nick %@; UID: %@; formattedUID: %@; displayName: %@", listContact, nick, listContact.UID, listContact.formattedUID, listContact.displayName);
 		}
 	}
 	
-	return contacts;
+	return nicks;
 }
 
 - (NSArray *)textView:(NSTextView *)textView completions:(NSArray *)words forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)idx
@@ -898,13 +899,14 @@
 		completions = [NSMutableArray array];
 		
 		// For each matching contact:
-		for (AIListContact *listContact in [self contactsMatchingBeginningString:partialWord]) {
+		for (NSString *nick in [self nicksMatchingBeginningString:partialWord]) {
 			// Complete the chat alias.
-			NSString *completion = [(AIGroupChat *)self.chat aliasForContact:listContact];
+			NSString *completion = nick;
 			
 			// Otherwise, complete the UID (if we're completing UIDs for this chat) or the display name.
-			if (!completion)
-				completion = autoCompleteUID ? listContact.formattedUID : listContact.displayName;
+#warning Fix this for nicksMatchingBeginningString
+//			if (!completion)
+//				completion = autoCompleteUID ? listContact.formattedUID : listContact.displayName;
 			
 			[completions addObject:(suffix ? [completion stringByAppendingString:suffix] : completion)];
 		}
diff -r 1bfcbf06c354 -r 3db86d54b08b Plugins/Purple Service/CBPurpleAccount.h
--- a/Plugins/Purple Service/CBPurpleAccount.h	Sun Apr 28 15:19:21 2013 -0400
+++ b/Plugins/Purple Service/CBPurpleAccount.h	Thu May 02 01:11:44 2013 +0200
@@ -196,10 +196,10 @@
 - (void)updateTopic:(NSString *)inTopic forChat:(AIGroupChat *)chat withSource:(NSString *)source;
 - (void)updateTitle:(NSString *)inTitle forChat:(AIGroupChat *)chat;
 - (void)convUpdateForChat:(AIGroupChat *)chat type:(NSNumber *)type;
-- (void)renameParticipant:(NSString *)oldUID newName:(NSString *)newUID newAlias:(NSString *)newAlias flags:(PurpleConvChatBuddyFlags)flags inChat:(AIGroupChat *)chat;
+- (void)renameParticipant:(NSString *)oldName newNick:(NSString *)newName newUID:(NSString *)newUID flags:(PurpleConvChatBuddyFlags)flags inChat:(AIGroupChat *)chat;
 - (void)removeUser:(NSString *)contactName fromChat:(AIGroupChat *)chat;
 - (void)updateUserListForChat:(AIGroupChat *)chat users:(NSArray *)users newlyAdded:(BOOL)newlyAdded;
-- (void)updateUser:(NSString *)user forChat:(AIGroupChat *)chat flags:(PurpleConvChatBuddyFlags)flags alias:(NSString *)alias attributes:(NSDictionary *)attributes;
+- (void)updateUser:(NSString *)user forChat:(AIGroupChat *)chat flags:(PurpleConvChatBuddyFlags)flags newAlias:(NSString *)alias attributes:(NSDictionary *)attributes;
 - (NSDictionary *)willJoinChatUsingDictionary:(NSDictionary *)chatCreationDictionary;
 - (BOOL)chatCreationDictionary:(NSDictionary *)chatCreationDict isEqualToDictionary:(NSDictionary *)baseDict;
 - (NSDictionary *)extractChatCreationDictionaryFromConversation:(PurpleConversation *)conv;
diff -r 1bfcbf06c354 -r 3db86d54b08b Plugins/Purple Service/CBPurpleAccount.m
--- a/Plugins/Purple Service/CBPurpleAccount.m	Sun Apr 28 15:19:21 2013 -0400
+++ b/Plugins/Purple Service/CBPurpleAccount.m	Thu May 02 01:11:44 2013 +0200
@@ -80,7 +80,7 @@
 - (NSString *)_mapIncomingGroupName:(NSString *)name;
 - (NSString *)_mapOutgoingGroupName:(NSString *)name;
 - (void)setTypingFlagOfChat:(AIChat *)inChat to:(NSNumber *)typingState;
-- (void)_receivedMessage:(NSAttributedString *)attributedMessage inChat:(AIChat *)chat fromListContact:(AIListContact *)sourceContact flags:(PurpleMessageFlags)flags date:(NSDate *)date;
+- (void)_receivedMessage:(NSAttributedString *)attributedMessage inChat:(AIChat *)chat fromListContact:(AIListContact *)sourceContact fromNick:(NSString *)sourceNick flags:(PurpleMessageFlags)flags date:(NSDate *)date;
 - (NSNumber *)shouldCheckMail;
 - (void)configurePurpleAccountNotifyingTarget:(id)target selector:(SEL)selector;
 - (void)continueConnectWithConfiguredProxy;
@@ -782,7 +782,7 @@
 		return;
 	
 	AIListContact *contact = [self contactWithUID:contactName];
-	[chat removeObject:contact];
+	[chat removeObject:contactName];
 	
 	if (contact.isStranger && 
 		![adium.chatController allGroupChatsContainingContact:contact.parentContact].count &&
@@ -820,22 +820,19 @@
 		
 		[contact setOnline:YES notify:NotifyNever silently:YES];
 		
-		[newListObjects addObject:contact];
+		[newListObjects addObject:[user objectForKey:@"Alias"]];
 	}
 	
-	[chat addParticipatingListObjects:newListObjects notify:newlyAdded];
+	[chat addParticipatingNicks:newListObjects notify:newlyAdded];
 	
 	for (NSDictionary *user in users) {
 		AIListContact *contact = [self contactWithUID:[user objectForKey:@"UID"]];
 		
-		[chat setFlags:(AIGroupChatFlags)[[user objectForKey:@"Flags"] integerValue] forContact:contact];
+		[chat setFlags:(AIGroupChatFlags)[[user objectForKey:@"Flags"] integerValue] forNick:[user objectForKey:@"Alias"]];
+		[chat setContact:contact forNick:[user objectForKey:@"Alias"]];
 		
-		if ([user objectForKey:@"Alias"]) {
-			[chat setAlias:[user objectForKey:@"Alias"] forContact:contact];
-			
-			if (contact.isStranger) {
-				[contact setServersideAlias:[user objectForKey:@"Alias"] silently:NO];
-			}
+		if ([user objectForKey:@"Alias"] && contact.isStranger) {
+			[contact setServersideAlias:[user objectForKey:@"Alias"] silently:NO];
 		}
 	}
 	
@@ -863,23 +860,21 @@
     return groupChatFlags;
 }
 
-- (void)renameParticipant:(NSString *)oldUID newName:(NSString *)newUID newAlias:(NSString *)newAlias flags:(PurpleConvChatBuddyFlags)flags inChat:(AIGroupChat *)chat
+- (void)renameParticipant:(NSString *)oldName newNick:(NSString *)newName newUID:(NSString *)newUID flags:(PurpleConvChatBuddyFlags)flags inChat:(AIGroupChat *)chat
 {
-	[chat removeSavedValuesForContactUID:oldUID];
+	[chat changeNick:oldName to:newName];
+	[chat setFlags:groupChatFlagsFromPurpleConvChatBuddyFlags(flags) forNick:newName];
 	
-	AIListContact *contact = [adium.contactController existingContactWithService:self.service account:self UID:oldUID];
-
+	AIListContact *contact = (AIListContact *)[chat contactForNick:newName];
+	
 	if (contact) {
 		[adium.contactController setUID:newUID forContact:contact];
 	} else {
 		contact = [self contactWithUID:newUID];
 	}
-
- 	[chat setFlags:groupChatFlagsFromPurpleConvChatBuddyFlags(flags) forContact:contact];
-	[chat setAlias:newAlias forContact:contact];
 	
 	if (contact.isStranger) {
-		[contact setServersideAlias:newAlias silently:NO];
+		[contact setServersideAlias:newName silently:NO];
 	}
 
 	// Post an update notification since we modified the user entirely.
@@ -908,28 +903,27 @@
 
 - (void)updateUser:(NSString *)user
 		   forChat:(AIGroupChat *)chat
-			 flags:(PurpleConvChatBuddyFlags)flags 
-			 alias:(NSString *)alias
+			 flags:(PurpleConvChatBuddyFlags)flags
+		  newAlias:(NSString *)alias
 		attributes:(NSDictionary *)attributes
 {
 	BOOL triggerUserlistUpdate = NO;
 	
-	AIListContact *contact = [self contactWithUID:user];
+	AIListContact *contact = (AIListContact *)[chat contactForNick:user];
 	
-	AIGroupChatFlags oldFlags = [chat flagsForContact:contact];
+	AIGroupChatFlags oldFlags = [chat flagsForNick:alias];
     AIGroupChatFlags newFlags = groupChatFlagsFromPurpleConvChatBuddyFlags(flags);
-	NSString *oldAlias = [chat aliasForContact:contact];
 	
 	// Trigger an update if the alias or flags (ignoring away state) changes.
-	if ((alias && !oldAlias)
-		|| (!alias && oldAlias)
-		|| ![[chat aliasForContact:contact] isEqualToString:alias]




More information about the commits mailing list