William Bowling is sharing code with you
Bitbucket is a code hosting site. Unlimited public and private repositories. Free for small teams.
Don't show this again1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | /*
* Adium is the legal property of its developers, whose names are listed in the copyright file included
* with this source distribution.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program; if not,
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#import "AIAliasSupportPlugin.h"
#import <Adium/AIContactControllerProtocol.h>
#import "AIContactInfoWindowController.h"
#import "AIContactListEditorPlugin.h"
#import <Adium/AIMenuControllerProtocol.h>
#import <AIUtilities/AIDictionaryAdditions.h>
#import <AIUtilities/AIMenuAdditions.h>
#import <AIUtilities/AIMutableOwnerArray.h>
#import <Adium/AIListContact.h>
#import <Adium/AIListObject.h>
#define ALIASES_DEFAULT_PREFS @"Alias Defaults"
#define DISPLAYFORMAT_DEFAULT_PREFS @"Display Format Defaults"
#define CONTACT_NAME_MENU_TITLE AILocalizedString(@"Contact Name Format",nil)
#define ALIAS AILocalizedString(@"Alias",nil)
#define ALIAS_SCREENNAME AILocalizedString(@"Alias (User Name)",nil)
#define SCREENNAME_ALIAS AILocalizedString(@"User Name (Alias)",nil)
#define SCREENNAME AILocalizedString(@"User Name",nil)
@interface AIAliasSupportPlugin ()
- (NSSet *)_applyAlias:(NSString *)inAlias toObject:(AIListObject *)inObject notify:(BOOL)notify;
- (NSMenu *)_contactNameMenu;
@end
/*!
* @class AIAliasSupportPlugin
* @brief Plugin to handle applying aliases to contacts
*
* This plugin applies aliases to contacts. It also responsible for generating the "long display name"
* used in the contact list which may include some combination of alias and screen name.
*/
@implementation AIAliasSupportPlugin
/*!
* @brief Install plugin
*/
- (void)installPlugin
{
//Register our default preferences
[adium.preferenceController registerDefaults:[NSDictionary dictionaryNamed:ALIASES_DEFAULT_PREFS
forClass:[self class]]
forGroup:PREF_GROUP_ALIASES];
[adium.preferenceController registerDefaults:[NSDictionary dictionaryNamed:DISPLAYFORMAT_DEFAULT_PREFS
forClass:[self class]]
forGroup:PREF_GROUP_DISPLAYFORMAT];
//Create the menu item
menuItem_contactName = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:CONTACT_NAME_MENU_TITLE
target:nil
action:nil
keyEquivalent:@""] autorelease];
//Add the menu item (which will have _contactNameMenu as its submenu)
[adium.menuController addMenuItem:menuItem_contactName toLocation:LOC_View_Additions];
menu_contactSubmenu = [[self _contactNameMenu] retain];
[menuItem_contactName setSubmenu:menu_contactSubmenu];
//Observe preferences changes
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applyAliasRequested:)
name:Contact_ApplyDisplayName
object:nil];
[adium.preferenceController registerPreferenceObserver:self forGroup:PREF_GROUP_DISPLAYFORMAT];
}
/*!
* @brief Uninstall plugin
*/
- (void)uninstallPlugin
{
[[AIContactObserverManager sharedManager] unregisterListObjectObserver:self];
[adium.preferenceController unregisterPreferenceObserver:self];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
/*!
* @brief Deallocate
*/
- (void)dealloc
{
[menu_contactSubmenu release];
[super dealloc];
}
/*!
* @brief Change the format for the long display name used in the contact list
*
* @param sender An NSMenuItem which was clicked. Its tag should be an AIDisplayNameType.
*/
-(IBAction)changeFormat:(id)sender
{
[adium.preferenceController setPreference:[NSNumber numberWithInteger:[sender tag]]
forKey:@"Long Display Format"
group:PREF_GROUP_DISPLAYFORMAT];
}
/*!
* @brief Update list object
*
* As contacts are created or a formattedUID is received, update their alias, display name, and long display name
*/
- (NSSet *)updateListObject:(AIListObject *)inObject keys:(NSSet *)inModifiedKeys silent:(BOOL)silent
{
if ((inModifiedKeys == nil) || ([inModifiedKeys containsObject:@"FormattedUID"])) {
return [self _applyAlias:[inObject preferenceForKey:@"Alias"
group:PREF_GROUP_ALIASES
]
toObject:inObject
notify:NO];
}
return nil;
}
/*!
* @brief Preferences changed. Our only preference is for the Long Display Name format
*
* Update the checked menu item since this is not done automatically.
* Update all list objects so we make use of the new long display format preference.
*/
- (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key
object:(AIListObject *)object preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
{
//Clear old checkmark
[[menu_contactSubmenu itemWithTag:displayFormat] setState:NSOffState];
//Load new displayFormat
displayFormat = [[prefDict objectForKey:@"Long Display Format"] integerValue];
//Set new checkmark
[[menu_contactSubmenu itemWithTag:displayFormat] setState:NSOnState];
if (firstTime) {
//Register ourself as a handle observer
[[AIContactObserverManager sharedManager] registerListObjectObserver:self];
} else {
//Update all existing contacts
[[AIContactObserverManager sharedManager] updateAllListObjectsForObserver:self];
}
}
/*!
* @brief Notification was posted to apply a specific alias
*
* This is used from elsewhere in Adium to request the alias of the object be updated. It's a bit ugly, really.
* The object of the notification is an AIListObject.
* The userInfo is a dictionary with an NSNumber on key @"Notify" indicating if a 'changed' notification should be sent out as a result.
* If this is NO, it is equivalent to a 'silent' update.
* The user info dictionary also has the desired NSString alias on the key @"Alias".
* If this is not specified, the object's preference is reloaded.
*/
- (void)applyAliasRequested:(NSNotification *)notification
{
AIListObject *object = [notification object];
NSDictionary *userInfo = [notification userInfo];
NSNumber *shouldNotifyNumber = [userInfo objectForKey:@"Notify"];
NSString *alias = [userInfo objectForKey:@"Alias"];
if (!alias) {
alias = [object preferenceForKey:@"Alias"
group:PREF_GROUP_ALIASES
];
}
[self _applyAlias:alias
toObject:object
notify:(shouldNotifyNumber ? [shouldNotifyNumber boolValue] : NO)];
}
//Private ---------------------------------------------------------------------------------------
/*!
* @brief Apply an alias to an object
*
* This does not save any preferences.
*
* @param inAlias The alias to apply.
* @param inObject The object to which the alias should be applied
* @param notify YES if a notification should be sent out after the alias is applied
*/
- (NSSet *)_applyAlias:(NSString *)inAlias toObject:(AIListObject *)inObject notify:(BOOL)notify
{
NSSet *modifiedAttributes;
NSString *displayName = nil;
NSString *longDisplayName = nil;
NSString *formattedUID = nil;
//Apply the alias
[[inObject displayArrayForKey:@"Display Name" create:(inAlias != nil)] setObject:inAlias withOwner:self priorityLevel:High_Priority];
//Get the displayName which is now active for the object
displayName = inObject.displayName;
//Build and set the Long Display Name
if ([inObject isKindOfClass:[AIListContact class]]) {
switch (displayFormat)
{
case AINameFormat_DisplayName:
longDisplayName = displayName;
break;
case AINameFormat_DisplayName_ScreenName:
formattedUID = inObject.formattedUID;
if (!displayName || !formattedUID || [displayName isEqualToString:formattedUID]) {
longDisplayName = displayName;
} else {
longDisplayName = [NSString stringWithFormat:@"%@ (%@)",displayName,formattedUID];
}
break;
case AINameFormat_ScreenName_DisplayName:
formattedUID = inObject.formattedUID;
if (!displayName || !formattedUID || [displayName isEqualToString:formattedUID]) {
longDisplayName = displayName;
} else {
longDisplayName = [NSString stringWithFormat:@"%@ (%@)",formattedUID,displayName];
}
break;
case AINameFormat_ScreenName:
//??? - How should this be handled for metaContacts? What if there are no aliases set?
formattedUID = inObject.formattedUID;
longDisplayName = (formattedUID ? formattedUID : displayName);
break;
default:
longDisplayName = nil;
break;
}
//Apply the Long Display Name
[[inObject displayArrayForKey:@"Long Display Name" create:(longDisplayName &&
![longDisplayName isEqualToString:displayName])] setObject:longDisplayName
withOwner:self];
}
modifiedAttributes = [NSSet setWithObjects:@"Display Name", @"Long Display Name", nil];
//If notify is YES, send out a manual listObjectAttributesChanged notice;
//if NO, the observer methods will be handling it
if (notify) {
[[AIContactObserverManager sharedManager] listObjectAttributesChanged:inObject
modifiedKeys:modifiedAttributes];
}
return modifiedAttributes;
}
/*!
* @brief Generate the menu of long display name format choices
*
* @result The autoreleased menu
*/
- (NSMenu *)_contactNameMenu
{
NSMenu *choicesMenu;
NSMenuItem *menuItem;
choicesMenu = [[[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@""] autorelease];
menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:ALIAS
target:self
action:@selector(changeFormat:)
keyEquivalent:@""] autorelease];
[menuItem setTag:AINameFormat_DisplayName];
[choicesMenu addItem:menuItem];
menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:ALIAS_SCREENNAME
target:self
action:@selector(changeFormat:)
keyEquivalent:@""] autorelease];
[menuItem setTag:AINameFormat_DisplayName_ScreenName];
[choicesMenu addItem:menuItem];
menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:SCREENNAME_ALIAS
target:self
action:@selector(changeFormat:)
keyEquivalent:@""] autorelease];
[menuItem setTag:AINameFormat_ScreenName_DisplayName];
[choicesMenu addItem:menuItem];
menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:SCREENNAME
target:self
action:@selector(changeFormat:)
keyEquivalent:@""] autorelease];
[menuItem setTag:AINameFormat_ScreenName];
[choicesMenu addItem:menuItem];
return choicesMenu;
}
@end
|