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 "AIAliasSupportPlugin.h"
18 #import <Adium/AIContactControllerProtocol.h>
19 #import "AIContactInfoWindowController.h"
20 #import "AIContactListEditorPlugin.h"
21 #import <Adium/AIMenuControllerProtocol.h>
22 #import <Adium/AIPreferenceControllerProtocol.h>
23 #import <AIUtilities/AIDictionaryAdditions.h>
24 #import <AIUtilities/AIMenuAdditions.h>
25 #import <AIUtilities/AIMutableOwnerArray.h>
26 #import <Adium/AIListContact.h>
27 #import <Adium/AIListObject.h>
29 #define ALIASES_DEFAULT_PREFS @"Alias Defaults"
30 #define DISPLAYFORMAT_DEFAULT_PREFS @"Display Format Defaults"
32 #define CONTACT_NAME_MENU_TITLE AILocalizedString(@"Contact Name Format",nil)
33 #define ALIAS AILocalizedString(@"Alias",nil)
34 #define ALIAS_SCREENNAME AILocalizedString(@"Alias (User Name)",nil)
35 #define SCREENNAME_ALIAS AILocalizedString(@"User Name (Alias)",nil)
36 #define SCREENNAME AILocalizedString(@"User Name",nil)
38 @interface AIAliasSupportPlugin (PRIVATE)
39 - (NSSet *)_applyAlias:(NSString *)inAlias toObject:(AIListObject *)inObject notify:(BOOL)notify;
40 - (NSMenu *)_contactNameMenu;
44 * @class AIAliasSupportPlugin
45 * @brief Plugin to handle applying aliases to contacts
47 * This plugin applies aliases to contacts. It also responsible for generating the "long display name"
48 * used in the contact list which may include some combination of alias and screen name.
50 @implementation AIAliasSupportPlugin
53 * @brief Install plugin
57 //Register our default preferences
58 [[adium preferenceController] registerDefaults:[NSDictionary dictionaryNamed:ALIASES_DEFAULT_PREFS
59 forClass:[self class]]
60 forGroup:PREF_GROUP_ALIASES];
61 [[adium preferenceController] registerDefaults:[NSDictionary dictionaryNamed:DISPLAYFORMAT_DEFAULT_PREFS
62 forClass:[self class]]
63 forGroup:PREF_GROUP_DISPLAYFORMAT];
65 //Create the menu item
66 menuItem_contactName = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:CONTACT_NAME_MENU_TITLE
69 keyEquivalent:@""] autorelease];
71 //Add the menu item (which will have _contactNameMenu as its submenu)
72 [[adium menuController] addMenuItem:menuItem_contactName toLocation:LOC_View_Additions];
74 menu_contactSubmenu = [[self _contactNameMenu] retain];
75 [menuItem_contactName setSubmenu:menu_contactSubmenu];
77 //Observe preferences changes
78 [[adium notificationCenter] addObserver:self
79 selector:@selector(applyAliasRequested:)
80 name:Contact_ApplyDisplayName
82 [[adium preferenceController] registerPreferenceObserver:self forGroup:PREF_GROUP_DISPLAYFORMAT];
86 * @brief Uninstall plugin
88 - (void)uninstallPlugin
90 [[adium contactController] unregisterListObjectObserver:self];
91 [[adium preferenceController] unregisterPreferenceObserver:self];
92 [[adium notificationCenter] removeObserver:self];
100 [menu_contactSubmenu release];
105 * @brief Change the format for the long display name used in the contact list
107 * @param sender An NSMenuItem which was clicked. Its tag should be an AIDisplayNameType.
109 -(IBAction)changeFormat:(id)sender
111 [[adium preferenceController] setPreference:[NSNumber numberWithInt:[sender tag]]
112 forKey:@"Long Display Format"
113 group:PREF_GROUP_DISPLAYFORMAT];
117 * @brief Update list object
119 * As contacts are created or a formattedUID is received, update their alias, display name, and long display name
121 - (NSSet *)updateListObject:(AIListObject *)inObject keys:(NSSet *)inModifiedKeys silent:(BOOL)silent
123 if ((inModifiedKeys == nil) || ([inModifiedKeys containsObject:@"FormattedUID"])) {
124 return [self _applyAlias:[inObject preferenceForKey:@"Alias"
125 group:PREF_GROUP_ALIASES
126 ignoreInheritedValues:YES]
135 * @brief Preferences changed. Our only preference is for the Long Display Name format
137 * Update the checked menu item since this is not done automatically.
138 * Update all list objects so we make use of the new long display format preference.
140 - (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key
141 object:(AIListObject *)object preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
143 //Clear old checkmark
144 [[menu_contactSubmenu itemWithTag:displayFormat] setState:NSOffState];
146 //Load new displayFormat
147 displayFormat = [[prefDict objectForKey:@"Long Display Format"] intValue];
150 [[menu_contactSubmenu itemWithTag:displayFormat] setState:NSOnState];
153 //Register ourself as a handle observer
154 [[adium contactController] registerListObjectObserver:self];
156 //Update all existing contacts
157 [[adium contactController] updateAllListObjectsForObserver:self];
163 * @brief Notification was posted to apply a specific alias
165 * This is used from elsewhere in Adium to request the alias of the object be updated. It's a bit ugly, really.
166 * The object of the notification is an AIListObject.
167 * The userInfo is a dictionary with an NSNumber on key @"Notify" indicating if a 'changed' notification should be sent out as a result.
168 * If this is NO, it is equivalent to a 'silent' update.
169 * The user info dictionary also has the desired NSString alias on the key @"Alias".
170 * If this is not specified, the object's preference is reloaded.
172 - (void)applyAliasRequested:(NSNotification *)notification
174 AIListObject *object = [notification object];
175 NSDictionary *userInfo = [notification userInfo];
177 NSNumber *shouldNotifyNumber = [userInfo objectForKey:@"Notify"];
179 NSString *alias = [userInfo objectForKey:@"Alias"];
181 alias = [object preferenceForKey:@"Alias"
182 group:PREF_GROUP_ALIASES
183 ignoreInheritedValues:YES];
186 [self _applyAlias:alias
188 notify:(shouldNotifyNumber ? [shouldNotifyNumber boolValue] : NO)];
191 //Private ---------------------------------------------------------------------------------------
193 * @brief Apply an alias to an object
195 * This does not save any preferences.
197 * @param inAlias The alias to apply.
198 * @param inObject The object to which the alias should be applied
199 * @param notify YES if a notification should be sent out after the alias is applied
201 - (NSSet *)_applyAlias:(NSString *)inAlias toObject:(AIListObject *)inObject notify:(BOOL)notify
203 NSSet *modifiedAttributes;
204 NSString *displayName = nil;
205 NSString *longDisplayName = nil;
206 NSString *formattedUID = nil;
208 AIMutableOwnerArray *displayNameArray = [inObject displayArrayForKey:@"Display Name"];
211 [[inObject displayArrayForKey:@"Adium Alias"] setObject:inAlias withOwner:self];
212 [displayNameArray setObject:inAlias withOwner:self priorityLevel:High_Priority]; // <---- Not setting the display array to null...
214 //Get the displayName which is now active for the object
215 displayName = [displayNameArray objectValue];
217 //Build and set the Long Display Name
218 if ([inObject isKindOfClass:[AIListContact class]]) {
219 switch (displayFormat)
221 case AINameFormat_DisplayName:
222 longDisplayName = displayName;
225 case AINameFormat_DisplayName_ScreenName:
226 formattedUID = [inObject formattedUID];
228 if (!displayName || !formattedUID || [displayName isEqualToString:formattedUID]) {
229 longDisplayName = displayName;
231 longDisplayName = [NSString stringWithFormat:@"%@ (%@)",displayName,formattedUID];
235 case AINameFormat_ScreenName_DisplayName:
236 formattedUID = [inObject formattedUID];
237 if (!displayName || !formattedUID || [displayName isEqualToString:formattedUID]) {
238 longDisplayName = displayName;
240 longDisplayName = [NSString stringWithFormat:@"%@ (%@)",formattedUID,displayName];
244 case AINameFormat_ScreenName:
245 //??? - How should this be handled for metaContacts? What if there are no aliases set?
246 formattedUID = [inObject formattedUID];
247 longDisplayName = (formattedUID ? formattedUID : displayName);
251 longDisplayName = nil;
255 //Apply the Long Display Name
256 [[inObject displayArrayForKey:@"Long Display Name"] setObject:longDisplayName withOwner:self];
259 modifiedAttributes = [NSSet setWithObjects:@"Display Name", @"Long Display Name", @"Adium Alias", nil];
261 //If notify is YES, send out a manual listObjectAttributesChanged notice;
262 //if NO, the observer methods will be handling it
264 [[adium contactController] listObjectAttributesChanged:inObject
265 modifiedKeys:modifiedAttributes];
268 return modifiedAttributes;
272 * @brief Generate the menu of long display name format choices
274 * @result The autoreleased menu
276 - (NSMenu *)_contactNameMenu
280 NSMenuItem *menuItem;
282 choicesMenu = [[[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@""] autorelease];
284 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:ALIAS
286 action:@selector(changeFormat:)
287 keyEquivalent:@""] autorelease];
288 [menuItem setTag:AINameFormat_DisplayName];
289 [choicesMenu addItem:menuItem];
291 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:ALIAS_SCREENNAME
293 action:@selector(changeFormat:)
294 keyEquivalent:@""] autorelease];
295 [menuItem setTag:AINameFormat_DisplayName_ScreenName];
296 [choicesMenu addItem:menuItem];
298 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:SCREENNAME_ALIAS
300 action:@selector(changeFormat:)
301 keyEquivalent:@""] autorelease];
302 [menuItem setTag:AINameFormat_ScreenName_DisplayName];
303 [choicesMenu addItem:menuItem];
305 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:SCREENNAME
307 action:@selector(changeFormat:)
308 keyEquivalent:@""] autorelease];
309 [menuItem setTag:AINameFormat_ScreenName];
310 [choicesMenu addItem:menuItem];