adium 5157:8b5d2cdd6d3d: Moved all group chat related code from ...

commits at adium.im commits at adium.im
Sun Oct 21 22:00:54 UTC 2012


details:	http://hg.adium.im/adium/rev/8b5d2cdd6d3d
revision:	5157:8b5d2cdd6d3d
branch:		adium-1.6
author:		Thijs Alkemade <thijsalkemade at gmail.com>
date:		Sun Oct 21 23:57:17 2012 +0200

Moved all group chat related code from AIChat into a subclass AIGroupChat.

This should improve memory usage for normal chats, and make the code somewhat cleaner.
Subject: adium 5158:2a996beac083: This change was unnecessary. Restore the ability to spam filetransfers.

details:	http://hg.adium.im/adium/rev/2a996beac083
revision:	5158:2a996beac083
branch:		adium-1.6
author:		Thijs Alkemade <thijsalkemade at gmail.com>
date:		Sun Oct 21 23:59:42 2012 +0200

This change was unnecessary. Restore the ability to spam filetransfers.

diffs (truncated from 2250 to 1000 lines):

diff -r 960761c3597b -r 2a996beac083 Adium.xcodeproj/project.pbxproj
--- a/Adium.xcodeproj/project.pbxproj	Sun Oct 21 20:07:44 2012 +0200
+++ b/Adium.xcodeproj/project.pbxproj	Sun Oct 21 23:59:42 2012 +0200
@@ -1371,6 +1371,8 @@
 		767870E51634139600BD0E4D /* AIAccountSelectionTopBar.xib in Resources */ = {isa = PBXBuildFile; fileRef = 767870E71634139600BD0E4D /* AIAccountSelectionTopBar.xib */; };
 		76889DEB12D3CA17007AEF00 /* get-info.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 76889DEA12D3CA17007AEF00 /* get-info.tiff */; };
 		76889DEF12D3CA40007AEF00 /* Profile.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 76889DEE12D3CA40007AEF00 /* Profile.tiff */; };
+		76A79E0B16349477007A0497 /* AIGroupChat.h in Headers */ = {isa = PBXBuildFile; fileRef = 76A79E0916349477007A0497 /* AIGroupChat.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		76A79E0C16349477007A0497 /* AIGroupChat.m in Sources */ = {isa = PBXBuildFile; fileRef = 76A79E0A16349477007A0497 /* AIGroupChat.m */; };
 		76C1AF9C125A906A00D269A9 /* AIAdiumURLProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 76C1AF9B125A906A00D269A9 /* AIAdiumURLProtocol.m */; };
 		76FF925A14B524B40043E23B /* AIIRCConsoleController.h in Headers */ = {isa = PBXBuildFile; fileRef = 76FF925814B524B40043E23B /* AIIRCConsoleController.h */; };
 		76FF925B14B524B40043E23B /* AIIRCConsoleController.m in Sources */ = {isa = PBXBuildFile; fileRef = 76FF925914B524B40043E23B /* AIIRCConsoleController.m */; };
@@ -4402,6 +4404,8 @@
 		767870E61634139600BD0E4D /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/AIAccountSelectionTopBar.xib; sourceTree = "<group>"; };
 		76889DEA12D3CA17007AEF00 /* get-info.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = "get-info.tiff"; path = "Resources/get-info.tiff"; sourceTree = "<group>"; };
 		76889DEE12D3CA40007AEF00 /* Profile.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = Profile.tiff; path = Resources/Profile.tiff; sourceTree = "<group>"; };
+		76A79E0916349477007A0497 /* AIGroupChat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIGroupChat.h; path = "Frameworks/Adium Framework/Source/AIGroupChat.h"; sourceTree = "<group>"; };
+		76A79E0A16349477007A0497 /* AIGroupChat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIGroupChat.m; path = "Frameworks/Adium Framework/Source/AIGroupChat.m"; sourceTree = "<group>"; };
 		76C1AF9A125A906A00D269A9 /* AIAdiumURLProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIAdiumURLProtocol.h; path = "Plugins/WebKit Message View/AIAdiumURLProtocol.h"; sourceTree = "<group>"; };
 		76C1AF9B125A906A00D269A9 /* AIAdiumURLProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIAdiumURLProtocol.m; path = "Plugins/WebKit Message View/AIAdiumURLProtocol.m"; sourceTree = "<group>"; };
 		76FF925814B524B40043E23B /* AIIRCConsoleController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIIRCConsoleController.h; path = "Plugins/Purple Service/AIIRCConsoleController.h"; sourceTree = "<group>"; };
@@ -8569,6 +8573,8 @@
 				63B0EC9A0F8FBB660062476B /* AIProxyListObject.m */,
 				34111A5D06BE1B370005AF5C /* ESObjectWithProperties.h */,
 				34111A5E06BE1B370005AF5C /* ESObjectWithProperties.m */,
+				76A79E0916349477007A0497 /* AIGroupChat.h */,
+				76A79E0A16349477007A0497 /* AIGroupChat.m */,
 			);
 			name = "Contacts & Chats";
 			sourceTree = "<group>";
@@ -9064,6 +9070,7 @@
 				112B47670F82E0FC00690E84 /* AIXtraInfo.h in Headers */,
 				34F17FCE0F8EAC34009C5A39 /* AIListOutlineView+Drawing.h in Headers */,
 				63B0EC9D0F8FBB660062476B /* AIProxyListObject.h in Headers */,
+				76A79E0B16349477007A0497 /* AIGroupChat.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -10548,6 +10555,7 @@
 				63B0EC9C0F8FBB660062476B /* AIProxyListObject.m in Sources */,
 				76FF926814B62AB80043E23B /* AIConsoleController.m in Sources */,
 				5AEE60011602BAE200304672 /* AIBoolToControlTextColorTransformer.m in Sources */,
+				76A79E0C16349477007A0497 /* AIGroupChat.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff -r 960761c3597b -r 2a996beac083 Frameworks/Adium Framework/Source/AIAbstractAccount.m
--- a/Frameworks/Adium Framework/Source/AIAbstractAccount.m	Sun Oct 21 20:07:44 2012 +0200
+++ b/Frameworks/Adium Framework/Source/AIAbstractAccount.m	Sun Oct 21 23:59:42 2012 +0200
@@ -24,6 +24,7 @@
 #import <Adium/AIInterfaceControllerProtocol.h>
 #import <Adium/AIStatusControllerProtocol.h>
 #import <Adium/AIChat.h>
+#import <Adium/AIGroupChat.h>
 #import <Adium/AIContentEvent.h>
 #import <Adium/AIListContact.h>
 #import <Adium/AIService.h>
@@ -1356,7 +1357,7 @@
 			[adium.contentController receiveContentObject:newStatusMessage];
 			
 			if (chat.isGroupChat)
-				[chat removeAllParticipatingContactsSilently];
+				[(AIGroupChat *)chat removeAllParticipatingContactsSilently];
 		}
 	}
 	
diff -r 960761c3597b -r 2a996beac083 Frameworks/Adium Framework/Source/AIChat.h
--- a/Frameworks/Adium Framework/Source/AIChat.h	Sun Oct 21 20:07:44 2012 +0200
+++ b/Frameworks/Adium Framework/Source/AIChat.h	Sun Oct 21 23:59:42 2012 +0200
@@ -97,22 +97,14 @@
 	AIChatInvalidNumberOfArguments
 } AIChatErrorType;
 
- at interface AIChat : ESObjectWithProperties <AIContainingObject> {
+ at interface AIChat : ESObjectWithProperties {
 	AIAccount			*account;
 	NSDate				*dateOpened;
 	BOOL				isOpen;
-	BOOL				isGroupChat;
 	BOOL				hasSentOrReceivedContent;
 
 	NSMutableArray		*pendingOutgoingContentObjects;
 	
-	BOOL				hideUserIconAndStatus;
-	BOOL				showJoinLeave;
-	
-	NSMutableDictionary	*participatingContactsFlags;
-	NSMutableDictionary	*participatingContactsAliases;
-	NSMutableArray		*participatingContacts;
-	
 	AIListContact		*preferredContact;
 	NSString			*name;
 	NSString			*uniqueChatID;
@@ -120,14 +112,10 @@
 	
 	NSMutableSet		*ignoredListContacts;
 	
-	BOOL				expanded;
-	
 	BOOL				enableTypingNotifications;
 	
 	NSMutableSet		*customEmoticons;
 	
-	NSDate				*lastMessageDate;
-	
 	// Former properties
 	NSImage				*tabStateIcon;
 	
@@ -141,12 +129,12 @@
 	NSInteger			ourTypingState;
 	
 	NSDictionary		*securityDetails;
-	
-	NSString			*topic;
-    AIListContact		*topicSetter;
+    
+    AIListContact       *_listObject;
 }
 
 + (id)chatForAccount:(AIAccount *)inAccount;
+- (id)initForAccount:(AIAccount *)inAccount;
 
 @property (readwrite, nonatomic, retain) AIAccount *account;
 
@@ -167,25 +155,9 @@
 
 - (void)setDisplayName:(NSString *)inDisplayName;
 
-// 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;
-
-- (void)resortParticipants;
-
-- (void)addParticipatingListObject:(AIListContact *)inObject notify:(BOOL)notify;
-- (void)addParticipatingListObjects:(NSArray *)inObjects notify:(BOOL)notify;
-- (void)removeAllParticipatingContactsSilently;
-- (void)removeObject:(AIListObject *)inObject;
-
 //
 @property (readwrite, nonatomic, retain) AIListContact *listObject;
 @property (readwrite, nonatomic, assign) AIListContact *preferredListObject;
-- (BOOL)inviteListContact:(AIListContact *)inObject withMessage:(NSString *)inviteMessage;
 
 - (BOOL)shouldBeginSendingContentObject:(AIContentObject *)inObject;
 - (void)finishedSendingContentObject:(AIContentObject *)inObject;
@@ -209,15 +181,6 @@
 - (BOOL)isListContactIgnored:(AIListObject *)inContact;
 - (void)setListContact:(AIListContact *)inContact isIgnored:(BOOL)isIgnored;
 
- at property (readwrite, nonatomic) BOOL isGroupChat;
- at property (readwrite, nonatomic) BOOL showJoinLeave;
-
- at property (readwrite, nonatomic) BOOL hideUserIconAndStatus;
- at property (readonly, nonatomic) BOOL supportsTopic;
-
-- (void)updateTopic:(NSString *)inTopic withSource:(AIListContact *)contact;
-- (void)setTopic:(NSString *)inTopic;
-
 - (void)addCustomEmoticon:(AIEmoticon *)inEmoticon;
 @property (readonly, nonatomic) NSMutableSet *customEmoticons;
 
@@ -229,6 +192,8 @@
 
 @property (readonly, nonatomic) BOOL shouldLog;
 
- at property (readwrite, copy, nonatomic) NSDate *lastMessageDate;
+// Compatibility. I don't like this here.
+- (NSArray *)containedObjects;
+- (BOOL)isGroupChat;
 
 @end
diff -r 960761c3597b -r 2a996beac083 Frameworks/Adium Framework/Source/AIChat.m
--- a/Frameworks/Adium Framework/Source/AIChat.m	Sun Oct 21 20:07:44 2012 +0200
+++ b/Frameworks/Adium Framework/Source/AIChat.m	Sun Oct 21 23:59:42 2012 +0200
@@ -43,18 +43,18 @@
 
 @interface AIChat ()
 - (id)initForAccount:(AIAccount *)inAccount;
-- (void)contentObjectAdded:(NSNotification *)notification;
 
 - (void)clearUniqueChatID;
 - (void)clearListObjectStatuses;
 
-- (AIListContact *)visibleObjectAtIndex:(NSUInteger)idx;
 @end
 
 @implementation AIChat
 
 static int nextChatNumber = 0;
 
+ at synthesize listObject = _listObject;
+
 + (id)chatForAccount:(AIAccount *)inAccount
 {
     return [[[self alloc] initForAccount:inAccount] autorelease];
@@ -65,38 +65,20 @@
     if ((self = [super init])) {
 		name = nil;
 		account = [inAccount retain];
-		participatingContacts = [[NSMutableArray alloc] init];
-		participatingContactsFlags = [[NSMutableDictionary alloc] init];
-		participatingContactsAliases = [[NSMutableDictionary alloc] init];
 		dateOpened = [[NSDate date] retain];
 		uniqueChatID = nil;
 		ignoredListContacts = nil;
 		isOpen = NO;
-		isGroupChat = NO;
-		expanded = YES;
 		customEmoticons = nil;
 		hasSentOrReceivedContent = NO;
-		showJoinLeave = YES;
 		pendingOutgoingContentObjects = [[NSMutableArray alloc] init];
 
 		AILog(@"[AIChat: %p initForAccount]",self);
-		
-		[[NSNotificationCenter defaultCenter] addObserver:self 
-												 selector:@selector(contentObjectAdded:) 
-													 name:Content_ContentObjectAdded 
-												   object:self];
 	}
 
     return self;
 }
 
-- (void)contentObjectAdded:(NSNotification *)notification
-{
-	AIContentMessage *content = [[notification userInfo] objectForKey:@"AIContentObject"];
-	
-	self.lastMessageDate = [content date];
-}
-
 /*!
  * @brief Deallocate
  */
@@ -105,22 +87,17 @@
 	AILog(@"[%@ dealloc]",self);
 
 	[account release];
-	[self removeAllParticipatingContactsSilently];
-	[participatingContacts release];
-	[participatingContactsFlags release];
-	[participatingContactsAliases release];
 	[dateOpened release];
+    [_listObject release];
 	[ignoredListContacts release];
 	[pendingOutgoingContentObjects release];
 	[uniqueChatID release]; uniqueChatID = nil;
 	[customEmoticons release]; customEmoticons = nil;
-	[topic release]; [topicSetter release];
 	
 	[tabStateIcon release]; tabStateIcon = nil;
     [chatCreationInfo release]; chatCreationInfo = nil;
     [enteredTextTimer release]; enteredTextTimer = nil;
     [securityDetails release]; securityDetails = nil;
-	[lastMessageDate release]; lastMessageDate = nil;
 	
 	[super dealloc];
 }
@@ -131,11 +108,7 @@
 	AIListContact 	*listObject = nil;
 	NSImage			*image = nil;
 
-	if (self.isGroupChat) {
-		listObject = (AIListContact *)[adium.contactController existingBookmarkForChat:self];
-	} else {
-		listObject = self.listObject;
-	}
+    listObject = self.listObject;
 
 	if (listObject) {
 		image = listObject.parentContact.userIcon;
@@ -153,11 +126,7 @@
 	AIListObject 	*listObject = nil;
 	NSImage			*chatMenuImage = nil;
 	
-	if (self.isGroupChat) {
-		listObject = (AIListContact *)[adium.contactController existingBookmarkForChat:self];
-	} else {
-		listObject = self.listObject;
-	}
+	listObject = self.listObject;
 
 	if (listObject) {
 		chatMenuImage = [AIUserIcons menuUserIconForObject:listObject];
@@ -224,12 +193,8 @@
 	if ([key isEqualToString:KEY_UNVIEWED_CONTENT] ||
 		[key isEqualToString:KEY_TYPING]) {
 		AIListObject	*listObject = nil;
-		
-		if (self.isGroupChat) {
-			listObject = (AIListContact *)[adium.contactController existingBookmarkForChat:self];
-		} else {
-			listObject = self.listObject;
-		}
+        
+		listObject = self.listObject;
 		
 		if (listObject) [listObject setValue:[self valueForProperty:key] forProperty:key notify:notify];
 	}
@@ -322,167 +287,14 @@
 									 silent:NO];
 }
 
-//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
-{
-	return [self aliasForContact:contact] ?: contact.displayName;
-}
-
-/*!
- * @brief The flags for a given contact.
- */
-- (AIGroupChatFlags)flagsForContact:(AIListObject *)contact
-{
-	return [(NSNumber *)[participatingContactsFlags objectForKey:contact.UID] intValue];
-}
-
-/*!
- * @brief The alias for a given contact
- */
-- (NSString *)aliasForContact:(AIListObject *)contact
-{
-	NSString *alias = [participatingContactsAliases objectForKey:contact.UID];
-	
-	if (!alias && self.isGroupChat) {
-		alias = [self.account fallbackAliasForContact:(AIListContact *)contact inChat:self];
-	}
-	
-	return alias;
-}
-
-/*!
- * @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
-{
-	[participatingContactsFlags setObject:[NSNumber numberWithInteger:flags]
-								   forKey:contact.UID];
-}
-
-/*!
- * @brief Set the alias for a contact.
- */
-- (void)setAlias:(NSString *)alias forContact:(AIListObject *)contact
-{
-	[participatingContactsAliases setObject:alias
-									 forKey:contact.UID];
-}
-
-AIGroupChatFlags highestFlag(AIGroupChatFlags flags)
-{
-	if ((flags & AIGroupChatFounder) == AIGroupChatFounder)
-		return AIGroupChatFounder;
-	
-	if ((flags & AIGroupChatOp) == AIGroupChatOp)
-		return AIGroupChatOp;
-	
-	if ((flags & AIGroupChatHalfOp) == AIGroupChatHalfOp)
-		return AIGroupChatHalfOp;
-	
-	if ((flags & AIGroupChatVoice) == AIGroupChatVoice)
-		return AIGroupChatVoice;
-	
-	return AIGroupChatNone;
-}
-
-/*!
- * @brief Resorts our participants
- *
- * This is called when our list objects change.
- */
-- (void)resortParticipants
-{
-	[participatingContacts sortUsingComparator:^(id objectA, id objectB){
-		AIGroupChatFlags flagA = highestFlag([self flagsForContact:objectA]), flagB = highestFlag([self flagsForContact:objectB]);
-		
-		if(flagA > flagB) {
-			return (NSComparisonResult)NSOrderedAscending;
-		} else if (flagA < flagB) {
-			return (NSComparisonResult)NSOrderedDescending;
-		} else {
-			return [[self displayNameForContact:objectA] localizedCaseInsensitiveCompare:[self displayNameForContact:objectB]];
-		}
-	}];
-}
-
-/*!
- * @brief Remove the saved values for a contact
- *
- * Removes any values which are dependent upon the contact, such as
- * its flags or alias.
-*/
-- (void)removeSavedValuesForContactUID:(NSString *)contactUID
-{
-	[participatingContactsFlags removeObjectForKey:contactUID];
-	[participatingContactsAliases removeObjectForKey:contactUID];
-}
-
-- (void)addParticipatingListObject:(AIListContact *)inObject notify:(BOOL)notify
-{
-	[self addParticipatingListObjects:[NSArray arrayWithObject:inObject] notify:notify];
-}
-
-- (void)addParticipatingListObjects:(NSArray *)inObjects 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];
-}
-
-- (BOOL)addObject:(AIListObject *)inObject
-{
-	NSParameterAssert([inObject isKindOfClass:[AIListContact class]]);
-
-	[self addParticipatingListObject:(AIListContact *)inObject notify:YES];
-	return YES;
-}
-
-// Invite a list object to join the chat. Returns YES if the chat joins, NO otherwise
-- (BOOL)inviteListContact:(AIListContact *)inContact withMessage:(NSString *)inviteMessage
-{
-	return ([self.account inviteContact:inContact toChat:self withMessage:inviteMessage]);
-}
-
 @synthesize preferredListObject = preferredContact;
 
-//If this chat only has one participating list object, it is returned.  Otherwise, nil is returned
-- (AIListContact *)listObject
-{
-	if (self.countOfContainedObjects == 1 && !self.isGroupChat) {
-		return (AIListContact *)[self visibleObjectAtIndex:0];
-	}
-
-	return nil;
-}
-
 - (void)setListObject:(AIListContact *)inListObject
 {
 	if (inListObject != self.listObject) {
-		if (self.countOfContainedObjects) {
-			[participatingContacts removeObjectAtIndex:0];
-		}
-		[self addParticipatingListObject:inListObject notify:YES];
-
+        [_listObject release];
+        _listObject = [inListObject retain];
+        
 		//Clear any local caches relying on the list object
 		[self clearListObjectStatuses];
 		[self clearUniqueChatID];
@@ -495,11 +307,7 @@
 - (NSString *)uniqueChatID
 {
 	if (!uniqueChatID) {
-		if (self.isGroupChat) {
-			uniqueChatID = [[NSString alloc] initWithFormat:@"%@.%i", self.name, nextChatNumber++];
-		} else {			
-			uniqueChatID = [self.listObject.internalObjectID retain];
-		}
+        uniqueChatID = [self.listObject.internalObjectID retain];
 
 		if (!uniqueChatID) {
 			uniqueChatID = [[NSString alloc] initWithFormat:@"UnknownChat.%i", nextChatNumber++];
@@ -524,8 +332,6 @@
 //Content --------------------------------------------------------------------------------------------------------------
 #pragma mark Content
 
- at synthesize lastMessageDate;
-
 /*!
  * @brief Informs the chat that the core and the account are ready to begin filtering and sending a content object
  *
@@ -568,33 +374,23 @@
 - (AIChatSendingAbilityType)messageSendingAbility
 {
 	AIChatSendingAbilityType sendingAbilityType;
-
-	if (self.isGroupChat) {
-		if (self.account.online) {
-			//XXX Liar!
-			sendingAbilityType = AIChatCanSendMessageNow;
-		} else {
-			sendingAbilityType = AIChatCanNotSendMessage;
-		}
-
-	} else {
-		if (self.account.online) {
-			AIListContact *listObject = self.listObject;
-			
-			if (listObject.online || listObject.isStranger) {
-				sendingAbilityType = AIChatCanSendMessageNow;
-			} else if ([self.account canSendOfflineMessageToContact:listObject]) {
-				sendingAbilityType = AIChatCanSendViaServersideOfflineMessage;				
-			} else if ([self.account maySendMessageToInvisibleContact:listObject]) {
-				sendingAbilityType = AIChatMayNotBeAbleToSendMessage;	
-			} else {
-				sendingAbilityType = AIChatCanNotSendMessage;
-			}
-
-		} else {
-			sendingAbilityType = AIChatCanNotSendMessage;
-		}		
-	}
+    
+    if (self.account.online) {
+        AIListContact *listObject = self.listObject;
+        
+        if (listObject.online || listObject.isStranger) {
+            sendingAbilityType = AIChatCanSendMessageNow;
+        } else if ([self.account canSendOfflineMessageToContact:listObject]) {
+            sendingAbilityType = AIChatCanSendViaServersideOfflineMessage;
+        } else if ([self.account maySendMessageToInvisibleContact:listObject]) {
+            sendingAbilityType = AIChatMayNotBeAbleToSendMessage;
+        } else {
+            sendingAbilityType = AIChatCanNotSendMessage;
+        }
+        
+    } else {
+        sendingAbilityType = AIChatCanNotSendMessage;
+    }
 	
 	return sendingAbilityType;
 }
@@ -651,128 +447,6 @@
 	return shouldLog;
 }
 
-#pragma mark AIContainingObject protocol
-- (NSArray *)visibleContainedObjects
-{
-	return self.containedObjects;
-}
-- (NSArray *)containedObjects
-{
-	return participatingContacts;
-}
-- (NSUInteger)countOfContainedObjects
-{
-	return [participatingContacts count];
-}
-
-- (BOOL)containsObject:(AIListObject *)inObject
-{
-	return [participatingContacts containsObjectIdenticalTo:inObject];
-}
-
-- (AIListContact *)visibleObjectAtIndex:(NSUInteger)idx
-{
-	return [participatingContacts objectAtIndex:idx];
-}
-
-- (NSUInteger)visibleIndexOfObject:(AIListObject *)obj
-{
-	if(![[AIContactHidingController sharedController] visibilityOfListObject:obj inContainer:self])
-		return NSNotFound;
-	return [participatingContacts indexOfObject:obj];
-}
-
-//Retrieve a specific object by service and UID
-- (AIListObject *)objectWithService:(AIService *)inService UID:(NSString *)inUID
-{
-	for (AIListContact *object in self) {
-		if ([inUID isEqualToString:object.UID] && object.service == inService)
-			return object;
-	}
-	
-	return nil;
-}
-
-- (NSArray *)uniqueContainedObjects
-{
-	return self.containedObjects;
-}
-
-- (void)removeObject:(AIListObject *)inObject
-{
-	if ([self containsObject:inObject]) {
-		AIListContact *contact = (AIListContact *)inObject; //if we contain it, it has to be an AIListContact
-		
-		//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];
-	}
-}
-
-- (void)removeObjectAfterAccountStopsTracking:(AIListObject *)object
-{
-	[self removeObject:object]; //does nothing if we've already removed it
-}
-
-- (void)removeAllParticipatingContactsSilently
-{
-	/* Note that allGroupChatsContainingContact won't count this chat if it's already marked as not open */
-	for (AIListContact *listContact in self) {
-		if (listContact.isStranger &&
-			![adium.chatController existingChatWithContact:listContact.parentContact] &&
-			([adium.chatController allGroupChatsContainingContact:listContact.parentContact].count == 0)) {
-			[adium.contactController accountDidStopTrackingContact:listContact];
-		}
-	}
-
-	[participatingContacts removeAllObjects];
-	[participatingContactsFlags removeAllObjects];
-	[participatingContactsAliases removeAllObjects];
-
-	[[NSNotificationCenter defaultCenter] postNotificationName:Chat_ParticipatingListObjectsChanged
-											  object:self];
-}
-
- at synthesize expanded;
-
-- (BOOL)isExpandable
-{
-	return NO;
-}
-
-- (NSUInteger)visibleCount
-{
-	return self.countOfContainedObjects;
-}
-
-- (NSString *)contentsBasedIdentifier
-{
-	return [NSString stringWithFormat:@"%@-%@.%@",self.name, self.account.service.serviceID, self.account.UID];
-}
-
-//Not used
-- (float)smallestOrder { return 0; }
-- (float)largestOrder { return 1E10f; }
-- (float)orderIndexForObject:(AIListObject *)listObject { return 0; }
-- (void)listObject:(AIListObject *)listObject didSetOrderIndex:(float)inOrderIndex {};
-
-
 #pragma mark Ignoring
 /*!
  * @brief Set the ignored state of a contact
@@ -827,62 +501,6 @@
 		(uniqueChatID ? uniqueChatID : @"<new>")];
 }
 
-#pragma mark Group Chats
-
- at synthesize isGroupChat, showJoinLeave, hideUserIconAndStatus;
-
-/*!
- * @brief Does this chat support topics?
- */
-- (BOOL)supportsTopic
-{
-	return account.groupChatsSupportTopic;
-}
-
-/*!
- * @brief Update the topic.
- */
-- (void)updateTopic:(NSString *)inTopic withSource:(AIListContact *)contact
-{
-	[self setValue:inTopic forProperty:KEY_TOPIC notify:NotifyNow];
-	
-	[self setValue:contact forProperty:KEY_TOPIC_SETTER notify:NotifyNow];
-	
-	// Apply the new topic to the message view
-	AIContentTopic *contentTopic = [AIContentTopic topicInChat:self
-													withSource:contact
-												   destination:nil
-														  date:[NSDate date]
-													   message:[NSAttributedString stringWithString:[self valueForProperty:KEY_TOPIC] ?: @""]];
-	
-	// The content controller has huge problems with blank messages being let through.
-	if (![[self valueForProperty:KEY_TOPIC] length]) {
-		contentTopic.message = CONTENT_TOPIC_MESSAGE_ACTUALLY_EMPTY;
-		contentTopic.actuallyBlank = YES;
-	}
-	
-	[adium.contentController receiveContentObject:contentTopic];
-}
-
-/*!
- * @brief Set the chat's topic, telling the account to update it.
- */
-- (void)setTopic:(NSString *)inTopic
-{
-	if (self.supportsTopic) {
-		// We mess with the topic, replacing nbsp with spaces; make sure we're not setting an identical one other than this.
-		NSString *tempTopic = [[self valueForProperty:KEY_TOPIC] stringByReplacingOccurrencesOfString:@"\u00A0" withString:@" "];
-		if ([tempTopic isEqualToString:inTopic]) {
-			AILogWithSignature(@"Not setting topic for %@, already the same.", self);
-		} else {
-			AILogWithSignature(@"Setting %@ topic to: %@", self, [self valueForProperty:KEY_TOPIC]);
-			[account setTopic:inTopic forChat:self];
-		}
-	} else {
-		AILogWithSignature(@"Attempt to topic when account doesn't support it.");
-	}
-}
-
 #pragma mark Custom emoticons
 
 - (void)addCustomEmoticon:(AIEmoticon *)inEmoticon
@@ -1033,20 +651,20 @@
 	//Send any file we were told to send to every participating list object (anyone remember the AOL mass mailing zareW scene?)
 	if (fileURL && fileURL.path.length) {
 		
-		for (AIListContact *listContact in self) {
+        for (AIListContact *listContact in self.containedObjects) {
 			AIListContact   *targetFileTransferContact;
 			
 			//Make sure we know where we are sending the file by finding the best contact for
 			//sending CONTENT_FILE_TRANSFER_TYPE.
 			if ((targetFileTransferContact = [adium.contactController preferredContactForContentType:CONTENT_FILE_TRANSFER_TYPE
-																						forListContact:listContact])) {
+                                                                                      forListContact:listContact])) {
 				[adium.fileTransferController sendFile:[fileURL path]
-										   toListContact:targetFileTransferContact];
+                                         toListContact:targetFileTransferContact];
 			} else {
-				AILogWithSignature(@"No contact available to receive files to %@", listContact);
+				AILogWithSignature(@"No contact available to receive files to %@", self.listObject);
 				NSBeep();
-			}
-		}
+            }
+        }
 	}
 	
 	return nil;
@@ -1061,15 +679,14 @@
 	return nil;
 }
 
-
-- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
+- (NSArray *)containedObjects
 {
-	return [self.containedObjects countByEnumeratingWithState:state objects:stackbuf count:len];
+    return [NSArray arrayWithObject:self.listObject];
 }
 
-- (BOOL) canContainObject:(id)obj
+- (BOOL)isGroupChat
 {
-	return [obj isKindOfClass:[AIListContact class]];
+    return NO;
 }
 
 @end
diff -r 960761c3597b -r 2a996beac083 Frameworks/Adium Framework/Source/AIChatControllerProtocol.h
--- a/Frameworks/Adium Framework/Source/AIChatControllerProtocol.h	Sun Oct 21 20:07:44 2012 +0200
+++ b/Frameworks/Adium Framework/Source/AIChatControllerProtocol.h	Sun Oct 21 23:59:42 2012 +0200
@@ -15,6 +15,7 @@
  */
 
 #import <Adium/AIControllerProtocol.h>
+#import <Adium/AIGroupChat.h>
 
 @protocol AIChatController_Private;
 @class AIChat, AIAccount, AIListContact;
@@ -32,13 +33,13 @@
 - (AIChat *)chatWithContact:(AIListContact *)inContact;
 - (AIChat *)existingChatWithContact:(AIListContact *)inContact;
 - (AIChat *)existingChatWithUniqueChatID:(NSString *)uniqueChatID;
-- (AIChat *)chatWithName:(NSString *)inName 
+- (AIGroupChat *)chatWithName:(NSString *)inName 
 			  identifier:(id)identifier
 			   onAccount:(AIAccount *)account
 		chatCreationInfo:(NSDictionary *)chatCreationInfo;
 
-- (AIChat *)existingChatWithIdentifier:(id)identifier onAccount:(AIAccount *)account;
-- (AIChat *)existingChatWithName:(NSString *)name onAccount:(AIAccount *)account;
+- (AIGroupChat *)existingChatWithIdentifier:(id)identifier onAccount:(AIAccount *)account;
+- (AIGroupChat *)existingChatWithName:(NSString *)name onAccount:(AIAccount *)account;
 
 - (BOOL)closeChat:(AIChat *)inChat;
 - (void)accountDidCloseChat:(AIChat *)inChat;
diff -r 960761c3597b -r 2a996beac083 Frameworks/Adium Framework/Source/AIContentMessage.m
--- a/Frameworks/Adium Framework/Source/AIContentMessage.m	Sun Oct 21 20:07:44 2012 +0200
+++ b/Frameworks/Adium Framework/Source/AIContentMessage.m	Sun Oct 21 23:59:42 2012 +0200
@@ -19,6 +19,7 @@
 #import <Adium/AIContentObject.h>
 #import <Adium/AIListContact.h>
 #import <Adium/AIChat.h>
+#import <Adium/AIGroupChat.h>
 
 @implementation AIContentMessage
 
@@ -77,7 +78,7 @@
 	[classes addObject:@"message"];
 	if(isAutoreply) [classes addObject:@"autoreply"];
 	if(self.chat.isGroupChat) {
-		AIGroupChatFlags flags = [self.chat flagsForContact:(AIListContact *)self.source];
+		AIGroupChatFlags flags = [(AIGroupChat *)self.chat flagsForContact:(AIListContact *)self.source];
 		if (flags & AIGroupChatOp)
 			[classes addObject:@"op"];
 		if (flags & AIGroupChatHalfOp)
@@ -92,7 +93,9 @@
 
 - (NSString *)senderPrefix
 {
-	AIGroupChatFlags flags = [self.chat flagsForContact:(AIListContact *)self.source];
+    if (!self.chat.isGroupChat) return @"";
+    
+	AIGroupChatFlags flags = [(AIGroupChat *)self.chat flagsForContact:(AIListContact *)self.source];
 	
 	if ((flags & AIGroupChatFounder) == AIGroupChatFounder) {
 		return @"~";
diff -r 960761c3597b -r 2a996beac083 Frameworks/Adium Framework/Source/AIGroupChat.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/Adium Framework/Source/AIGroupChat.h	Sun Oct 21 23:59:42 2012 +0200
@@ -0,0 +1,53 @@
+//
+//  AIGroupChat.h
+//  Adium
+//
+//  Created by Thijs Alkemade on 21-10-12.
+//  Copyright (c) 2012 The Adium Team. All rights reserved.
+//
+
+#import "AIChat.h"
+
+ at interface AIGroupChat : AIChat <AIContainingObject> {
+	NSString			*topic;
+    AIListContact		*topicSetter;
+	
+	NSMutableDictionary	*participatingContactsFlags;
+	NSMutableDictionary	*participatingContactsAliases;
+	NSMutableArray		*participatingContacts;
+	
+	BOOL				hideUserIconAndStatus;
+	BOOL				showJoinLeave;
+	BOOL				expanded;
+    
+	NSDate				*lastMessageDate;
+}
+
+ at property (readwrite, nonatomic) BOOL showJoinLeave;
+
+ at property (readwrite, nonatomic) BOOL hideUserIconAndStatus;
+ at property (readonly, nonatomic) BOOL supportsTopic;
+
+- (void)updateTopic:(NSString *)inTopic withSource:(AIListContact *)contact;
+- (void)setTopic:(NSString *)inTopic;
+
+ at 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;
+
+- (void)addParticipatingListObject:(AIListContact *)inObject notify:(BOOL)notify;
+- (void)addParticipatingListObjects:(NSArray *)inObjects notify:(BOOL)notify;
+- (void)removeAllParticipatingContactsSilently;
+- (void)removeObject:(AIListObject *)inObject;
+
+- (BOOL)inviteListContact:(AIListContact *)inObject withMessage:(NSString *)inviteMessage;
+
+- (void)resortParticipants;
+
+ at end
diff -r 960761c3597b -r 2a996beac083 Frameworks/Adium Framework/Source/AIGroupChat.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Frameworks/Adium Framework/Source/AIGroupChat.m	Sun Oct 21 23:59:42 2012 +0200
@@ -0,0 +1,497 @@
+//
+//  AIGroupChat.m
+//  Adium
+//
+//  Created by Thijs Alkemade on 21-10-12.
+//  Copyright (c) 2012 The Adium Team. All rights reserved.
+//
+
+#import "AIGroupChat.h"
+#import "AIContactControllerProtocol.h"
+#import "AIListContact.h"
+#import "AIListObject.h"
+#import "AIServiceIcons.h"
+#import "AIUserIcons.h"
+#import "AIContentTopic.h"
+#import "AIContentControllerProtocol.h"
+#import "AIAttributedStringAdditions.h"
+#import "AIChatControllerProtocol.h"
+#import "AIContactObserverManager.h"
+#import "AIContactHidingController.h"
+#import "AIArrayAdditions.h"
+#import "AIService.h"
+
+ at interface AIGroupChat ()
+
+- (void)contentObjectAdded:(NSNotification *)notification;
+- (AIListContact *)visibleObjectAtIndex:(NSUInteger)idx;
+
+ at end
+
+ at implementation AIGroupChat
+
+static int nextChatNumber = 0;
+
+ at synthesize lastMessageDate, showJoinLeave, hideUserIconAndStatus;
+
+- (id)initForAccount:(AIAccount *)inAccount
+{
+    if ((self = [super initForAccount:inAccount])) {
+        showJoinLeave = YES;
+		expanded = YES;
+        participatingContacts = [[NSMutableArray alloc] init];
+		participatingContactsFlags = [[NSMutableDictionary alloc] init];
+		participatingContactsAliases = [[NSMutableDictionary alloc] init];
+
+        
+		[[NSNotificationCenter defaultCenter] addObserver:self
+												 selector:@selector(contentObjectAdded:)
+													 name:Content_ContentObjectAdded
+												   object:self];
+    }
+    
+    return self;
+}
+
+- (void)dealloc
+{
+	[topic release]; [topicSetter release];
+    
+	[self removeAllParticipatingContactsSilently];
+    
+    [lastMessageDate release];
+	[participatingContacts release];
+	[participatingContactsFlags release];
+	[participatingContactsAliases release];
+    
+    [super dealloc];
+}
+
+- (NSImage *)chatImage
+{
+    AIListContact 	*listObject = nil;
+	NSImage			*image = nil;
+    
+    listObject = (AIListContact *)[adium.contactController existingBookmarkForChat:self];
+    
+	if (listObject) {
+		image = listObject.parentContact.userIcon;
+		if (!image) image = [AIServiceIcons serviceIconForObject:listObject type:AIServiceIconLarge direction:AIIconNormal];
+	} else {
+		image = [AIServiceIcons serviceIconForObject:self.account type:AIServiceIconLarge direction:AIIconNormal];
+	}
+    
+	return image;
+}
+
+//lil image
+- (NSImage *)chatMenuImage
+{
+	AIListObject 	*listObject = nil;
+	NSImage			*chatMenuImage = nil;
+	
+	listObject = (AIListContact *)[adium.contactController existingBookmarkForChat:self];




More information about the commits mailing list