Performed [21405] and [21406], moving the contact list to Source, on adium-1.1
[adiumx.git] / Source / ESAutoAwayPlugin.m
blob74d34d7cacf0317a8e85b6161c42d54378f77518
1 //
2 //  ESAutoAwayPlugin.m
3 //  Adium
4 //
5 //  Created by Evan Schoenberg on 3/4/05.
6 //  Copyright 2006 The Adium Team. All rights reserved.
7 //
9 #import "ESAutoAwayPlugin.h"
10 #import <Adium/AIAccountControllerProtocol.h>
11 #import <Adium/AIPreferenceControllerProtocol.h>
12 #import "AIStatusController.h"
13 #import <Adium/AIAccount.h>
14 #import <Adium/AIStatus.h>
15 #import <Adium/AIStatusGroup.h>
17 /*!
18  * @class ESAutoAwayPlugin
19  * @brief Provides auto-away functionality for the state system
20  *
21  * This class implements auto-away.  When the user is inactive for a period of time specified by the user,
22  * all accounts which are online and available are set to a specified status state. 
23  */
24 @implementation ESAutoAwayPlugin
26 /*!
27  * @brief Initialize the auto-away system
28  *
29  * When AIMachineIdleUpdateNotification is posted, check the time idle against the time at which to switch available
30  * accounts to a state (as specified by the user in the preferences).
31  */
32 - (void)installPlugin
34         automaticAwaySet = NO;
36         [[adium notificationCenter] addObserver:self
37                                                                    selector:@selector(machineIdleUpdate:)
38                                                                            name:AIMachineIdleUpdateNotification
39                                                                          object:nil];
40         [[adium notificationCenter] addObserver:self
41                                                                    selector:@selector(machineIsActive:)
42                                                                            name:AIMachineIsActiveNotification
43                                                                          object:nil];
44         
45         //Observe preference changes for updating when and how we should automatically change our state
46         [[adium preferenceController] registerPreferenceObserver:self 
47                                                                                                         forGroup:PREF_GROUP_STATUS_PREFERENCES];        
50 /*!
51 * Deallocate
52  */
53 - (void)dealloc
55         [previousStatusStateDict release];
56         [accountsToReconnect release];
57         [autoAwayID release];
58         [[adium notificationCenter] removeObserver:self];
59         [[adium preferenceController] unregisterPreferenceObserver:self];
60         [super dealloc];
63 /*!
64  * @brief Preferences changed
65  *
66  * Note whether we are supposed to change states after a specified time.
67  */
68 - (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key
69                                                         object:(AIListObject *)object preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
71         [autoAwayID release];
72         autoAwayID = [[prefDict objectForKey:KEY_STATUS_AUTO_AWAY_STATUS_STATE_ID] retain];
74         autoAway = (autoAwayID ? 
75                                 [[prefDict objectForKey:KEY_STATUS_AUTO_AWAY] boolValue] :
76                                 NO);
78         autoAwayInterval = [[prefDict objectForKey:KEY_STATUS_AUTO_AWAY_INTERVAL] doubleValue];
81 /*!
82 * @brief Invoked when machine idle updates
83  *
84  * Invoked when Adium has an update on machine activity.  If we are not yet idle, and the current length of inactivity
85  * is over the threshold, set our accounts to idle status.
86  */
87 - (void)machineIdleUpdate:(NSNotification *)notification
89         if (!automaticAwaySet && autoAway) {
90                 double  duration = [[[notification userInfo] objectForKey:@"Duration"] doubleValue];
91                 
92                 //If we are over the away threshold, set our available accounts to away
93                 if (duration > autoAwayInterval) {
94                         NSEnumerator    *enumerator;
95                         AIAccount               *account;
96                         AIStatusItem    *targetStatusState;
97                         
98                         if (!previousStatusStateDict) previousStatusStateDict = [[NSMutableDictionary alloc] init];
99                         
100                         targetStatusState = [[adium statusController] statusStateWithUniqueStatusID:autoAwayID];
101                         
102                         if ([targetStatusState isKindOfClass:[AIStatusGroup class]]) {
103                                 targetStatusState = [(AIStatusGroup *)targetStatusState anyContainedStatus];
104                         }
105                         
106                         if (targetStatusState) {
107                                 enumerator = [[[adium accountController] accounts] objectEnumerator];
108                                 while ((account = [enumerator nextObject])) {
109                                         AIStatus        *currentStatusState = [account statusState];
110                                         if ([currentStatusState statusType] == AIAvailableStatusType) {
111                                                 //Store the state the account is in at present
112                                                 [previousStatusStateDict setObject:currentStatusState
113                                                                                                         forKey:[NSNumber numberWithUnsignedInt:[account hash]]];
114                                                 
115                                                 if ([account online]) {
116                                                         //If online, set the state
117                                                         [account setStatusState:(AIStatus *)targetStatusState];
118                                                         
119                                                         //If we just brought the account offline, note that it will need to be reconnected later
120                                                         if ([targetStatusState statusType] == AIOfflineStatusType) {
121                                                                 if (!accountsToReconnect) accountsToReconnect = [[NSMutableSet alloc] init];
122                                                                 [accountsToReconnect addObject:account];
123                                                         }
124                                                         
125                                                 } else {
126                                                         //If offline, set the state without coming online
127                                                         [account setStatusStateAndRemainOffline:(AIStatus *)targetStatusState];
128                                                 }
129                                         }
130                                 }
131                         }
133                         automaticAwaySet = YES;
134                 }
135         }
139 * @brief Invoked when machine becomes active
141  * Invoked when Adium has an update on machine activity.  Restore any status states we overrode with auto-away.
142  */
143 - (void)machineIsActive:(NSNotification *)notification
145         if (automaticAwaySet) {
146                 NSEnumerator    *enumerator;
147                 AIAccount               *account;
148                 
149                 enumerator = [[[adium accountController] accounts] objectEnumerator];
150                 while ((account = [enumerator nextObject])) {
151                         AIStatus                *targetStatusState;
152                         NSNumber                *accountHash = [NSNumber numberWithUnsignedInt:[account hash]];
153                         
154                         targetStatusState = [previousStatusStateDict objectForKey:accountHash];
155                         if (targetStatusState) {
156                                 if ([account online] || [accountsToReconnect containsObject:account]) {
157                                         //If online or needs to be reconnected, set the previous state, going online if necessary
158                                         [account setStatusState:targetStatusState];
159                                 } else {
160                                         //If offline, set the state without coming online
161                                         [account setStatusStateAndRemainOffline:targetStatusState];
162                                 }
163                         }
164                 }
166                 [previousStatusStateDict release]; previousStatusStateDict = nil;
167                 [accountsToReconnect release]; accountsToReconnect = nil;
168                 
169                 automaticAwaySet = NO;
170         }
173 @end