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 again

wbowling / adium (fork of adium / adium)

Fork of Adium for patches/improvements

Clone this repository (size: 338.7 MB): HTTPS / SSH
hg clone https://bitbucket.org/wbowling/adium
hg clone ssh://hg@bitbucket.org/wbowling/adium

adium / Source / CBContactCountingDisplayPlugin.m

/* 
 * 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/AIContactControllerProtocol.h>
#import <Adium/AIMenuControllerProtocol.h>
#import "CBContactCountingDisplayPlugin.h"
#import <AIUtilities/AIDictionaryAdditions.h>
#import <AIUtilities/AIMenuAdditions.h>
#import <AIUtilities/AIMutableOwnerArray.h>
#import <Adium/AIAccount.h>
#import <Adium/AIListContact.h>
#import <Adium/AIListObject.h>
#import <Adium/AIListGroup.h>

#define CONTACT_COUNTING_DISPLAY_DEFAULT_PREFS  @"ContactCountingDisplayDefaults"

#define SHOW_COUNT_ONLINE_CONTACTS_TITLE                        AILocalizedString(@"Show Group Online Count", nil)
#define SHOW_COUNT_ALL_CONTACTS_TITLE                           AILocalizedString(@"Show Group Total Count", nil)

#define KEY_COUNT_ALL_CONTACTS                                  @"Count All Contacts"
#define KEY_COUNT_ONLINE_CONTACTS                               @"Count Online Contacts"

#define KEY_HIDE_CONTACT_LIST_GROUPS                    @"Hide Contact List Groups"

/*!
 * @class CBContactCountingDisplayPlugin
 *
 * @brief Component to handle displaying counts of contacts, both online and total, next to group names
 *
 * This componenet adds two menu items, "Count All Contacts" and "Count Online Contacts." Both default to being off.
 * When on, these options display the appropriate count for an AIListGroup's contained objects.
 */
@implementation CBContactCountingDisplayPlugin

/*!
 * @brief Install
 */
- (void)installPlugin
{
    //register our defaults
    [adium.preferenceController registerDefaults:[NSDictionary dictionaryNamed:CONTACT_COUNTING_DISPLAY_DEFAULT_PREFS 
                                                                                                                                                forClass:[self class]] 
                                                                                  forGroup:PREF_GROUP_CONTACT_LIST];
        
    //init our menu items
    menuItem_countOnlineObjects = [[NSMenuItem alloc] initWithTitle:SHOW_COUNT_ONLINE_CONTACTS_TITLE 
                                                                                                                 target:self 
                                                                                                                 action:@selector(toggleMenuItem:)
                                                                                                  keyEquivalent:@""];
    [adium.menuController addMenuItem:menuItem_countOnlineObjects toLocation:LOC_View_Counting_Toggles];                

    menuItem_countAllObjects = [[NSMenuItem alloc] initWithTitle:SHOW_COUNT_ALL_CONTACTS_TITLE
                                                                                                                 target:self 
                                                                                                                 action:@selector(toggleMenuItem:)
                                                                                                  keyEquivalent:@""];
        [adium.menuController addMenuItem:menuItem_countAllObjects toLocation:LOC_View_Counting_Toggles];               
    
        //set up the prefs
        countAllObjects = NO;
        countOnlineObjects = NO;
        
        [adium.preferenceController registerPreferenceObserver:self forGroup:PREF_GROUP_CONTACT_LIST];
        [adium.preferenceController registerPreferenceObserver:self forGroup:PREF_GROUP_CONTACT_LIST_DISPLAY];
        
        [[AIContactObserverManager sharedManager] registerListObjectObserver:self];
}

/*!
 * @brief Preferences changed
 *
 * PREF_GROUP_CONTACT_LIST preferences changed; update our counting display as necessary.
 */
- (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key
                                                        object:(AIListObject *)object preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
{
        // Don't update for specific objects.
        if (object != nil)
                return;
        
        if ([group isEqualToString:PREF_GROUP_CONTACT_LIST] &&
                ([key isEqualToString:KEY_COUNT_ONLINE_CONTACTS] || [key isEqualToString:KEY_COUNT_ALL_CONTACTS] || firstTime)) {
                countAllObjects = [[prefDict objectForKey:KEY_COUNT_ALL_CONTACTS] boolValue];
                countOnlineObjects = [[prefDict objectForKey:KEY_COUNT_ONLINE_CONTACTS] boolValue];
                
                [[AIContactObserverManager sharedManager] updateAllListObjectsForObserver:self];
        
                [menuItem_countOnlineObjects setState:countOnlineObjects];
                [menuItem_countAllObjects setState:countAllObjects];

        } else if (([group isEqualToString:PREF_GROUP_CONTACT_LIST_DISPLAY]) &&
                           (!key || [key isEqualToString:KEY_HIDE_CONTACT_LIST_GROUPS])) {              
                showingGroups = ![[prefDict objectForKey:KEY_HIDE_CONTACT_LIST_GROUPS] boolValue];
        }
}

/*!
 * @brief Update the counts when a group changes its object count or a contact signs on or off
 */
- (NSSet *)updateListObject:(AIListObject *)inObject keys:(NSSet *)inModifiedKeys silent:(BOOL)silent
{    
        NSMutableSet    *groups = [NSMutableSet set];

        //We never update for an AIAccount object
        
        if ([inObject isKindOfClass:[AIListContact class]] && [inModifiedKeys containsObject:@"Online"]) {
                // We need to update *all* of this contact's groups for its online change.
                [groups unionSet:inObject.groups];
        } else if ([inObject isKindOfClass:[AIListGroup class]]
                           && (!inModifiedKeys || ([inModifiedKeys containsObject:@"ObjectCount"] || [inModifiedKeys containsObject:@"VisibleObjectCount"]))
                           && ![inObject.UID isEqualToString:ADIUM_ROOT_GROUP_NAME]) {
                
                /* We check against a nil inModifiedKeys so we can remove our Counting information from the display when the user
                 * toggles it off.
                 *
                 * We update for any group which isn't the root group when its contained objects count changes.
                 */     
                [groups addObject:inObject];
        } else {
                // We don't need to update anything.
                return nil;
        }

        for (AIListGroup *inGroup in groups) {

                NSString                *countString = nil;

                NSUInteger onlineObjects = [[inGroup.visibleContainedObjects valueForKeyPath:@"@sum.Online"] integerValue];
                NSUInteger totalObjects = inGroup.countOfContainedObjects;

                /*
                 * Create our count string for displaying in the list group's cell
                 * If the number of online objects is the same as the number of total objects, just display one number.
                 * If the group is the offline group, just display the number of total objects if we should.
                 */
                if (countOnlineObjects && countAllObjects && (onlineObjects != totalObjects) && (inGroup != adium.contactController.offlineGroup)) {
                        countString = [NSString stringWithFormat:AILocalizedString(@"%lu of %lu", "Used in the display for the contact list for the number of online contacts out of the number of total contacts"),
                                                                                                        onlineObjects, totalObjects];
                } else if (countAllObjects) {
                        countString = [NSString stringWithFormat:@"%lu", totalObjects];
                } else if (inGroup != adium.contactController.offlineGroup) {
                        countString = [NSString stringWithFormat:@"%lu", onlineObjects];
                } else {
                        countString = [NSString stringWithString:@""];
                }

                [inGroup setValue:countString
                          forProperty:@"Count Text"
                                   notify:NotifyNever];
                [inGroup setValue:[NSNumber numberWithBool:(countOnlineObjects || countAllObjects)]
                          forProperty:@"Show Count"
                                   notify:NotifyNever];

                [[AIContactObserverManager sharedManager] listObjectAttributesChanged:inGroup
                                                                                                                                 modifiedKeys:[NSSet setWithObject:@"Count Text"]];
        }
        
        return nil;
}

/*!
 * @brief User toggled one of our two menu items
 */
- (void)toggleMenuItem:(id)sender
{
        if (sender == menuItem_countOnlineObjects) {
                BOOL    newPref = !countOnlineObjects;

                //Toggle and set, which will call back on preferencesChanged: above
                [adium.preferenceController setPreference:[NSNumber numberWithBool:newPref]
                                                                                         forKey:KEY_COUNT_ONLINE_CONTACTS
                                                                                          group:PREF_GROUP_CONTACT_LIST];

        } else if (sender == menuItem_countAllObjects) {
                BOOL    newPref = !countAllObjects;

                //Toggle and set, which will call back on preferencesChanged: above
                [adium.preferenceController setPreference:[NSNumber numberWithBool:newPref]
                                                                                         forKey:KEY_COUNT_ALL_CONTACTS
                                                                                          group:PREF_GROUP_CONTACT_LIST];
    }
}

- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
{
    if ((menuItem == menuItem_countOnlineObjects) || (menuItem == menuItem_countAllObjects)) {
                return showingGroups;
        }
        
        return YES;
}

/*
 * Uninstall
 */
- (void)uninstallPlugin
{
    //we are no longer an observer
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [[AIContactObserverManager sharedManager] unregisterListObjectObserver:self];
        [adium.preferenceController unregisterPreferenceObserver:self];
}

@end