Update the icon in the personal preferences if it's changed elsewhere (the contact...
[adiumx.git] / Source / AIExtendedStatusPlugin.m
blobb5cf380e2ea3e20b5760e9df39c95ff99aa8f5bb
1 /* 
2  * Adium is the legal property of its developers, whose names are listed in the copyright file included
3  * with this source distribution.
4  * 
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.
8  * 
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.
12  * 
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.
15  */
17 #import "AIExtendedStatusPlugin.h"
18 #import <Adium/AIContactControllerProtocol.h>
19 #import <Adium/AIContentControllerProtocol.h>
20 #import <Adium/AIPreferenceControllerProtocol.h>
21 #import <AIUtilities/AIMutableOwnerArray.h>
22 #import <AIUtilities/AIAttributedStringAdditions.h>
23 #import <AIUtilities/AIMutableStringAdditions.h>
24 #import <Adium/AIAbstractListController.h>
25 #import <Adium/AIListObject.h>
26 #import <Adium/AIListContact.h>
28 #define STATUS_MAX_LENGTH       100
30 @interface AIExtendedStatusPlugin (PRIVATE)
31 - (void)preferencesChanged:(NSNotification *)notification;
32 @end
34 /*!
35  * @class AIExtendedStatusPlugin
36  * @brief Manage the 'extended status' shown in the contact list
37  *
38  * If the contact list layout calls for displaying a status message or idle time (or both), this component manages
39  * generating the appropriate string, storing it in the @"ExtendedStatus" status object, and updating it as necessary.
40  */
41 @implementation AIExtendedStatusPlugin
43 /*!
44  * @brief Install
45  */
46 - (void)installPlugin
48         [[adium preferenceController] registerPreferenceObserver:self forGroup:PREF_GROUP_LIST_LAYOUT];
49         
50         whitespaceAndNewlineCharacterSet = [[NSCharacterSet whitespaceAndNewlineCharacterSet] retain];
53 /*!
54  * @brief Uninstall
55  */
56 - (void)uninstallPlugin
58         [[adium preferenceController] unregisterPreferenceObserver:self];
59         [[adium contactController] unregisterListObjectObserver:self];
62 /*!
63  * @brief Preferences changes
64  *
65  * PREF_GROUP_LIST_LAYOUT changed; update our list objects if needed.
66  */
67 - (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key
68                                                         object:(AIListObject *)object preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
70         BOOL oldShowStatus = showStatus;
71         BOOL oldShowIdle = showIdle;
72         
73         EXTENDED_STATUS_STYLE statusStyle = [[prefDict objectForKey:KEY_LIST_LAYOUT_EXTENDED_STATUS_STYLE] intValue];
74         showStatus = ((statusStyle == STATUS_ONLY) || (statusStyle == IDLE_AND_STATUS));
75         showIdle = ((statusStyle == IDLE_ONLY) || (statusStyle == IDLE_AND_STATUS));
76         
77         if (firstTime) {
78                 [[adium contactController] registerListObjectObserver:self];
79         } else {
80                 if ((oldShowStatus != showStatus) || (oldShowIdle != showIdle)) {
81                         [[adium contactController] updateAllListObjectsForObserver:self];
82                 }
83         }
86 /*!
87  * @brief Update list object's extended status messages
88  */
89 - (NSSet *)updateListObject:(AIListObject *)inObject keys:(NSSet *)inModifiedKeys silent:(BOOL)silent
91         NSSet           *modifiedAttributes = nil;
93         //Idle time
94     if ((inModifiedKeys == nil || 
95                  (showIdle && [inModifiedKeys containsObject:@"Idle"]) ||
96                  (showStatus && ([inModifiedKeys containsObject:@"StatusMessage"] ||
97                                                  [inModifiedKeys containsObject:@"ContactListDisplayName"] ||
98                                                  [inModifiedKeys containsObject:@"StatusName"]))) &&
99                 [inObject isKindOfClass:[AIListContact class]]){
100                 NSMutableString *statusMessage = nil;
101                 NSString                *finalMessage = nil;
102                 int                             idle;
104                 //Work at the parent contact (metacontact, etc.) level for extended status, since that's what's displayed in the contact list
105                 inObject = [(AIListContact *)inObject parentContact];
107                 if (showStatus) {
108                         NSAttributedString *filteredMessage;
110                         filteredMessage = [[adium contentController] filterAttributedString:[(AIListContact *)inObject contactListStatusMessage]
111                                                                                                                                 usingFilterType:AIFilterContactList
112                                                                                                                                           direction:AIFilterIncoming
113                                                                                                                                                 context:inObject];
114                         statusMessage = [[[[filteredMessage string] stringByTrimmingCharactersInSet:whitespaceAndNewlineCharacterSet] mutableCopy] autorelease];
116                         //Incredibly long status messages are slow to size, so we crop them to a reasonable length
117                         if ([statusMessage length] > STATUS_MAX_LENGTH) {
118                                 [statusMessage deleteCharactersInRange:NSMakeRange(STATUS_MAX_LENGTH,
119                                                                                                                                    [statusMessage length] - STATUS_MAX_LENGTH)];
120                         }
122                         /* Linebreaks in the status message cause vertical alignment issues. */
123                         [statusMessage convertNewlinesToSlashes];       
124                 }
126                 idle = (showIdle ? [inObject integerStatusObjectForKey:@"Idle"] : 0);
128                 //
129                 if (idle > 0 && statusMessage) {
130                         finalMessage = [NSString stringWithFormat:@"(%@) %@",[self idleStringForSeconds:idle], statusMessage];
131                 } else if (idle > 0) {
132                         finalMessage = [NSString stringWithFormat:@"(%@)",[self idleStringForSeconds:idle]];
133                 } else {
134                         finalMessage = statusMessage;
135                 }
137                 [[inObject displayArrayForKey:@"ExtendedStatus"] setObject:finalMessage withOwner:self];
138                 modifiedAttributes = [NSSet setWithObject:@"ExtendedStatus"];
139         }
140         
141    return modifiedAttributes;
146  * @brief Determine the idle string
148  * @param seconds Number of seconds idle
149  * @result A localized string to display for the idle time
150  */
151 - (NSString *)idleStringForSeconds:(int)seconds
153         NSString        *idleString;
154         
155         //Create the idle string
156         if (seconds > 599400) {//Cap idle at 999 Hours (999*60*60 seconds)
157                 idleString = AILocalizedString(@"Idle",nil);
158         } else if (seconds >= 600) {
159                 idleString = [NSString stringWithFormat:@"%ih",seconds / 60];
160         } else if (seconds >= 60) {
161                 idleString = [NSString stringWithFormat:@"%i:%02i",seconds / 60, seconds % 60];
162         } else {
163                 idleString = [NSString stringWithFormat:@"%i",seconds];
164         }
165         
166         return idleString;
169 @end