Added `-[NSArray validateAsPropertyList]` and `-[NSDictionary validateAsPropertyList...
[adiumx.git] / Source / AIContactListEditorPlugin.m
blob934c082a28fadfd196ce6666fd6c15d592b59d9e
1 /* 
2  * Adium is the legal property of its developers, whose names are listed in the copyright file included
3  * with this source distribution.
4  * 
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.
8  * 
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.
12  * 
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.
15  */
17 #import <Adium/AIAccountControllerProtocol.h>
18 #import <Adium/AIContactControllerProtocol.h>
19 #import <Adium/AIInterfaceControllerProtocol.h>
20 #import "AIContactListEditorPlugin.h"
21 #import <Adium/AIMenuControllerProtocol.h>
22 #import "AINewContactWindowController.h"
23 #import "AINewGroupWindowController.h"
24 #import <Adium/AIToolbarControllerProtocol.h>
25 #import <AIUtilities/AIMenuAdditions.h>
26 #import <AIUtilities/AIToolbarUtilities.h>
27 #import <AIUtilities/AIImageAdditions.h>
28 #import <AIUtilities/AIStringAdditions.h>
29 #import <Adium/AIAccount.h>
30 #import <Adium/AIChat.h>
31 #import <Adium/AIListContact.h>
32 #import <Adium/AIListObject.h>
33 #import <Adium/AIListGroup.h>
34 #import <Adium/AIMetaContact.h>
36 #define ADD_BOOKMARK                                            @"Add Bookmark"
37 #define ADD_BOOKMARK_ELLIPSIS                           [ADD_BOOKMARK stringByAppendingEllipsis]
39 #define ADD_CONTACT                                                     AILocalizedString(@"Add Contact",nil)
40 #define ADD_CONTACT_ELLIPSIS                            [ADD_CONTACT stringByAppendingEllipsis]
42 #define ADD_CONTACT_TO_GROUP                            AILocalizedString(@"Add Contact To Group",nil)
43 #define ADD_CONTACT_TO_GROUP_ELLIPSIS           [ADD_CONTACT_TO_GROUP stringByAppendingEllipsis]
45 #define ADD_GROUP                                                       AILocalizedString(@"Add Group",nil)
46 #define ADD_GROUP_ELLIPSIS                                      [ADD_GROUP stringByAppendingEllipsis]
48 #define DELETE_CONTACT_ELLIPSIS                         [AILocalizedString(@"Remove Contact",nil) stringByAppendingEllipsis]
49 #define DELETE_CONTACT_CONTEXT_ELLIPSIS         [AILocalizedString(@"Remove",nil) stringByAppendingEllipsis]
51 #define RENAME_GROUP                                            AILocalizedString(@"Rename Group",nil)
52 #define RENAME_GROUP_ELLIPSIS                           [RENAME_GROUP stringByAppendingEllipsis]
54 #define ADD_CONTACT_IDENTIFIER                          @"AddContact"
55 #define ADD_GROUP_IDENTIFIER                            @"AddGroup"
59 @interface AIContactListEditorPlugin (PRIVATE)
60 - (void)deleteFromArray:(NSArray *)array;
61 - (void)promptForNewContactOnWindow:(NSWindow *)inWindow selectedListObject:(AIListObject *)inListObject;
62 -(void)promptForNewBookmarkOnWindow:(NSWindow*)window;
63 @end
65 /*!
66  * @class AIContactListEditorPlugin
67  * @brief Component for managing adding and deleting contacts and groups
68  */
69 @implementation AIContactListEditorPlugin
71 /*!
72  * @brief Install
73  */
74 - (void)installPlugin
76     NSMenuItem          *menuItem;
77         NSToolbarItem   *toolbarItem;
78         
79         /*
80         this piece of code is not used for the time being - may implement at later date -eb
81         
82         //Add Bookmark
83         menuItem_addBookmark = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:ADD_BOOKMARK_ELLIPSIS
84                                                                                                                                                                           target:self
85                                                                                                                                                                           action:@selector(addBookmark:)
86                                                                                                                                                            keyEquivalent:@""];
88         [[adium menuController] addMenuItem:menuItem_addBookmark toLocation:LOC_Contact_Manage];
89         */
90         //Add Contact
91     menuItem_addContact = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:ADD_CONTACT_ELLIPSIS
92                                                                                                                                                                 target:self
93                                                                                                                                                                 action:@selector(addContact:)
94                                                                                                                                                  keyEquivalent:@"d"];
95     [[adium menuController] addMenuItem:menuItem_addContact toLocation:LOC_Contact_Manage];
96         
97         menuItem_addContactContext = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:ADD_CONTACT_TO_GROUP_ELLIPSIS
98                                                                                                                                                                           target:self
99                                                                                                                                                                           action:@selector(addContact:)
100                                                                                                                                                            keyEquivalent:@""];
101         [[adium menuController] addContextualMenuItem:menuItem_addContactContext toLocation:Context_Group_Manage];
102         
103         menuItem_tabAddContact = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:ADD_CONTACT_ELLIPSIS
104                                                                                                                                                                    target:self 
105                                                                                                                                                                    action:@selector(addContactFromTab:)
106                                                                                                                                                         keyEquivalent:@""] autorelease];
107     [[adium menuController] addContextualMenuItem:menuItem_tabAddContact toLocation:Context_Contact_Stranger_ChatAction];
109         [[adium notificationCenter] addObserver:self 
110                                                                    selector:@selector(addContactRequest:) 
111                                                                            name:Contact_AddNewContact 
112                                                                          object:nil];
113         
114         //Add Group
115     menuItem_addGroup = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:ADD_GROUP_ELLIPSIS
116                                                                                                                                                          target:self
117                                                                                                                                                          action:@selector(addGroup:) 
118                                                                                                                                           keyEquivalent:@"D"];
119     [[adium menuController] addMenuItem:menuItem_addGroup toLocation:LOC_Contact_Manage];
121         //Delete Selection
122     menuItem_delete = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:DELETE_CONTACT_ELLIPSIS
123                                                                                                                                                    target:self
124                                                                                                                                                    action:@selector(deleteSelection:) 
125                                                                                                                                         keyEquivalent:@"\b"];
126     [[adium menuController] addMenuItem:menuItem_delete toLocation:LOC_Contact_Manage];
128         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:DELETE_CONTACT_CONTEXT_ELLIPSIS
129                                                                                                                                          target:self
130                                                                                                                                          action:@selector(deleteSelectionFromTab:) 
131                                                                                                                           keyEquivalent:@""] autorelease];
132         [[adium menuController] addContextualMenuItem:menuItem toLocation:Context_Contact_NegativeAction];
133         
134         //Add Contact toolbar item
135     toolbarItem = [AIToolbarUtilities toolbarItemWithIdentifier:ADD_CONTACT_IDENTIFIER
136                                                                                                                   label:ADD_CONTACT
137                                                                                                    paletteLabel:ADD_CONTACT
138                                                                                                                 toolTip:AILocalizedString(@"Add a new contact",nil)
139                                                                                                                  target:self
140                                                                                                 settingSelector:@selector(setImage:)
141                                                                                                         itemContent:[NSImage imageNamed:@"AddContact" forClass:[self class] loadLazily:YES]
142                                                                                                                  action:@selector(addContact:)
143                                                                                                                    menu:nil];
144     [[adium toolbarController] registerToolbarItem:toolbarItem forToolbarType:@"ListObject"];   
145         
146         //Add Group toolbar item
147     toolbarItem = [AIToolbarUtilities toolbarItemWithIdentifier:ADD_GROUP_IDENTIFIER
148                                                                                                                   label:ADD_GROUP
149                                                                                                    paletteLabel:ADD_GROUP
150                                                                                                                 toolTip:AILocalizedString(@"Add a new group",nil)
151                                                                                                                  target:self
152                                                                                                 settingSelector:@selector(setImage:)
153                                                                                                         itemContent:[NSImage imageNamed:@"addGroup" forClass:[self class] loadLazily:YES]
154                                                                                                                  action:@selector(addGroup:)
155                                                                                                                    menu:nil];
156     [[adium toolbarController] registerToolbarItem:toolbarItem forToolbarType:@"ContactList"];  
157         
158         //Rename Group
159         //      menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:RENAME_GROUP_ELLIPSIS
160         //                                                                                                                                       target:self
161         //                                                                                                                                       action:@selector(renameGroup:) 
162         //                                                                                                                        keyEquivalent:@""] autorelease];
163         //  [[adium menuController] addContextualMenuItem:menuItem toLocation:Context_Group_Manage];    
167  * @brief Uninstall
168  */
169 - (void)uninstallPlugin
171     [[adium notificationCenter] removeObserver:self];
175  * @brief Validate our menu items
176  */
177 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
179         if (menuItem == menuItem_delete) {
180                 return [[adium interfaceController] selectedListObjectInContactList] != nil;
181                 
182         } else if (menuItem == menuItem_tabAddContact) {
183                 return [[adium menuController] currentContextMenuObject] != nil;
184         
185         } else if (menuItem == menuItem_addGroup || menuItem == menuItem_addContact || menuItem == menuItem_addContactContext) {
186                 NSEnumerator    *enumerator = [[[adium accountController] accounts] objectEnumerator];
187                 AIAccount               *account;
188                 
189                 while ((account = [enumerator nextObject])) {   
190                         if ([account contactListEditable]) return YES;
191                 }
192                 
193                 return NO;
195         } else if (menuItem == menuItem_addBookmark) {
196                 return [[[adium interfaceController] activeChat] isGroupChat];
197         }
198         
199         return YES;
202 //Called by a context menu
203 - (IBAction)renameGroup:(id)sender
205         //      AIListObject    *object = [[adium menuController] currentContextMenuObject];
206         //<renameGroup> : I wish I worked... :( 
208 //Add Bookmark ----------------------------------------------------------------------------------------------------------
209 #pragma mark Add Bookmark
211  * @brief Promp for a new bookmark
212  */
213 - (IBAction)addBookmark:(id)sender
215         [self promptForNewBookmarkOnWindow:nil];
218 -(void)promptForNewBookmarkOnWindow:(NSWindow*)window
220         NSLog(@"addBookmark");
222 //Add Contact ----------------------------------------------------------------------------------------------------------
223 #pragma mark Add Contact
225  * @brief Prompt for a new contact
226  */
227 - (IBAction)addContact:(id)sender
229         [self promptForNewContactOnWindow:nil selectedListObject:[[adium interfaceController] selectedListObject]];
234  * @brief Prompt for a new contact with the current tab's name
235  */
236 - (IBAction)addContactFromTab:(id)sender
238         [self promptForNewContactOnWindow:nil selectedListObject:[[adium menuController] currentContextMenuObject]];
242  * @brief Prompt for a new contact
244  * @param inWindow If non-nil, display the new contact prompt as a sheet on inWindow
245  * @param inListObject If a contact and a stranger, will be autofilled into the new contact window
246  */
247 - (void)promptForNewContactOnWindow:(NSWindow *)inWindow selectedListObject:(AIListObject *)inListObject
249         //We only autofill if the selected list object is a contact and a stranger
250         if (![inListObject isKindOfClass:[AIListContact class]] || [(AIListContact *)inListObject isIntentionallyNotAStranger] ||
251                 [inListObject isKindOfClass:[AIMetaContact class]]) {
252                 inListObject = nil;
253         }
254         
255         [AINewContactWindowController promptForNewContactOnWindow:inWindow
256                                                                                                                  name:(inListObject ? [inListObject UID] : nil)
257                                                                                                           service:(inListObject ? [(AIListContact *)inListObject service] : nil)
258                                                                                                           account:nil];
262  * @brief Add contact request notification
264  * Display the add contact window.  Triggered by an incoming Contact_AddNewContact notification 
265  * @param notification Notification with a userInfo containing @"UID" and @"Service" keys
266  */
267 - (void)addContactRequest:(NSNotification *)notification
269         NSDictionary *userInfo = [notification userInfo];
270         if (userInfo) {
271                 [AINewContactWindowController promptForNewContactOnWindow:nil
272                                                                                                                          name:[userInfo objectForKey:@"UID"]
273                                                                                                                   service:[userInfo objectForKey:@"AIService"]
274                                                                                                                   account:[userInfo objectForKey:@"AIAccount"]];
275         }
279 //Add Group ------------------------------------------------------------------------------------------------------------
280 #pragma mark Add Group
282  * @brief Prompt for a new group
283  */
284 - (IBAction)addGroup:(id)sender
286         [AINewGroupWindowController promptForNewGroupOnWindow:nil];
290 //Delete Selection -----------------------------------------------------------------------------------------------------
291 #pragma mark Delete Selection
293  * @brief Delete the list objects selected in the contact list
294  */
295 - (IBAction)deleteSelection:(id)sender
296 {       
297         [self deleteFromArray:[[adium interfaceController] arrayOfSelectedListObjectsInContactList]];
301  * @brief Delete the list object associated with the current context menu
302  */
303 - (IBAction)deleteSelectionFromTab:(id)sender
305         AIListObject   *currentContextMenuObject;
306         if ((currentContextMenuObject = [[adium menuController] currentContextMenuObject])) {
307                 [self deleteFromArray:[NSArray arrayWithObject:currentContextMenuObject]];
308         }
312  * @brief Delete an array of <tt>AIListObject</tt>s
314  * After a modal confirmation prompt, the objects in the array are deleted.
316  * @param array An <tt>NSArray</tt> of <tt>AIListObject</tt>s.
317  */
318 - (void)deleteFromArray:(NSArray *)array
320         if (array) {
321                 NSString        *message;
322                 int                     count = [array count];
324                 if (count == 1) {
325                         AIListObject    *listObject = [array objectAtIndex:0];
326                         NSString                *name = [listObject displayName];
327                         if ([listObject isKindOfClass:[AIListGroup class]]) {
328                                 message = [NSString stringWithFormat:AILocalizedString(@"This will remove the group \"%@\" from the contact lists of your online accounts. The %i contacts within this group will also be removed.\n\nThis action can not be undone.",nil),
329                                         name,
330                                         [(AIListGroup *)listObject containedObjectsCount]];
331                                 
332                         } else {
333                                 message = [NSString stringWithFormat:AILocalizedString(@"This will remove %@ from the contact lists of your online accounts.",nil), name];
334                         }
335                 } else {
336                         BOOL            containsGroup = NO;
337                         NSEnumerator *enumerator = [array objectEnumerator];
338                         AIListObject *listObject;
339                         
340                         while ((listObject = [enumerator nextObject]) && !containsGroup) {
341                                 containsGroup = [listObject isKindOfClass:[AIListGroup class]];
342                         }
344                         if (containsGroup) {
345                                 message = [NSString stringWithFormat:AILocalizedString(@"This will remove %i items from the contact lists of your online accounts. Contacts in any deleted groups will also be removed.\n\nThis action can not be undone.",nil), count];
346                         } else {
347                                 message = [NSString stringWithFormat:AILocalizedString(@"This will remove %i contacts from the contact lists of your online accounts.",nil), count];
348                         }
349                 }
350                 
351                 //Make sure we're in the front so our prompt is visible
352                 [NSApp activateIgnoringOtherApps:YES];
353                 
354                 //Guard deletion with a warning prompt          
355                 int result = NSRunAlertPanel(AILocalizedString(@"Remove from list?",nil),
356                                                                          message,
357                                                                          AILocalizedString(@"Remove",nil),
358                                                                          AILocalizedString(@"Cancel",nil),
359                                                                          nil);
361                 if (result == NSAlertDefaultReturn) {
362                         [[adium contactController] removeListObjects:array];
363                 }
364         }       
367 @end