* 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 <Adium/AIChatControllerProtocol.h> #import <Adium/AIContactControllerProtocol.h> #import <Adium/AIContentControllerProtocol.h> #import <Adium/AIInterfaceControllerProtocol.h> #import <Adium/AIToolbarControllerProtocol.h> #import "ESUserIconHandlingPlugin.h" #import <AIUtilities/AIFileManagerAdditions.h> #import <AIUtilities/AIMutableOwnerArray.h> #import <AIUtilities/AIToolbarUtilities.h> #import <AIUtilities/AIMenuAdditions.h> #import <AIUtilities/AIImageAdditions.h> #import <AIUtilities/AIImageButton.h> #import <Adium/AIAccount.h> #import <Adium/AIListContact.h> #import <Adium/AIListObject.h> #import <Adium/AIServiceIcons.h> #define TOOLBAR_ITEM_TAG -999 @interface ESUserIconHandlingPlugin () - (void)registerToolbarItem; - (void)_updateToolbarIconOfChat:(AIChat *)inChat inWindow:(NSWindow *)window; - (void)_updateToolbarItem:(NSToolbarItem *)item forChat:(AIChat *)chat; - (void)updateToolbarItemForObject:(AIListObject *)inObject; - (void)toolbarDidAddItem:(NSToolbarItem *)item; - (void)chatDidBecomeVisible:(NSNotification *)notification; - (void)listObjectAttributesChanged:(NSNotification *)notification; - (IBAction)dummyAction:(id)sender; * @class ESUserIconHandlingPlugin * @brief User icon handling component * This component manages the Adium user icon cache. It also provides a toolbar icon which shows the user icon * or service icon of the current chat in its window. @implementation ESUserIconHandlingPlugin [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(listObjectAttributesChanged:) name:ListObject_AttributesChanged [self registerToolbarItem]; [adium.preferenceController unregisterPreferenceObserver:self]; //Needs some [self updateToolbarItemForObject:inObject]; * @brief List object attributes changes * A plugin, or this plugin, modified the display array for the object; ensure our cache is up to date. - (void)listObjectAttributesChanged:(NSNotification *)notification AIListObject *inObject = [notification object]; NSSet *keys = [[notification userInfo] objectForKey:@"Keys"]; if ([keys containsObject:KEY_USER_ICON]) { [self updateToolbarItemForObject:inObject]; for (AIChat *chat in adium.interfaceController.openChats) { NSWindow *window = [adium.interfaceController windowForChat:chat]; [self _updateToolbarIconOfChat:chat #pragma mark Toolbar Item * @brief Register our toolbar item * Our toolbar item shows an image for the current chat, displaying it full size/animating if clicked. - (void)registerToolbarItem NSToolbarItem *toolbarItem; toolbarItems = [[NSMutableSet alloc] init]; validatedItems = [[NSMutableSet alloc] init]; //Toolbar item registration [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(toolbarWillAddItem:) name:NSToolbarWillAddItemNotification [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(toolbarDidRemoveItem:) name:NSToolbarDidRemoveItemNotification button = [[AIImageButton alloc] initWithFrame:NSMakeRect(0,0,32,32)]; toolbarItem = [AIToolbarUtilities toolbarItemWithIdentifier:@"UserIcon" label:AILocalizedString(@"Icon",nil) paletteLabel:AILocalizedString(@"Contact Icon",nil) toolTip:AILocalizedString(@"Show this contact's icon",nil) settingSelector:@selector(setView:) action:@selector(dummyAction:) [toolbarItem setMinSize:NSMakeSize(32,32)]; [toolbarItem setMaxSize:NSMakeSize(32,32)]; [button setCornerRadius:3.0f]; [button setToolbarItem:toolbarItem]; [button setImage:[NSImage imageNamed:@"default-icon" forClass:[self class] loadLazily:YES]]; //Register our toolbar item [adium.toolbarController registerToolbarItem:toolbarItem forToolbarType:@"MessageWindow"]; * @brief After the toolbar has added the item we can set up the submenus - (void)toolbarWillAddItem:(NSNotification *)notification NSToolbarItem *item = [[notification userInfo] objectForKey:@"item"]; if ([[item itemIdentifier] isEqualToString:@"UserIcon"]) { //Add menu to toolbar item (for text mode) NSMenuItem *menuFormRepresentation, *blankMenuItem; menuFormRepresentation = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] init] autorelease]; menu = [[[NSMenu allocWithZone:[NSMenu menuZone]] init] autorelease]; [menu setAutoenablesItems:NO]; blankMenuItem = [[NSMenuItem alloc] initWithTitle:@"" action:@selector(dummyAction:) [blankMenuItem setRepresentedObject:item]; [blankMenuItem setEnabled:YES]; [menu addItem:blankMenuItem]; [menuFormRepresentation setSubmenu:menu]; [menuFormRepresentation setTitle:[item label]]; [item setMenuFormRepresentation:menuFormRepresentation]; //If this is the first item added, start observing for chats becoming visible so we can update the icon if ([toolbarItems count] == 0) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(chatDidBecomeVisible:) name:@"AIChatDidBecomeVisible" [toolbarItems addObject:item]; [self performSelector:@selector(toolbarDidAddItem:) - (void)toolbarDidAddItem:(NSToolbarItem *)item /* Only need to take action if we haven't already validated the initial state of this item. * This will only be true when the toolbar is revealed for the first time having been hidden when window opened. if (![validatedItems containsObject:item]) { NSEnumerator *enumerator = [[NSApp windows] objectEnumerator]; NSToolbar *thisItemsToolbar = [item toolbar]; //Look at each window to find the toolbar we are in while ((window = [enumerator nextObject])) { if ([window toolbar] == thisItemsToolbar) break; [self _updateToolbarItem:item forChat:[adium.interfaceController activeChatInWindow:window]]; * @brief Toolbar removed an item. * If the item is one of ours, stop tracking it. * @param notification Notification with an @"item" userInfo key for an NSToolbarItem. - (void)toolbarDidRemoveItem: (NSNotification *)notification NSToolbarItem *item = [[notification userInfo] objectForKey:@"item"]; if ([toolbarItems containsObject:item]) { [toolbarItems removeObject:item]; [validatedItems removeObject:item]; if ([toolbarItems count] == 0) { [[NSNotificationCenter defaultCenter] removeObserver:self name:@"AIChatDidBecomeVisible" * @brief A chat became visible in a window. * Update the item with the @"UserIcon" identifier if necessary * @param notification Notification with an AIChat object and an @"NSWindow" userInfo key - (void)chatDidBecomeVisible:(NSNotification *)notification [self _updateToolbarIconOfChat:[notification object] inWindow:[[notification userInfo] objectForKey:@"NSWindow"]]; - (void)updateToolbarItemForObject:(AIListObject *)inObject //Update the icon in the toolbar for this contact if a chat is open and we have any toolbar items if (([toolbarItems count] > 0) && [inObject isKindOfClass:[AIListContact class]] && (chat = [adium.chatController existingChatWithContact:(AIListContact *)inObject]) && (window = [adium.interfaceController windowForChat:chat])) { [self _updateToolbarIconOfChat:chat - (void)_updateToolbarItem:(NSToolbarItem *)item forChat:(AIChat *)chat AIListContact *listContact; listContact = (AIListContact *)[adium.contactController existingBookmarkForChat:chat]; listContact = chat.listObject.parentContact; image = [listContact userIcon]; //Use the serviceIcon if no image can be found if (!image) image = [AIServiceIcons serviceIconForObject:listContact //If we have no listObject or we have a name, we are a group chat and //should use the account's service icon image = [AIServiceIcons serviceIconForObject:chat.account [(AIImageButton *)[item view] setImage:image]; [validatedItems addObject:item]; * @brief Update the user image toolbar icon in a chat * @param chat The chat for which to retrieve an image * @param window The window in which the chat resides - (void)_updateToolbarIconOfChat:(AIChat *)chat inWindow:(NSWindow *)window NSToolbar *toolbar = [window toolbar]; NSEnumerator *enumerator = [[toolbar items] objectEnumerator]; while ((item = [enumerator nextObject])) { if ([[item itemIdentifier] isEqualToString:@"UserIcon"]) { [self _updateToolbarItem:item forChat:chat]; * @brief Empty action for menu item validation purposes - (IBAction)dummyAction:(id)sender{}; * @brief Menu needs update * Should only be called for a menu off one of our toolbar items in text-only mode, and only when that menu is about - (void)menuNeedsUpdate:(NSMenu *)menu NSMenuItem *menuItem = [menu itemAtIndex:0]; NSToolbarItem *toolbarItem = [menuItem representedObject]; [menuItem setImage:[[[(AIImageButton *)[toolbarItem view] image] copy] autorelease]]; - (BOOL)validateMenuItem:(NSMenuItem *)menuItem