adium 2128:9992255c5007: Contact list support for moving contact...

commits at adium.im commits at adium.im
Sun May 10 19:37:37 UTC 2009


details:	http://hg.adium.im/adium/rev/9992255c5007
revision:	2128:9992255c5007
author:		Zachary West <zacw at adium.im>
date:		Sun May 10 15:36:59 2009 -0400

Contact list support for moving contacts in multiple groups.

This changes the cursor for meta-contact-combine to NSDragOperationLink and reappropriates NSDragOperationCopy as the "copy into this group". Copying into a group uses the option key as a modifier, like Finder.

Dragging a contact into a group it already is contained in just removes the group it was dragged from.

Refs #11930.

diffstat:

 Frameworks/Adium Framework/Source/AIAccount.h                   |   2 +-
 Frameworks/Adium Framework/Source/AIAccount.m                   |   5 +-
 Frameworks/Adium Framework/Source/AIContactControllerProtocol.h |   4 +-
 Frameworks/Adium Framework/Source/AIListBookmark.m              |   2 +-
 Frameworks/Adium Framework/Source/AIListContact.m               |   2 +-
 Frameworks/Adium Framework/Source/AIMetaContact.m               |   4 +-
 Plugins/Bonjour/AWBonjourAccount.m                              |   2 +-
 Plugins/Purple Service/CBPurpleAccount.m                        |  31 +++-
 Plugins/Purple Service/ESPurpleGaduGaduAccount.m                |   2 +-
 Plugins/Purple Service/SLPurpleCocoaAdapter.h                   |   2 +-
 Plugins/Purple Service/SLPurpleCocoaAdapter.m                   |  77 ++++--------
 Plugins/Twitter Plugin/AITwitterAccount.m                       |   4 +-
 Source/AIAddBookmarkPlugin.m                                    |   2 +-
 Source/AIAdvancedInspectorPane.m                                |   3 +-
 Source/AIContactController.m                                    |  16 +-
 Source/AIListController.m                                       |  21 ++-
 16 files changed, 86 insertions(+), 93 deletions(-)

diffs (460 lines):

diff -r 73741974b435 -r 9992255c5007 Frameworks/Adium Framework/Source/AIAccount.h
--- a/Frameworks/Adium Framework/Source/AIAccount.h	Sat May 09 00:16:18 2009 -0400
+++ b/Frameworks/Adium Framework/Source/AIAccount.h	Sun May 10 15:36:59 2009 -0400
@@ -241,7 +241,7 @@
 - (void)addContact:(AIListContact *)contact toGroup:(AIListGroup *)group;
 - (void)removeContacts:(NSArray *)objects;
 - (void)deleteGroup:(AIListGroup *)group;
-- (void)moveListObjects:(NSArray *)objects toGroups:(NSSet *)groups;
+- (void)moveListObjects:(NSArray *)objects fromGroups:(NSSet *)oldGroups toGroups:(NSSet *)groups;
 - (void)renameGroup:(AIListGroup *)group to:(NSString *)newName;
 - (BOOL)isContactIntentionallyListed:(AIListContact *)contact;
 
diff -r 73741974b435 -r 9992255c5007 Frameworks/Adium Framework/Source/AIAccount.m
--- a/Frameworks/Adium Framework/Source/AIAccount.m	Sat May 09 00:16:18 2009 -0400
+++ b/Frameworks/Adium Framework/Source/AIAccount.m	Sun May 10 15:36:59 2009 -0400
@@ -753,9 +753,10 @@
  * Move existing contacts to a specific group on this account.  The passed contacts should already exist somewhere on
  * this account.
  * @param objects NSArray of AIListContact objects to remove
- * @param group AIListGroup destination for contacts
+ * @param oldGroups NSSet of AIListGroup source for contacts
+ * @param group NSSet of AIListGroup destination for contacts
  */
-- (void)moveListObjects:(NSArray *)objects toGroups:(NSSet *)groups
+- (void)moveListObjects:(NSArray *)objects fromGroups:(NSSet *)oldGroups toGroups:(NSSet *)groups
 {
 	NSAssert(NO, @"Should not be reached");
 }
diff -r 73741974b435 -r 9992255c5007 Frameworks/Adium Framework/Source/AIContactControllerProtocol.h
--- a/Frameworks/Adium Framework/Source/AIContactControllerProtocol.h	Sat May 09 00:16:18 2009 -0400
+++ b/Frameworks/Adium Framework/Source/AIContactControllerProtocol.h	Sun May 10 15:36:59 2009 -0400
@@ -115,8 +115,8 @@
 - (void)explodeMetaContact:(AIMetaContact *)metaContact; //Unpack contained contacts and then remove the meta
 - (void)removeListGroup:(AIListGroup *)listGroup;
 - (void)requestAddContactWithUID:(NSString *)contactUID service:(AIService *)inService account:(AIAccount *)inAccount;
-- (void)moveContact:(AIListObject *)listContact intoGroups:(NSSet *)containers;
-- (void)_moveContactLocally:(AIListContact *)listContact toGroups:(NSSet *)groups;
+- (void)moveContact:(AIListObject *)listContact fromGroups:(NSSet *)oldGroups intoGroups:(NSSet *)groups;
+- (void)_moveContactLocally:(AIListContact *)listContact fromGroups:(NSSet *)oldGroups toGroups:(NSSet *)groups;
 @property (readonly, nonatomic) BOOL useContactListGroups;
 
 //For Accounts
diff -r 73741974b435 -r 9992255c5007 Frameworks/Adium Framework/Source/AIListBookmark.m
--- a/Frameworks/Adium Framework/Source/AIListBookmark.m	Sat May 09 00:16:18 2009 -0400
+++ b/Frameworks/Adium Framework/Source/AIListBookmark.m	Sun May 10 15:36:59 2009 -0400
@@ -226,7 +226,7 @@
 		targetGroup = [NSSet setWithObject:adium.contactController.contactList];
 	}
 
-	[adium.contactController moveContact:self intoGroups:targetGroup];
+	[adium.contactController moveContact:self fromGroups:self.groups intoGroups:targetGroup];
 }
 
 /*!
diff -r 73741974b435 -r 9992255c5007 Frameworks/Adium Framework/Source/AIListContact.m
--- a/Frameworks/Adium Framework/Source/AIListContact.m	Sat May 09 00:16:18 2009 -0400
+++ b/Frameworks/Adium Framework/Source/AIListContact.m	Sun May 10 15:36:59 2009 -0400
@@ -207,7 +207,7 @@
 		
 		[groups addObject:localGroup];
 	}
-	[adium.contactController _moveContactLocally:self toGroups:groups];
+	[adium.contactController _moveContactLocally:self fromGroups:self.groups toGroups:groups];
 }
 
 #pragma mark Names
diff -r 73741974b435 -r 9992255c5007 Frameworks/Adium Framework/Source/AIMetaContact.m
--- a/Frameworks/Adium Framework/Source/AIMetaContact.m	Sat May 09 00:16:18 2009 -0400
+++ b/Frameworks/Adium Framework/Source/AIMetaContact.m	Sun May 10 15:36:59 2009 -0400
@@ -157,7 +157,7 @@
 		[targetGroups addObject:adium.contactController.contactList];
 	}
 
-	[adium.contactController _moveContactLocally:self toGroups:targetGroups];
+	[adium.contactController _moveContactLocally:self fromGroups:self.groups toGroups:targetGroups];
 }
 
 - (void) removeFromList
@@ -343,7 +343,7 @@
 
 	//If we remove our list object, don't continue to show up in the contact list
 	if (self.countOfContainedObjects == 0)
-		[adium.contactController _moveContactLocally:self toGroups:[NSSet set]];
+		[adium.contactController _moveContactLocally:self fromGroups:self.groups toGroups:[NSSet set]];
 	
 	[contact release];
 }
diff -r 73741974b435 -r 9992255c5007 Plugins/Bonjour/AWBonjourAccount.m
--- a/Plugins/Bonjour/AWBonjourAccount.m	Sat May 09 00:16:18 2009 -0400
+++ b/Plugins/Bonjour/AWBonjourAccount.m	Sun May 10 15:36:59 2009 -0400
@@ -116,7 +116,7 @@
 
 }
 
-- (void)moveListObjects:(NSArray *)objects toGroups:(NSSet *)groups
+- (void)moveListObjects:(NSArray *)objects fromGroups:(NSSet *)oldGroups toGroups:(NSSet *)groups
 {
 	//XXX does bonjour support groups?
 }
diff -r 73741974b435 -r 9992255c5007 Plugins/Purple Service/CBPurpleAccount.m
--- a/Plugins/Purple Service/CBPurpleAccount.m	Sat May 09 00:16:18 2009 -0400
+++ b/Plugins/Purple Service/CBPurpleAccount.m	Sun May 10 15:36:59 2009 -0400
@@ -637,23 +637,34 @@
 	return object.UID;
 }
 
-- (void)moveListObjects:(NSArray *)objects toGroups:(NSSet *)groups
+- (NSSet *)mappedGroupNamesFromGroups:(NSSet *)groups
 {
-	NSMutableSet *groupNames = [NSMutableSet set];
-	NSMutableSet *mappedGroupNames = [NSMutableSet set];
-	for (AIListGroup* group in groups)
-	{
-		[groupNames addObject:group.UID];
-		[mappedGroupNames addObject:[self _mapOutgoingGroupName:group.UID]];
+	NSMutableSet *mappedNames = [NSMutableSet set];
+	
+	for (AIListGroup *group in groups) {
+		[mappedNames addObject:[self _mapOutgoingGroupName:group.UID]];
 	}
 	
+	return mappedNames;
+}
+
+- (void)moveListObjects:(NSArray *)objects fromGroups:(NSSet *)oldGroups toGroups:(NSSet *)groups
+{
+	NSSet *sourceMappedNames = [self mappedGroupNamesFromGroups:oldGroups];
+	NSSet *destinationMappedNames = [self mappedGroupNamesFromGroups:groups];
+
 	//Move the objects to it
 	for (AIListContact *contact in objects) {
 		//Tell the purple thread to perform the serverside operation
-		[purpleAdapter moveUID:contact.UID onAccount:self toGroups:mappedGroupNames];
+		[purpleAdapter moveUID:contact.UID onAccount:self fromGroups:sourceMappedNames toGroups:destinationMappedNames];
 
-		//Use the non-mapped group name locally
-		[contact setRemoteGroupNames:groupNames];
+		for (AIListGroup *group in oldGroups) {
+			[contact removeRemoteGroupName:group.UID];
+		}
+		
+		for (AIListGroup *group in groups) {
+			[contact addRemoteGroupName:group.UID];
+		}
 	}		
 }
 
diff -r 73741974b435 -r 9992255c5007 Plugins/Purple Service/ESPurpleGaduGaduAccount.m
--- a/Plugins/Purple Service/ESPurpleGaduGaduAccount.m	Sat May 09 00:16:18 2009 -0400
+++ b/Plugins/Purple Service/ESPurpleGaduGaduAccount.m	Sun May 10 15:36:59 2009 -0400
@@ -78,7 +78,7 @@
 
 - (void)moveListObjects:(NSArray *)objects toGroups:(NSSet *)groups
 {
-	[super moveListObjects:objects toGroups:groups];
+	[super moveListObjects:objects fromGroups:[NSSet set] toGroups:groups];
 	
 	[self uploadContactListToServer];
 }
diff -r 73741974b435 -r 9992255c5007 Plugins/Purple Service/SLPurpleCocoaAdapter.h
--- a/Plugins/Purple Service/SLPurpleCocoaAdapter.h	Sat May 09 00:16:18 2009 -0400
+++ b/Plugins/Purple Service/SLPurpleCocoaAdapter.h	Sun May 10 15:36:59 2009 -0400
@@ -52,7 +52,7 @@
 
 - (void)addUID:(NSString *)objectUID onAccount:(id)adiumAccount toGroup:(NSString *)groupName;
 - (void)removeUID:(NSString *)objectUID onAccount:(id)adiumAccount fromGroup:(NSString *)groupName;
-- (void)moveUID:(NSString *)objectUID onAccount:(id)adiumAccount toGroups:(NSSet *)groupNames;
+- (void)moveUID:(NSString *)objectUID onAccount:(id)adiumAccount fromGroups:(NSSet *)groupNames toGroups:(NSSet *)groupNames;
 - (void)renameGroup:(NSString *)oldGroupName onAccount:(id)adiumAccount to:(NSString *)newGroupName;
 - (void)deleteGroup:(NSString *)groupName onAccount:(id)adiumAccount;
 
diff -r 73741974b435 -r 9992255c5007 Plugins/Purple Service/SLPurpleCocoaAdapter.m
--- a/Plugins/Purple Service/SLPurpleCocoaAdapter.m	Sat May 09 00:16:18 2009 -0400
+++ b/Plugins/Purple Service/SLPurpleCocoaAdapter.m	Sun May 10 15:36:59 2009 -0400
@@ -967,9 +967,10 @@
 		purple_blist_add_group(group, NULL);
 	}
 	
-	//Find the buddy (Create if necessary)
 	buddyUTF8String = [objectUID UTF8String];
-	buddy = purple_find_buddy(account, buddyUTF8String);
+	
+	// Find an existing buddy in the group.
+	buddy = purple_find_buddy_in_group(account, buddyUTF8String, group);
 	if (!buddy) buddy = purple_buddy_new(account, buddyUTF8String, NULL);
 
 	AILog(@"Adding buddy %s to group %s",purple_buddy_get_name(buddy), group->name);
@@ -983,70 +984,46 @@
 
 - (void)removeUID:(NSString *)objectUID onAccount:(id)adiumAccount fromGroup:(NSString *)groupName
 {
-	PurpleAccount *account = accountLookupFromAdiumAccount(adiumAccount);
-	PurpleBuddy 	*buddy;
+	const char	*groupUTF8String;
+	PurpleGroup	*group;
 	
-	if ((buddy = purple_find_buddy(account, [objectUID UTF8String]))) {
-		const char	*groupUTF8String;
-		PurpleGroup	*group;
-
-		groupUTF8String = (groupName ? [groupName UTF8String] : "Buddies");
-		if ((group = purple_find_group(groupUTF8String))) {
+	// Find the right buddy; group -> buddy in group -> remove that buddy
+	
+	groupUTF8String = (groupName ? [groupName UTF8String] : "Buddies");
+	if ((group = purple_find_group(groupUTF8String))) {
+		PurpleAccount *account = accountLookupFromAdiumAccount(adiumAccount);
+		PurpleBuddy 	*buddy;
+		
+		if ((buddy = purple_find_buddy_in_group(account, [objectUID UTF8String], group))) {
 			/* Remove this contact from the server-side and purple-side lists. 
 			 * Updating purpleside does not change the server.
 			 *
 			 * Purple has a commented XXX as to whether this order or the reverse (blist, then serv) is correct.
 			 * We'll use the order which purple uses as of purple 1.1.4. */
+			
+			AILog(@"Removing buddy %s from group %s", purple_buddy_get_name(buddy), purple_group_get_name(purple_buddy_get_group(buddy)));
+			
 			purple_account_remove_buddy(account, buddy, group);
 			purple_blist_remove_buddy(buddy);
 		}
 	}
 }
 
-- (void)moveUID:(NSString *)objectUID onAccount:(id)adiumAccount toGroups:(NSSet *)groupNames;
+- (void)moveUID:(NSString *)objectUID onAccount:(id)adiumAccount fromGroups:(NSSet *)oldGroups toGroups:(NSSet *)groupNames;
 {
-	PurpleAccount *account;
-	PurpleBuddy	*buddy;
-	PurpleGroup 	*group;
-	const char	*buddyUTF8String;
-	const char	*groupUTF8String;
-
-	account = accountLookupFromAdiumAccount(adiumAccount);
-
 	for (NSString *groupName in groupNames) {
-		//Get the destination group (creating if necessary)
-		groupUTF8String = (groupName ? [groupName UTF8String] : "Buddies");
-		group = purple_find_group(groupUTF8String);
-		if (!group) {
-			/* If we can't find the group, something's gone wrong... we shouldn't be using a group we don't have.
-			 * We'll just silently turn this into an add operation. */
-			group = purple_group_new(groupUTF8String);
-			purple_blist_add_group(group, NULL);
+		if (!oldGroups.count) {
+			// If we don't have any source groups, silently turn this into an add.
+			[self addUID:objectUID onAccount:adiumAccount toGroup:groupName];
+			continue;
 		}
 		
-		buddyUTF8String = [objectUID UTF8String];
-		/* If we support contacts in multiple groups at once this should change */
-		GSList *buddies = purple_find_buddies(account, buddyUTF8String);
-		
-		if (buddies) {
-			GSList *cur;
-			for (cur = buddies; cur; cur = cur->next) {
-				/* purple_blist_add_buddy() will update the local list and perform a serverside move as necessary */
-				purple_blist_add_buddy(cur->data, NULL, group, NULL);			
-			}
-			g_slist_free(buddies);
-			
-		} else {
-			/* If we can't find a buddy, something's gone wrong... we shouldn't be moving a buddy we don't have.
-			 * As with the group, we'll just silently turn this into an add operation. */
-			buddy = purple_buddy_new(account, buddyUTF8String, NULL);
-			
-			/* purple_blist_add_buddy() will update the local list and perform a serverside move as necessary */
-			purple_blist_add_buddy(buddy, NULL, group, NULL);
-			
-			/* purple_blist_add_buddy() won't perform a serverside add, however.  Add if necessary. */
-			purple_account_add_buddy(account, buddy);
-			
+		for (NSString *sourceGroupName in oldGroups) {
+			// Add the contact to the new group; first so we don't cause a full removal
+			[self addUID:objectUID onAccount:adiumAccount toGroup:groupName];
+
+			// Remove the contact from the old group.
+			[self removeUID:objectUID onAccount:adiumAccount fromGroup:sourceGroupName];
 		}
 	}
 }
diff -r 73741974b435 -r 9992255c5007 Plugins/Twitter Plugin/AITwitterAccount.m
--- a/Plugins/Twitter Plugin/AITwitterAccount.m	Sat May 09 00:16:18 2009 -0400
+++ b/Plugins/Twitter Plugin/AITwitterAccount.m	Sun May 10 15:36:59 2009 -0400
@@ -208,7 +208,7 @@
 		
 		timelineBookmark = [adium.contactController bookmarkForChat:newTimelineChat];
 
-		[adium.contactController moveContact:timelineBookmark intoGroups:[NSSet setWithObject:[adium.contactController groupWithUID:TWITTER_REMOTE_GROUP_NAME]]];
+		[adium.contactController moveContact:timelineBookmark fromGroups:[NSSet set] intoGroups:[NSSet setWithObject:[adium.contactController groupWithUID:TWITTER_REMOTE_GROUP_NAME]]];
 	}
 	
 	NSTimeInterval updateInterval = [[self preferenceForKey:TWITTER_PREFERENCE_UPDATE_INTERVAL group:TWITTER_PREFERENCE_GROUP_UPDATES] intValue] * 60;
@@ -358,7 +358,7 @@
  * @param objects NSArray of AIListContact objects to remove
  * @param group AIListGroup destination for contacts
  */
-- (void)moveListObjects:(NSArray *)objects toGroups:(NSSet *)groups
+- (void)moveListObjects:(NSArray *)objects oldGroups:(NSSet *)oldGroups toGroups:(NSSet *)groups
 {
 	// XXX do twitter grouping
 }
diff -r 73741974b435 -r 9992255c5007 Source/AIAddBookmarkPlugin.m
--- a/Source/AIAddBookmarkPlugin.m	Sat May 09 00:16:18 2009 -0400
+++ b/Source/AIAddBookmarkPlugin.m	Sun May 10 15:36:59 2009 -0400
@@ -96,7 +96,7 @@
 	AIListBookmark *bookmark = [adium.contactController bookmarkForChat:chat];
 	[bookmark setDisplayName:name];
 	
-	[adium.contactController moveContact:bookmark intoGroups:[NSSet setWithObject:group]];
+	[adium.contactController moveContact:bookmark fromGroups:[NSSet set] intoGroups:[NSSet setWithObject:group]];
 }
 
 /*!
diff -r 73741974b435 -r 9992255c5007 Source/AIAdvancedInspectorPane.m
--- a/Source/AIAdvancedInspectorPane.m	Sat May 09 00:16:18 2009 -0400
+++ b/Source/AIAdvancedInspectorPane.m	Sun May 10 15:36:59 2009 -0400
@@ -416,7 +416,8 @@
 				if (![group.UID isEqualToString:exactContact.remoteGroupNames.anyObject]) {
 					if (exactContact.remoteGroupNames.anyObject) {
 						//Move contact
-						[adium.contactController moveContact:exactContact intoGroups:[NSSet setWithObject:group]];
+						// XXX Multiple containers
+						[adium.contactController moveContact:exactContact fromGroups:[NSSet set] intoGroups:[NSSet setWithObject:group]];
 
 					} else {						
 						[exactContact.account addContact:exactContact toGroup:group];
diff -r 73741974b435 -r 9992255c5007 Source/AIContactController.m
--- a/Source/AIContactController.m	Sat May 09 00:16:18 2009 -0400
+++ b/Source/AIContactController.m	Sun May 10 15:36:59 2009 -0400
@@ -309,7 +309,7 @@
 	[listContact release];
 }
 
-- (void)_moveContactLocally:(AIListContact *)listContact toGroups:(NSSet *)groups
+- (void)_moveContactLocally:(AIListContact *)listContact fromGroups:(NSSet *)oldGroups toGroups:(NSSet *)groups
 {
 	//Protect with a retain while we are removing and adding the contact to our arrays
 	[listContact retain];
@@ -317,7 +317,7 @@
 	[contactPropertiesObserverManager delayListObjectNotifications];
 	
 	//Remove this object from any local groups we have it in currently
-	for (AIListGroup *group in listContact.groups) {
+	for (AIListGroup *group in oldGroups) {
 		[group removeObject:listContact];
 		[self _didChangeContainer:group object:listContact];
 	}
@@ -645,7 +645,7 @@
 	BOOL								success;
 	
 	//Remove the object from its previous containing groups
-	[self _moveContactLocally:inContact toGroups:[NSSet set]];
+	[self _moveContactLocally:inContact fromGroups:inContact.groups toGroups:[NSSet set]];
 	
 	//AIMetaContact will handle reassigning the list object's grouping to being itself
 	if ((success = [metaContact addObject:inContact])) {
@@ -1252,7 +1252,7 @@
  */
 - (void)removeBookmark:(AIListBookmark *)listBookmark
 {
-	[self moveContact:listBookmark intoGroups:[NSSet set]];
+	[self moveContact:listBookmark fromGroups:listBookmark.groups intoGroups:[NSSet set]];
 	[bookmarkDict removeObjectForKey:listBookmark.internalObjectID];
 	
 	[self saveContactList];
@@ -1441,7 +1441,7 @@
 											userInfo:userInfo];
 }
 
-- (void)moveContact:(AIListContact *)contact intoGroups:(NSSet *)groups
+- (void)moveContact:(AIListContact *)contact fromGroups:(NSSet *)oldGroups intoGroups:(NSSet *)groups
 {
 	[contactPropertiesObserverManager delayListObjectNotifications];
 	if (contact.metaContact) {
@@ -1456,9 +1456,9 @@
 	
 	if (contact.existsServerside) {
 		if (contact.account.online)
-			[contact.account moveListObjects:[NSArray arrayWithObject:contact] toGroups:groups];
+			[contact.account moveListObjects:[NSArray arrayWithObject:contact] fromGroups:oldGroups toGroups:groups];
 	} else {
-		[self _moveContactLocally:contact toGroups:groups];
+		[self _moveContactLocally:contact fromGroups:oldGroups toGroups:groups];
 		
 		if ([contact conformsToProtocol:@protocol(AIContainingObject)]) {
 			id<AIContainingObject> container = (id<AIContainingObject>)contact;
@@ -1467,7 +1467,7 @@
 			for (AIListContact *child in container) {
 				//Only move the contact if it is actually listed on the account in question
 				if (child.account.online && !child.isStranger)
-					[child.account moveListObjects:[NSArray arrayWithObject:child] toGroups:groups];
+					[child.account moveListObjects:[NSArray arrayWithObject:child] fromGroups:oldGroups toGroups:groups];
 			}
 		}		
 	}
diff -r 73741974b435 -r 9992255c5007 Source/AIListController.m
--- a/Source/AIListController.m	Sat May 09 00:16:18 2009 -0400
+++ b/Source/AIListController.m	Sun May 10 15:36:59 2009 -0400
@@ -39,6 +39,7 @@
 #import <AIUtilities/AIOutlineViewAdditions.h>
 #import <AIUtilities/AIObjectAdditions.h>
 #import <AIUtilities/AIFunctions.h>
+#import <AIUtilities/AIEventAdditions.h>
 
 #define EDGE_CATCH_X						40.0f
 #define EDGE_CATCH_Y						40.0f
@@ -558,10 +559,10 @@
 
 		if ((index == NSOutlineViewDropOnItemIndex) && [proposedListObject isKindOfClass:[AIListContact class]] &&
 			([info draggingSource] == [self contactListView])) {
-			//Dropping into a contact or attaching groups: Copy
+			//Dropping into a contact or attaching groups: "link"
 			if (([contactListView rowForItem:primaryDragItem] == -1) ||
 				[primaryDragItem isKindOfClass:[AIListContact class]]) {
-				retVal = NSDragOperationCopy;
+				retVal = NSDragOperationLink;
 
 				if ([primaryDragItem isKindOfClass:[AIListContact class]] &&
 					[proposedListObject isKindOfClass:[AIListContact class]] &&
@@ -598,7 +599,7 @@
 
 				[outlineView setDropItem:item dropChildIndex:insertIndex];
 				
-				retVal = NSDragOperationPrivate;
+				retVal = ([NSEvent optionKey] ? NSDragOperationCopy : NSDragOperationPrivate);
 			} else {
 				// We can sort manually.
 				
@@ -617,7 +618,7 @@
 					}
 				}
 				
-				retVal = NSDragOperationPrivate;
+				retVal = ([NSEvent optionKey] ? NSDragOperationCopy : NSDragOperationPrivate);
 			}
 		} else {
 			retVal = NSDragOperationPrivate;
@@ -706,13 +707,15 @@
 					
 					NSAssert2([group canContainObject:listObject], @"BUG: Attempting to drop %@ into %@", listObject, group);
 					
-					if (![group containsObject:listObject]) {
+					// Allow a drag into a group already containing the list object
+					// if the group isn't containing -this- proxy.
+					if (!([group containsObject:listObject] && proxyObject.containingObject == group)) {
 						if([listObject isKindOfClass:[AIListContact class]]) {
 							// Contact being moved to a new group.
-							/* XXX This call needs to be moveContact:fromGroup:intoGroup: such that we remove it from
-							 * the originating group and send it to the right group, leaving other groups alone.
-							 */
-							[adium.contactController moveContact:(AIListContact *)listObject intoGroups:[NSSet setWithObject:group]];
+							// Holding option copies into the new group (like in Finder)
+							[adium.contactController moveContact:(AIListContact *)listObject
+													  fromGroups:([NSEvent optionKey] ? [NSSet set] : [NSSet setWithObject:proxyObject.containingObject])
+													  intoGroups:[NSSet setWithObject:group]];
 
 						} else if ([listObject isKindOfClass:[AIListGroup class]]) {							
 							// Group being moved to a new detached window.




More information about the commits mailing list