adium/adium

Docs: Minor tweaks.
adium-1.5.11
2016-09-04, Robert Vehse
307f53385811
Docs: Minor tweaks.
/*
* 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/AIAccountControllerProtocol.h>
#import <Adium/AIContactControllerProtocol.h>
#import <Adium/AIMenuControllerProtocol.h>
#import <Adium/AIToolbarControllerProtocol.h>
#import <Adium/AIInterfaceControllerProtocol.h>
#import <Adium/AIChatControllerProtocol.h>
#import "ESBlockingPlugin.h"
#import <AIUtilities/AIMenuAdditions.h>
#import <AIUtilities/AIStringAdditions.h>
#import <AIUtilities/AIToolbarUtilities.h>
#import <AIUtilities/AIImageAdditions.h>
#import <Adium/AIAccount.h>
#import <Adium/AIListContact.h>
#import <Adium/AIListGroup.h>
#import <Adium/AIMetaContact.h>
#import <Adium/AIChat.h>
#define BLOCK AILocalizedString(@"Block","Block Contact menu item")
#define UNBLOCK AILocalizedString(@"Unblock","Unblock Contact menu item")
#define BLOCK_MENUITEM [BLOCK stringByAppendingEllipsis]
#define UNBLOCK_MENUITEM [UNBLOCK stringByAppendingEllipsis]
#define BLOCK_GROUP AILocalizedString(@"Block Group","Block Group menu item")
#define UNBLOCK_GROUP AILocalizedString(@"Unblock Group","Unblock Group menu item")
#define BLOCK_GROUP_MENUITEM [BLOCK_GROUP stringByAppendingEllipsis]
#define UNBLOCK_GROUP_MENUITEM [UNBLOCK_GROUP stringByAppendingEllipsis]
#define TOOLBAR_ITEM_IDENTIFIER @"BlockParticipants"
#define TOOLBAR_BLOCK_ICON_KEY @"msg-block-contact"
#define TOOLBAR_UNBLOCK_ICON_KEY @"msg-unblock-contact"
@interface ESBlockingPlugin()
- (void)_setContact:(AIListContact *)contact isBlocked:(BOOL)isBlocked;
- (void)accountConnected:(NSNotification *)notification;
- (BOOL)areAllGivenContactsBlocked:(NSArray *)contacts;
- (void)setPrivacy:(BOOL)block forContacts:(NSArray *)contacts;
- (IBAction)blockOrUnblockParticipants:(NSToolbarItem *)senderItem;
- (BOOL)blockContactInGroup:(AIListContact *)contact withBlock:(BOOL)isBlock;
- (BOOL)contactIsBlocked:(AIListContact *)chkContact;
//protocols
- (NSSet *)updateListObject:(AIListObject *)inObject keys:(NSSet *)inModifiedKeys silent:(BOOL)silent;
//notifications
- (void)chatDidBecomeVisible:(NSNotification *)notification;
- (void)toolbarWillAddItem:(NSNotification *)notification;
- (void)toolbarDidRemoveItem:(NSNotification *)notification;
//toolbar item methods
- (void)updateToolbarIconOfChat:(AIChat *)inChat inWindow:(NSWindow *)window;
- (void)updateToolbarItem:(NSToolbarItem *)item forChat:(AIChat *)chat;
- (void)updateToolbarItemForObject:(AIListObject *)inObject;
@end
#pragma mark -
@implementation ESBlockingPlugin
- (void)installPlugin
{
//Install the Block menu items
blockContactMenuItem = [[NSMenuItem alloc] initWithTitle:BLOCK_MENUITEM
target:self
action:@selector(blockContact:)
keyEquivalent:@"b"];
[blockContactMenuItem setKeyEquivalentModifierMask:(NSCommandKeyMask|NSAlternateKeyMask)];
[adium.menuController addMenuItem:blockContactMenuItem toLocation:LOC_Contact_NegativeAction];
//Add our get info contextual menu items
blockContactContextualMenuItem = [[NSMenuItem alloc] initWithTitle:BLOCK_MENUITEM
target:self
action:@selector(blockContact:)
keyEquivalent:@""];
[adium.menuController addContextualMenuItem:blockContactContextualMenuItem toLocation:Context_Contact_NegativeAction];
//we want to know when an account connects
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(accountConnected:)
name:ACCOUNT_CONNECTED
object:nil];
//create the block toolbar item
chatToolbarItems = [[NSMutableSet alloc] init];
//cache toolbar icons
blockedToolbarIcons = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSImage imageNamed:@"msg-block-contact" forClass:[self class]], TOOLBAR_BLOCK_ICON_KEY,
[NSImage imageNamed:@"msg-unblock-contact" forClass:[self class]], TOOLBAR_UNBLOCK_ICON_KEY,
nil];
NSToolbarItem *chatItem = [AIToolbarUtilities toolbarItemWithIdentifier:TOOLBAR_ITEM_IDENTIFIER
label:BLOCK
paletteLabel:BLOCK
toolTip:AILocalizedString(@"Blocking prevents a contact from contacting you or seeing your online status.", nil)
target:self
settingSelector:@selector(setImage:)
itemContent:[blockedToolbarIcons valueForKey:TOOLBAR_BLOCK_ICON_KEY]
action:@selector(blockOrUnblockParticipants:)
menu:nil];
[adium.toolbarController registerToolbarItem:chatItem forToolbarType:@"MessageWindow"];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(toolbarWillAddItem:)
name:NSToolbarWillAddItemNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(toolbarDidRemoveItem:)
name:NSToolbarDidRemoveItemNotification
object:nil];
[[AIContactObserverManager sharedManager] registerListObjectObserver:self];
}
- (void)uninstallPlugin
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[AIContactObserverManager sharedManager] unregisterListObjectObserver:self];
[chatToolbarItems release];
[blockedToolbarIcons release];
[blockContactMenuItem release];
[blockContactContextualMenuItem release];
}
/*!
* @brief Block or unblock contacts
*
* @param block Flag indicating what the operation should achieve: NO for unblock, YES for block.
* @param contacts The contacts to block or unblock
*/
- (void)setPrivacy:(BOOL)block forContacts:(NSArray *)contacts
{
AIListContact *currentContact = nil;
for (currentContact in contacts) {
if ([currentContact isBlocked] != block) {
[currentContact setIsBlocked:block updateList:YES];
}
}
}
- (IBAction)blockContact:(id)sender
{
AIListObject *object;
object = ((sender == blockContactMenuItem) ?
adium.interfaceController.selectedListObject :
adium.menuController.currentContextMenuObject);
//Handles group block
if ([object isKindOfClass:[AIListGroup class]]) {
BOOL shouldBlock;
NSString *format;
AIListGroup *group = (AIListGroup *)object;
shouldBlock = [[sender title] isEqualToString:BLOCK_GROUP_MENUITEM];
format = (shouldBlock ?
AILocalizedString(@"Are you sure you want to block all contacts in the group %@?",nil) :
AILocalizedString(@"Are you sure you want to unblock all contacts in the group %@?",nil));
if (NSRunAlertPanel([NSString stringWithFormat:format, [group displayName]],
@"",
(shouldBlock ? BLOCK_GROUP : UNBLOCK_GROUP),
AILocalizedString(@"Cancel", nil),
nil) == NSAlertDefaultReturn) {
//iterate over all contacts in the group
AIListContact *curContact = nil;
for (curContact in [group uniqueContainedObjects]) {
[self blockContactInGroup:curContact withBlock:shouldBlock];
}
}
}
//Handle single contact group
if ([object isKindOfClass:[AIListContact class]]) {
AIListContact *contact = (AIListContact *)object;
BOOL shouldBlock;
NSString *format;
shouldBlock = [[sender title] isEqualToString:BLOCK_MENUITEM];
format = (shouldBlock ?
AILocalizedString(@"Are you sure you want to block %@?",nil) :
AILocalizedString(@"Are you sure you want to unblock %@?",nil));
if (NSRunAlertPanel([NSString stringWithFormat:format, contact.displayName],
@"",
(shouldBlock ? BLOCK : UNBLOCK),
AILocalizedString(@"Cancel", nil),
nil) == NSAlertDefaultReturn) {
//Handle metas
if ([object isKindOfClass:[AIMetaContact class]]) {
AIMetaContact *meta = (AIMetaContact *)object;
//Enumerate over the various list contacts contained
NSEnumerator *enumerator = [[meta uniqueContainedObjects] objectEnumerator];
AIListContact *containedContact = nil;
while ((containedContact = [enumerator nextObject])) {
AIAccount *account = containedContact.account;
if ([account conformsToProtocol:@protocol(AIAccount_Privacy)]) {
[self _setContact:containedContact isBlocked:shouldBlock];
} else {
NSLog(@"Account %@ does not support blocking (contact %@ not blocked on this account)", account, containedContact);
}
}
} else {
AIListContact *singleContact = (AIListContact *)object;
AIAccount *account = singleContact.account;
if ([account conformsToProtocol:@protocol(AIAccount_Privacy)]) {
[self _setContact:singleContact isBlocked:shouldBlock];
} else {
NSLog(@"Account %@ does not support blocking (contact %@ not blocked on this account)", account, singleContact);
}
}
[[NSNotificationCenter defaultCenter] postNotificationName:@"AIPrivacySettingsChangedOutsideOfPrivacyWindow"
object:nil];
}
}
}
- (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem
{
for(NSWindow *currentWindow in [NSApp windows]) {
if (currentWindow.toolbar == toolbarItem.toolbar) {
AIChat *chat = [adium.interfaceController activeChatInWindow:currentWindow];
AIAccount *account = chat.account;
return [account conformsToProtocol:@protocol(AIAccount_Privacy)];
}
}
return NO;
}
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
{
AIListObject *object;
if (menuItem == blockContactMenuItem) {
object = adium.interfaceController.selectedListObject;
} else {
object = adium.menuController.currentContextMenuObject;
}
// For handling groups
if ([object isKindOfClass:[AIListGroup class]]) {
AIListGroup *group = (AIListGroup *)object;
//iterate over contacts in group
NSInteger numContactsBlocked = 0;
NSInteger numContactsUnblocked = 0;
AIListContact *curContact = nil;
for (curContact in [group uniqueContainedObjects]) {
if ([self contactIsBlocked:curContact]) {
numContactsBlocked++;
} else {
numContactsUnblocked++;
}
}
if (numContactsBlocked || numContactsUnblocked) {
// if there are more blocked in the group, menu says "Unblock..."
if (numContactsBlocked > numContactsUnblocked) {
[menuItem setTitle:UNBLOCK_GROUP_MENUITEM];
} else {
[menuItem setTitle:BLOCK_GROUP_MENUITEM];
}
return YES;
} else {
return NO;
}
}
// For handling contacts
if ([object isKindOfClass:[AIListContact class]]) {
//Handle metas
if ([object isKindOfClass:[AIMetaContact class]]) {
AIMetaContact *meta = (AIMetaContact *)object;
//Enumerate over the various list contacts contained
NSEnumerator *enumerator = [[meta uniqueContainedObjects] objectEnumerator];
AIListContact *contact = nil;
NSInteger votesForBlock = 0;
NSInteger votesForUnblock = 0;
while ((contact = [enumerator nextObject])) {
AIAccount<AIAccount_Privacy> *account = (AIAccount<AIAccount_Privacy> *)contact.account;
if ([account conformsToProtocol:@protocol(AIAccount_Privacy)]) {
AIPrivacyType privType = (([account privacyOptions] == AIPrivacyOptionAllowUsers) ? AIPrivacyTypePermit : AIPrivacyTypeDeny);
if ([[account listObjectsOnPrivacyList:privType] containsObject:contact]) {
switch (privType) {
case AIPrivacyTypePermit:
/* He's on a permit list. The action would remove him, blocking him */
votesForBlock++;
break;
case AIPrivacyTypeDeny:
/* He's on a deny list. The action would remove him, unblocking him */
votesForUnblock++;
break;
}
} else {
switch (privType) {
case AIPrivacyTypePermit:
/* He's not on the permit list. The action would add him, unblocking him */
votesForUnblock++;
break;
case AIPrivacyTypeDeny:
/* He's not on a deny list. The action would add him, blocking him */
votesForBlock++;
break;
}
}
}
}
if (votesForBlock || votesForUnblock) {
if (votesForBlock >= votesForUnblock) {
[menuItem setTitle:BLOCK_MENUITEM];
} else {
[menuItem setTitle:UNBLOCK_MENUITEM];
}
return YES;
} else {
return NO;
}
} else {
AIListContact *contact = (AIListContact *)object;
AIAccount<AIAccount_Privacy> *account = (AIAccount<AIAccount_Privacy> *)contact.account;
if ([account conformsToProtocol:@protocol(AIAccount_Privacy)]) {
AIPrivacyType privType = (([account privacyOptions] == AIPrivacyOptionAllowUsers) ? AIPrivacyTypePermit : AIPrivacyTypeDeny);
if ([[account listObjectsOnPrivacyList:privType] containsObject:contact]) {
switch (privType) {
case AIPrivacyTypePermit:
/* He's on a permit list. The action would remove him, blocking him */
[menuItem setTitle:BLOCK_MENUITEM];
break;
case AIPrivacyTypeDeny:
/* He's on a deny list. The action would remove him, unblocking him */
[menuItem setTitle:UNBLOCK_MENUITEM];
break;
}
} else {
switch (privType) {
case AIPrivacyTypePermit:
/* He's not on the permit list. The action would add him, unblocking him */
[menuItem setTitle:UNBLOCK_MENUITEM];
break;
case AIPrivacyTypeDeny:
/* He's not on a deny list. The action would add him, blocking him */
[menuItem setTitle:BLOCK_MENUITEM];
break;
}
}
return YES;
} else {
return NO;
}
}
}
return NO;
}
#pragma mark -
#pragma mark Private
//Private --------------------------------------------------------------------------------------------------------------
- (void)_setContact:(AIListContact *)contact isBlocked:(BOOL)isBlocked
{
//We want to block on all accounts with the same service class. If you want someone gone, you want 'em GONE.
NSEnumerator *enumerator = [[adium.accountController accountsCompatibleWithService:contact.service] objectEnumerator];
AIAccount<AIAccount_Privacy> *account = nil;
AIListContact *sameContact = nil;
while ((account = [enumerator nextObject])) {
sameContact = [account contactWithUID:contact.UID];
if ([account conformsToProtocol:@protocol(AIAccount_Privacy)]){
if (sameContact){
/* If the account is in AIPrivacyOptionAllowUsers mode, blocking a contact means removing it from the allow list.
* Similarly, in allow mode, unblocking a contact means adding it to the allow list.
*
* In AIPrivacyOptionDenyUsers mode, blocking a contact means adding it to the block list.
*
* In all other modes, we can't block specific contacts... so we first switch to AIPrivacyOptionDenyUsers, the more lenient
* of the two possibilities, then add the contact to the block list.
*/
AIPrivacyOption privacyOption = [account privacyOptions];
if (privacyOption == AIPrivacyOptionAllowUsers) {
[sameContact setIsAllowed:!isBlocked updateList:YES];
} else {
if (privacyOption != AIPrivacyOptionDenyUsers) {
[account setPrivacyOptions:AIPrivacyOptionDenyUsers];
}
[sameContact setIsBlocked:isBlocked updateList:YES];
}
}
}
}
}
/*!
* @brief Inform AIListContact instances of the user's intended privacy towards the people they represent
*/
#warning Something similar needs to happen to update when an account privacyOptions change
- (void)accountConnected:(NSNotification *)notification
{
AIAccount *account = [notification object];
if ([account conformsToProtocol:@protocol(AIAccount_Privacy)] &&
([(AIAccount <AIAccount_Privacy> *)account privacyOptions] == AIPrivacyOptionDenyUsers)) {
AIListContact *currentContact;
NSArray *blockedContacts = [(AIAccount <AIAccount_Privacy> *)account listObjectsOnPrivacyList:AIPrivacyTypeDeny];
for (currentContact in blockedContacts) {
[currentContact setIsBlocked:YES updateList:NO];
}
}
}
/*!
* @brief Used in conjunction with blocking a group, to block every contact in that group
*
* @param contact The contact to block
* @result A flag indicating if the block was succesful
*/
- (BOOL)blockContactInGroup:(AIListContact *)contact withBlock:(BOOL)isBlock
{
//Handle metas
if ([contact isKindOfClass:[AIMetaContact class]]) {
AIMetaContact *meta = (AIMetaContact *)contact;
//Enumerate over the various list contacts contained
AIListContact *containedContact = nil;
for (containedContact in [meta uniqueContainedObjects]) {
AIAccount *acct = containedContact.account;
if ([acct conformsToProtocol:@protocol(AIAccount_Privacy)]) {
[self _setContact:containedContact isBlocked:isBlock];
} else {
NSLog(@"Account %@ does not support blocking (contact %@ not blocked on this account)", acct, containedContact);
}
}
} else {
AIAccount *acct = contact.account;
if ([acct conformsToProtocol:@protocol(AIAccount_Privacy)]) {
[self _setContact:contact isBlocked:isBlock];
} else {
NSLog(@"Account %@ does not support blocking (contact %@ not blocked on this account)", acct, contact);
}
}
[[NSNotificationCenter defaultCenter] postNotificationName:@"AIPrivacySettingsChangedOutsideOfPrivacyWindow"
object:nil];
return YES;
}
/*!
* @brief Checks if a contact is blocked, used in conjunction with group blocking
*
* @param contact The contact to check
* @result A flag indicating if the contact is blocked
*/
- (BOOL)contactIsBlocked:(AIListContact *)chkContact
{
//Handle metas
if ([chkContact isKindOfClass:[AIMetaContact class]]) {
AIMetaContact *meta = (AIMetaContact *)chkContact;
//Enumerate over the various list contacts contained
AIListContact *contact = nil;
NSInteger votesForBlocked = 0;
NSInteger votesForUnblocked = 0;
for (contact in [meta uniqueContainedObjects]) {
AIAccount *acct = contact.account;
if ([acct conformsToProtocol:@protocol(AIAccount_Privacy)]) {
AIPrivacyType privType = (([(AIAccount <AIAccount_Privacy> *)acct privacyOptions] == AIPrivacyOptionAllowUsers) ? AIPrivacyTypePermit : AIPrivacyTypeDeny);
if ([[(AIAccount <AIAccount_Privacy> *)acct listObjectsOnPrivacyList:privType] containsObject:contact]) {
switch (privType) {
case AIPrivacyTypePermit:
/* He's on a permit list. The action would remove him, blocking him */
votesForUnblocked++;
break;
case AIPrivacyTypeDeny:
/* He's on a deny list. The action would remove him, unblocking him */
votesForBlocked++;
break;
}
} else {
switch (privType) {
case AIPrivacyTypePermit:
/* He's not on the permit list. The action would add him, unblocking him */
votesForBlocked++;
break;
case AIPrivacyTypeDeny:
/* He's not on a deny list. The action would add him, blocking him */
votesForUnblocked++;
break;
}
}
}
}
if (votesForBlocked) {
return YES;
} else {
return NO;
}
} else {
AIListContact *contact = (AIListContact *)chkContact;
AIAccount *acct = chkContact.account;
if ([acct conformsToProtocol:@protocol(AIAccount_Privacy)]) {
AIPrivacyType privType = (([(AIAccount <AIAccount_Privacy> *)acct privacyOptions] == AIPrivacyOptionAllowUsers) ? AIPrivacyTypePermit : AIPrivacyTypeDeny);
if ([[(AIAccount <AIAccount_Privacy> *)acct listObjectsOnPrivacyList:privType] containsObject:contact]) {
switch (privType) {
case AIPrivacyTypePermit:
// He's on a permit list, therefore he is not blocked
return NO;
case AIPrivacyTypeDeny:
// He's on a deny list, therefore he is blocked
return YES;
}
} else {
switch (privType) {
case AIPrivacyTypePermit:
// He's not on the permit list, therefore he is blocked
return YES;
case AIPrivacyTypeDeny:
// He's not on a deny list, therefore he is unblocked
return NO;
}
}
return NO;
}
}
return NO;
}
/*!
* @brief Determine if all the referenced contacts are blocked or unblocked
*
* @param contacts The contacts to query
* @result A flag indicating if all the contacts are blocked or not
*/
- (BOOL)areAllGivenContactsBlocked:(NSArray *)contacts
{
AIListContact *currentContact = nil;
BOOL areAllGivenContactsBlocked = YES;
//for each contact in the array
for (currentContact in contacts) {
//if the contact is unblocked, then all the contacts in the array aren't blocked
if (![currentContact isBlocked]) {
areAllGivenContactsBlocked = NO;
break;
}
}
return areAllGivenContactsBlocked;
}
/*!
* @brief Block or unblock participants of the active chat in a chat window
*
* If all the participants of the chat are blocked, attempt to unblock each
* Else, attempt to block those that are not already blocked.
* Then, Update the item for the chat.
*
* We have to do it this way because a user can (un)block participants of
* a chat window in the background by command-clicking the toolbar item.
*
* @param senderItem The toolbar item that received the event
*/
- (IBAction)blockOrUnblockParticipants:(NSToolbarItem *)senderItem
{
NSEnumerator *windowEnumerator = [[NSApp windows] objectEnumerator];
NSWindow *currentWindow = nil;
NSToolbar *windowToolbar = nil;
NSToolbar *senderToolbar = [senderItem toolbar];
AIChat *activeChatInWindow = nil;
NSArray *participants = nil;
//for each open window
while ((currentWindow = [windowEnumerator nextObject])) {
//if it has a toolbar
if ((windowToolbar = [currentWindow toolbar])) {
//do the toolbars match?
if (windowToolbar == senderToolbar) {
activeChatInWindow = [adium.interfaceController activeChatInWindow:currentWindow];
participants = [activeChatInWindow containedObjects];
//do the deed
BOOL shouldBlock = ![self areAllGivenContactsBlocked:participants];
NSString *format = (shouldBlock ?
AILocalizedString(@"Are you sure you want to block %@?",nil) :
AILocalizedString(@"Are you sure you want to unblock %@?",nil));
NSString *questionQualifier = [NSString stringWithFormat:AILocalizedString(@"%d contacts", nil),
activeChatInWindow.containedObjects.count];
if(activeChatInWindow.containedObjects.count == 1) {
questionQualifier = [[activeChatInWindow.containedObjects objectAtIndex:0] displayName];
}
if (NSRunAlertPanel([NSString stringWithFormat:format, questionQualifier],
@"",
(shouldBlock ? BLOCK : UNBLOCK),
AILocalizedString(@"Cancel", nil),
nil) == NSAlertDefaultReturn) {
[self setPrivacy:shouldBlock forContacts:participants];
[self updateToolbarItem:senderItem forChat:activeChatInWindow];
}
break;
}
}
}
}
#pragma mark -
#pragma mark Protocols
/*!
* @brief Update any chat with the list object
*
* If the list object is (un)blocked, update any chats that we my have open with it.
*/
- (NSSet *)updateListObject:(AIListObject *)inObject keys:(NSSet *)inModifiedKeys silent:(BOOL)silent
{
if ([inModifiedKeys containsObject:@"isBlocked"]) {
[self updateToolbarItemForObject:inObject];
}
return nil;
}
#pragma mark -
#pragma mark Notifications
/*!
* @brief Toolbar has added an instance of the chat block toolbar item
*/
- (void)toolbarWillAddItem:(NSNotification *)notification
{
NSToolbarItem *item = [[notification userInfo] objectForKey:@"item"];
if ([[item itemIdentifier] isEqualToString:TOOLBAR_ITEM_IDENTIFIER]) {
//If this is the first item added, start observing for chats becoming visible so we can update the item
if ([chatToolbarItems count] == 0) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(chatDidBecomeVisible:)
name:@"AIChatDidBecomeVisible"
object:nil];
}
[self updateToolbarItem:item forChat:adium.interfaceController.activeChat];
[chatToolbarItems addObject:item];
}
}
/*!
* @brief A toolbar item was removed
*/
- (void)toolbarDidRemoveItem:(NSNotification *)notification
{
NSToolbarItem *item = [[notification userInfo] objectForKey:@"item"];
[chatToolbarItems removeObject:item];
if ([chatToolbarItems count] == 0) {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:@"AIChatDidBecomeVisible"
object:nil];
}
}
/*!
* @brief A chat became visible in a window.
*
* Update the window's (un)block toolbar item to reflect the block state of a list object
*
* @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"]];
}
#pragma mark -
#pragma mark Toolbar Item Update Methods
/*!
* @brief Update the toolbar icon in a chat for a particular contact
*
* @param inObject The list object we want to update the toolbar item for
*/
- (void)updateToolbarItemForObject:(AIListObject *)inObject
{
AIChat *chat = nil;
NSWindow *window = nil;
//Update the icon in the toolbar for this contact if a chat is open and we have any toolbar items
if (([chatToolbarItems count] > 0) &&
[inObject isKindOfClass:[AIListContact class]] &&
(chat = [adium.chatController existingChatWithContact:(AIListContact *)inObject]) &&
(window = [adium.interfaceController windowForChat:chat])) {
[self updateToolbarIconOfChat:chat
inWindow:window];
}
}
/*!
* @brief Update the toolbar item for the particpants of a particular chat
*
* @param item The toolbar item to modify
* @param chat The chat for which the participants are participating in
*/
- (void)updateToolbarItem:(NSToolbarItem *)item forChat:(AIChat *)chat
{
if ([self areAllGivenContactsBlocked:[chat containedObjects]]) {
//assume unblock appearance
[item setLabel:UNBLOCK];
[item setPaletteLabel:UNBLOCK];
[item setImage:[blockedToolbarIcons valueForKey:TOOLBAR_UNBLOCK_ICON_KEY]];
} else {
//assume block appearance
[item setLabel:BLOCK];
[item setPaletteLabel:BLOCK];
[item setImage:[blockedToolbarIcons valueForKey:TOOLBAR_BLOCK_ICON_KEY]];
}
}
/*!
* @brief Update the (un)block toolbar icon in a chat
*
* @param chat The chat with the participants
* @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];
NSToolbarItem *item;
while ((item = [enumerator nextObject])) {
if ([[item itemIdentifier] isEqualToString:TOOLBAR_ITEM_IDENTIFIER]) {
[self updateToolbarItem:item forChat:chat];
break;
}
}
}
@end