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 "AIContactController.h"
18 #import "AIMenuController.h"
19 #import "AIPreferenceController.h"
20 #import "CBContactCountingDisplayPlugin.h"
21 #import <AIUtilities/AIDictionaryAdditions.h>
22 #import <AIUtilities/AIMenuAdditions.h>
23 #import <AIUtilities/AIMutableOwnerArray.h>
24 #import <Adium/AIAccount.h>
25 #import <Adium/AIListContact.h>
26 #import <Adium/AIListObject.h>
27 #import <Adium/AIListGroup.h>
29 #define CONTACT_COUNTING_DISPLAY_DEFAULT_PREFS @"ContactCountingDisplayDefaults"
31 #define COUNT_ONLINE_CONTACTS_TITLE AILocalizedString(@"Show Group Online Count", nil)
32 #define COUNT_ALL_CONTACTS_TITLE AILocalizedString(@"Show Group Total Count", nil)
34 #define PREF_GROUP_CONTACT_LIST @"Contact List"
35 #define KEY_COUNT_ALL_CONTACTS @"Count All Contacts"
36 #define KEY_COUNT_ONLINE_CONTACTS @"Count Online Contacts"
39 * @class CBContactCountingDisplayPlugin
41 * @brief Component to handle displaying counts of contacts, both online and total, next to group names
43 * This componenet adds two menu items, "Count All Contacts" and "Count Online Contacts." Both default to being off.
44 * When on, these options display the appropriate count for an AIListGroup's contained objects.
46 @implementation CBContactCountingDisplayPlugin
53 //register our defaults
54 [[adium preferenceController] registerDefaults:[NSDictionary dictionaryNamed:CONTACT_COUNTING_DISPLAY_DEFAULT_PREFS
55 forClass:[self class]]
56 forGroup:PREF_GROUP_CONTACT_LIST];
59 menuItem_countOnlineObjects = [[NSMenuItem alloc] initWithTitle:COUNT_ONLINE_CONTACTS_TITLE
61 action:@selector(toggleMenuItem:)
63 [[adium menuController] addMenuItem:menuItem_countOnlineObjects toLocation:LOC_View_Toggles];
65 menuItem_countAllObjects = [[NSMenuItem alloc] initWithTitle:COUNT_ALL_CONTACTS_TITLE
67 action:@selector(toggleMenuItem:)
69 [[adium menuController] addMenuItem:menuItem_countAllObjects toLocation:LOC_View_Toggles];
73 countOnlineObjects = NO;
75 [[adium preferenceController] registerPreferenceObserver:self forGroup:PREF_GROUP_CONTACT_LIST];
79 * @brief Preferences changed
81 * PREF_GROUP_CONTACT_LIST preferences changed; update our counting display as necessary.
83 - (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key
84 object:(AIListObject *)object preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
86 BOOL oldCountAllObjects = countAllObjects;
87 BOOL oldCountOnlineObjects = countOnlineObjects;
89 countAllObjects = [[prefDict objectForKey:KEY_COUNT_ALL_CONTACTS] boolValue];
90 countOnlineObjects = [[prefDict objectForKey:KEY_COUNT_ONLINE_CONTACTS] boolValue];
92 if ((countAllObjects && !oldCountAllObjects) || (countOnlineObjects && !oldCountOnlineObjects)){
93 //One of the displays is on, but it was off before
95 if (!oldCountAllObjects && !oldCountOnlineObjects){
96 //Install our observer if we are now counting contacts in some form but weren't before
97 //This will update all list objects.
98 [[adium contactController] registerListObjectObserver:self];
101 [[adium contactController] updateAllListObjectsForObserver:self];
104 }else if ((!countAllObjects && oldCountAllObjects) || (!countOnlineObjects && oldCountOnlineObjects)){
105 //One of the displays is off, but it was on before
108 [[adium contactController] updateAllListObjectsForObserver:self];
110 if (!countAllObjects && !countOnlineObjects){
111 //Remove our observer since we are now doing no counting
112 [[adium contactController] unregisterListObjectObserver:self];
116 if([menuItem_countAllObjects state] != countAllObjects) {
117 [menuItem_countAllObjects setState:countAllObjects];
119 if([menuItem_countOnlineObjects state] != countOnlineObjects) {
120 [menuItem_countOnlineObjects setState:countOnlineObjects];
125 * @brief Update the counts when a group changes its object count or a contact signs on or off
127 - (NSSet *)updateListObject:(AIListObject *)inObject keys:(NSSet *)inModifiedKeys silent:(BOOL)silent
129 NSSet *modifiedAttributes = nil;
131 //We never update for an AIAccount object
132 if([inObject isKindOfClass:[AIAccount class]]) return nil;
134 /* We check against a nil inModifiedKeys so we can remove our Counting information from the display when the user
137 * We update for any group which isn't the root group when its contained objects count changes.
138 * We update a contact's containing group when its online state changes.
140 if((inModifiedKeys == nil) ||
141 ((countOnlineObjects || countAllObjects) &&
142 (([inObject isKindOfClass:[AIListGroup class]] && [inModifiedKeys containsObject:@"ObjectCount"] && ![[inObject UID] isEqualToString:ADIUM_ROOT_GROUP_NAME]) ||
143 ([inObject isKindOfClass:[AIListContact class]] && [inModifiedKeys containsObject:@"Online"])))){
145 //Obtain the group we want to work with -- for a contact, use its parent group.
146 AIListGroup *targetGroup = ([inObject isKindOfClass:[AIListContact class]] ?
147 [inObject parentGroup] :
150 NSString *countString = nil;
151 int onlineObjects = 0, totalObjects = 0;
153 //Obtain a count of online objects in this group
154 if(countOnlineObjects){
155 AIListObject *containedObject;
156 NSEnumerator *enumerator;
159 enumerator = [targetGroup objectEnumerator];
160 while(containedObject = [enumerator nextObject]){
161 if([containedObject online]) onlineObjects++;
165 //Obtain a count of all objects in this group
167 totalObjects = [[targetGroup statusObjectForKey:@"ObjectCount"] intValue];
170 //Build a string to add to the right of the name which shows any information we just extracted
171 if (countOnlineObjects && countAllObjects){
172 countString = [NSString stringWithFormat:@" (%i/%i)", onlineObjects, totalObjects];
173 }else if(countAllObjects){
174 countString = [NSString stringWithFormat:@" (%i)", totalObjects];
175 }else if(countOnlineObjects){
176 countString = [NSString stringWithFormat:@" (%i)", onlineObjects];
180 AIMutableOwnerArray *rightTextArray = [targetGroup displayArrayForKey:@"Right Text"];
182 [rightTextArray setObject:countString withOwner:self priorityLevel:High_Priority];
183 modifiedAttributes = [NSSet setWithObject:@"Right Text"];
185 AIMutableOwnerArray *rightTextArray = [targetGroup displayArrayForKey:@"Right Text" create:NO];
187 //If there is a right text object now but there shouldn't be anymore, remove it
188 if ([rightTextArray objectWithOwner:self]){
189 [rightTextArray setObject:nil withOwner:self priorityLevel:High_Priority];
190 modifiedAttributes = [NSSet setWithObject:@"Right Text"];
195 return(modifiedAttributes);
199 * @brief User toggled one of our two menu items
201 - (void)toggleMenuItem:(id)sender
203 if(sender == menuItem_countOnlineObjects || sender == menuItem_countAllObjects) {
204 BOOL newState = ![sender state];
206 //Toggle and set, which will call back on preferencesChanged: above
207 [sender setState:newState];
208 [[adium preferenceController] setPreference:[NSNumber numberWithBool:newState]
209 forKey:(sender == menuItem_countAllObjects ?
210 KEY_COUNT_ALL_CONTACTS :
211 KEY_COUNT_ONLINE_CONTACTS)
212 group:PREF_GROUP_CONTACT_LIST];
219 - (void)uninstallPlugin
221 //we are no longer an observer
222 [[adium notificationCenter] removeObserver:self];
223 [[adium contactController] unregisterListObjectObserver:self];
224 [[adium preferenceController] unregisterPreferenceObserver:self];