2 * Adium is the legal property of its developers, whose names are listed in the copyright file included
3 * with this source distribution.
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
10 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11 * Public License for more details.
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 #import <Adium/AIContactControllerProtocol.h>
18 #import "AIContactInfoWindowController.h"
19 #import "ESContactInfoListController.h"
20 #import <Adium/AIListGroup.h>
21 #import <Adium/AIListObject.h>
22 #import "AIListOutlineView.h"
23 #import <Adium/AIMetaContact.h>
25 @implementation ESContactInfoListController
27 //The superclass's implementation does not expand metaContacts
28 - (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
32 if ([contactList isKindOfClass:[AIMetaContact class]]) {
33 return ((index >= 0) && (index < [(AIMetaContact *)contactList uniqueContainedObjectsCount]) ?
34 [(AIMetaContact *)contactList uniqueObjectAtIndex:index] :
37 return ((index >= 0) && (index < [(AIListGroup *)contactList containedObjectsCount]) ?
38 [contactList objectAtIndex:index] :
45 if ([item isKindOfClass:[AIMetaContact class]]) {
46 return ((index >= 0) && (index < [(AIMetaContact *)item uniqueContainedObjectsCount]) ?
47 [(AIMetaContact *)item uniqueObjectAtIndex:index] :
50 return ((index >= 0) && (index < [(AIListGroup *)item containedObjectsCount]) ?
51 [item objectAtIndex:index] :
57 //The superclass's implementation does not expand metaContacts
58 - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
62 if ([contactList isKindOfClass:[AIMetaContact class]]) {
63 return [(AIMetaContact *)contactList uniqueContainedObjectsCount];
65 return [(AIListGroup *)contactList containedObjectsCount];
71 if ([item isKindOfClass:[AIMetaContact class]]) {
72 return [(AIMetaContact *)item uniqueContainedObjectsCount];
74 return [(AIListGroup *)item containedObjectsCount];
79 //The superclass's implementation does not expand metaContacts
80 - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
82 if ([item isKindOfClass:[AIMetaContact class]] || [item isKindOfClass:[AIListGroup class]]) {
90 * @brief Change the info window as the selection changes
92 * We want to configure for contact-specific information when a contact is selected in the drawer
93 * If no row is selected, we configure for the contactList root (the metaContact itself)
95 - (void)outlineViewSelectionDidChange:(NSNotification *)aNotification
97 if (!aNotification || [aNotification object] == contactListView) {
98 int selectedRow = [contactListView selectedRow];
100 [delegate contactInfoListControllerSelectionDidChangeToListObject:((selectedRow != -1) ?
101 [contactListView itemAtRow:selectedRow] :
107 * @brief Remove the selected rows from the metaContact
109 - (void)outlineViewDeleteSelectedRows:(NSOutlineView *)outlineView
111 [(AIContactInfoWindowController *)delegate removeContact:outlineView];
115 * @brief Validate a drag and drop operation
117 - (NSDragOperation)outlineView:(NSOutlineView*)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index
119 NSPasteboard *draggingPasteboard = [info draggingPasteboard];
120 NSString *avaliableType = [draggingPasteboard availableTypeFromArray:[NSArray arrayWithObject:@"AIListObject"]];
122 //No dropping into contacts
123 if ([avaliableType isEqualToString:@"AIListObject"]) {
125 id primaryDragItem = nil;
127 //If we don't have drag items, we are dragging from another instance; build our own dragItems array
128 //using the supplied internalObjectIDs
130 if ([[draggingPasteboard availableTypeFromArray:[NSArray arrayWithObject:@"AIListObjectUniqueIDs"]] isEqualToString:@"AIListObjectUniqueIDs"]) {
131 NSArray *dragItemsUniqueIDs;
132 NSMutableArray *arrayOfDragItems;
134 NSEnumerator *enumerator;
136 dragItemsUniqueIDs = [draggingPasteboard propertyListForType:@"AIListObjectUniqueIDs"];
137 arrayOfDragItems = [NSMutableArray array];
139 enumerator = [dragItemsUniqueIDs objectEnumerator];
140 while ((uniqueID = [enumerator nextObject])) {
141 [arrayOfDragItems addObject:[[adium contactController] existingListObjectWithUniqueID:uniqueID]];
144 //We will release this when the drag is completed
145 dragItems = [arrayOfDragItems retain];
149 primaryDragItem = [dragItems objectAtIndex:0];
151 if ([primaryDragItem isKindOfClass:[AIListGroup class]]) {
152 //Disallow dragging groups into the contact info window
153 return NSDragOperationNone;
156 //Disallow dragging contacts into anything besides the contact list
157 if (index == NSOutlineViewDropOnItemIndex) {
159 //The contactList is 'nil' to the outlineView
160 [outlineView setDropItem:nil dropChildIndex:[outlineView rowForItem:item]];
165 return NSDragOperationPrivate;
169 - (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index
171 NSPasteboard *draggingPasteboard = [info draggingPasteboard];
172 NSString *availableType = [draggingPasteboard availableTypeFromArray:[NSArray arrayWithObject:@"AIListObject"]];
174 //No longer in a drag, so allow tooltips again
175 if ([availableType isEqualToString:@"AIListObject"]) {
177 //If we don't have drag items, we are dragging from another instance; build our own dragItems array
178 //using the supplied internalObjectIDs
180 if ([[draggingPasteboard availableTypeFromArray:[NSArray arrayWithObject:@"AIListObjectUniqueIDs"]] isEqualToString:@"AIListObjectUniqueIDs"]) {
181 NSArray *dragItemsUniqueIDs;
182 NSMutableArray *arrayOfDragItems;
184 NSEnumerator *enumerator;
186 dragItemsUniqueIDs = [draggingPasteboard propertyListForType:@"AIListObjectUniqueIDs"];
187 arrayOfDragItems = [NSMutableArray array];
189 enumerator = [dragItemsUniqueIDs objectEnumerator];
190 while ((uniqueID = [enumerator nextObject])) {
191 [arrayOfDragItems addObject:[[adium contactController] existingListObjectWithUniqueID:uniqueID]];
194 //We will release this when the drag is completed
195 dragItems = [arrayOfDragItems retain];
199 //The tree root is not associated with our root contact list group, so we need to make that association here
200 if (item == nil) item = contactList;
202 //Move the list object to its new location
203 if ([item isKindOfClass:[AIMetaContact class]]) {
205 NSMutableArray *realDragItems = [NSMutableArray array];
206 NSEnumerator *enumerator;
207 AIListObject *aDragItem;
209 if (index == [outlineView numberOfRows]) {
210 index = [item containedObjectsCount];
212 //The outline view has one unique contact for each service/UID combination, while the metacontact
213 //has a containedObjectsArray with multiple contacts for each. We want to find which item is at
214 //our drop row, then determine the index in the metacontact of that item. That's the index we move to.
215 index = [(AIMetaContact *)item indexOfObject:[outlineView itemAtRow:index]];
218 enumerator = [dragItems objectEnumerator];
219 while ((aDragItem = [enumerator nextObject])) {
220 if ([aDragItem isMemberOfClass:[AIListContact class]]) {
221 //For listContacts, add all contacts with the same service and UID (on all accounts)
222 [realDragItems addObjectsFromArray:[[[adium contactController] allContactsWithService:[aDragItem service]
224 existingOnly:YES] allObjects]];
226 [realDragItems addObject:aDragItem];
230 [[adium contactController] moveListObjects:realDragItems intoObject:item index:index];
231 [outlineView reloadData];
235 //Call super and return its value
236 return [super outlineView:outlineView acceptDrop:info item:item childIndex:index];
239 //Due to a bug in NSDrawer, convertPoint:fromView reports a point too low by the trailingOffset
240 //when our contact list is in a drawer.
241 - (AIListObject *)contactListItemAtScreenPoint:(NSPoint)screenPoint
243 NSPoint viewPoint = [contactListView convertPoint:[[contactListView window] convertScreenToBase:screenPoint] fromView:[[contactListView window] contentView]];
245 viewPoint.y += [(AIContactInfoWindowController *)delegate drawerTrailingOffset];
247 AIListObject *hoveredObject = [contactListView itemAtRow:[contactListView rowAtPoint:viewPoint]];
249 return hoveredObject;
252 //We want to just show UIDs whereever possible
253 - (BOOL)useAliasesInContactListAsRequested
258 //We don't want to change text colors based on the user's status or state
259 - (BOOL)shouldUseContactTextColors{