pt_BR strings updates
[adiumx.git] / Source / ESAwayStatusWindowController.m
blob37efd9877fc9b365e40b3d0d18e6cd21fbe95a26
1 //
2 //  ESAwayStatusWindowController.m
3 //  Adium
4 //
5 //  Created by Evan Schoenberg on 4/12/05.
6 //  Copyright 2006 The Adium Team. All rights reserved.
7 //
9 #import "ESAwayStatusWindowController.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/AIStatusIcons.h>
16 #import <Adium/AIServiceIcons.h>
17 #import <AIUtilities/AIArrayAdditions.h>
18 #import <AIUtilities/AIAttributedStringAdditions.h>
19 #import <AIUtilities/AIImageTextCell.h>
20 #import <AIUtilities/AITableViewAdditions.h>
21 #import <AIUtilities/AIApplicationAdditions.h>
24 #define AWAY_STATUS_WINDOW_NIB                                  @"AwayStatusWindow"
25 #define KEY_AWAY_STATUS_WINDOW_FRAME                    @"Away Status Window Frame"
27 @interface ESAwayStatusWindowController (PRIVATE)
28 - (void)localizeButtons;
29 - (void)configureStatusWindow;
30 - (NSAttributedString *)attributedStatusTitleForStatus:(AIStatus *)statusState withIcon:(NSImage *)statusIcon;
31 - (NSArray *)awayAccounts;
32 - (void)setupMultistatusTable;
33 @end
35 /*!
36  * @class ESAwayStatusWindowController
37  * @brief Window controller for the status window which optionally shows when one or more accounts are away or invisible
38  */
39 @implementation ESAwayStatusWindowController
41 static ESAwayStatusWindowController     *sharedInstance = nil;
42 static BOOL                                                     alwaysOnTop = NO;
43 static BOOL                                                     hideInBackground = NO;
45 /*!
46  * @brief Update the visibility of the status window
47  *
48  * Opens or closes the window if necessary.
49  *
50  * If shouldBeVisibile is YES and the window is already visible, updates its contents to reflect the current status.
51  * If shouldBeVisible is NO and the window is already not visibile, no action is taken.
52  */
53 + (void)updateStatusWindowWithVisibility:(BOOL)shouldBeVisible
55         if (shouldBeVisible) {
56                 if (sharedInstance) {
57                         //Update the window's configuration
58                         [sharedInstance configureStatusWindow];
59                 } else {
60                         //Create a new shared instance, which will be configured automatically once the window loads
61                         sharedInstance = [[self alloc] initWithWindowNibName:AWAY_STATUS_WINDOW_NIB];
62                         [sharedInstance showWindow:nil];
63                 }
64         
65         } else {
66                 if (sharedInstance) {
67                         //If the window is current visible, close it
68                         [sharedInstance closeWindow:nil];
69                 }
70         }
73 + (void)setAlwaysOnTop:(BOOL)flag
75         alwaysOnTop = flag;
76         
77         if (sharedInstance) {
78                 //Update any open window
79                 [[sharedInstance window] setLevel:(alwaysOnTop ? NSFloatingWindowLevel : NSNormalWindowLevel)];
80         }
83 + (void)setHideInBackground:(BOOL)flag
85         hideInBackground = flag;
86         
87         if (sharedInstance) {
88                 //Update any open window
89                 [[sharedInstance window] setHidesOnDeactivate:hideInBackground];
90         }
91 }       
93 /*!
94  * @brief Window size and position autosave name
95  */
96 - (NSString *)adiumFrameAutosaveName
98         return KEY_AWAY_STATUS_WINDOW_FRAME;
102  * @brief Window loaded
103  */
104 - (void)windowDidLoad
106         //Call super first so we get our placement before performing autosizing
107         [super windowDidLoad];
108         
109         [[self window] setLevel:(alwaysOnTop ? NSFloatingWindowLevel : NSNormalWindowLevel)];
110         [[self window] setHidesOnDeactivate:hideInBackground];
112         /* Set a more reasonable minimum size after the window is sized using our nib's specification.
113          * NSPanel behaves oddly with minimum size... it seems to increase the nib-specified minimum by 11.
114          */
115         [[self window] setMinSize:NSMakeSize([[self window] minSize].width, 80)];
116         
117         //Setup the textviews
118     [textView_singleStatus setHorizontallyResizable:NO];
119     [textView_singleStatus setVerticallyResizable:YES];
120     [textView_singleStatus setDrawsBackground:NO];
121         [textView_singleStatus setMinSize:NSZeroSize];
122     [scrollView_singleStatus setDrawsBackground:NO];
124         [self localizeButtons];
125         [self setupMultistatusTable];
127         [self configureStatusWindow];
128         
129         [[adium notificationCenter] addObserver:self
130                                                                    selector:@selector(statusIconSetChanged:)
131                                                                            name:AIStatusIconSetDidChangeNotification
132                                                                          object:nil];   
136  * @brief Window will close
138  * Release and clear the reference to our shared instance
139  */
140 - (void)windowWillClose:(id)sender
142         [super windowWillClose:sender];
144         /* Hack of the day.  The table view crashes when the window is released out from under it after it has reloaded data because
145          * it thinks it needs display. It thinks that because we are animating the window's resizing process.  We could do animate:NO
146          * in configureStatusWindow, but that wouldn't be as pretty.
147          */
148         [tableView_multiStatus setDataSource:nil];
150     //Clean up and release the shared instance
151     [sharedInstance autorelease]; sharedInstance = nil;
155  * @brief Deallocate
156  */
157 - (void)dealloc
159         [_awayAccounts release]; _awayAccounts = nil;
160         [[adium notificationCenter] removeObserver:self];
162         [super dealloc];
166  * @brief Configure status window for the current account status(es)
167  */
168  - (void)configureStatusWindow
170         NSWindow                *window = [self window];
171         BOOL                    allOnlineAccountsAreUnvailable;
172         AIStatusType    activeUnvailableStatusType;
173         NSString                *activeUnvailableStatusName = nil;
174         NSSet                   *relevantStatuses;
175         NSRect                  frame = [window frame];
176         int                             newHeight;
177         
178         [window setTitle:AILocalizedString(@"Current Status",nil)];
179         [_awayAccounts release]; _awayAccounts = nil;
181         relevantStatuses = [[adium statusController] activeUnavailableStatusesAndType:&activeUnvailableStatusType 
182                                                                                                                                                  withName:&activeUnvailableStatusName
183                                                                                                    allOnlineAccountsAreUnvailable:&allOnlineAccountsAreUnvailable];
184         
185         if (allOnlineAccountsAreUnvailable && ([relevantStatuses count] == 1)) {
186                 //Show the single status tab if all online accounts are unavailable and they are all in the same status state
187                 NSImage                         *statusIcon;
188                 NSAttributedString      *statusTitle;
190                 statusIcon = [AIStatusIcons statusIconForStatusName:activeUnvailableStatusName
191                                                                                                   statusType:activeUnvailableStatusType
192                                                                                                         iconType:AIStatusIconTab
193                                                                                                   direction:AIIconNormal];
194                 statusTitle = [self attributedStatusTitleForStatus:[relevantStatuses anyObject]
195                                                                                                   withIcon:statusIcon];
196                 
197                 [[textView_singleStatus textStorage] setAttributedString:statusTitle];
199                 newHeight = [statusTitle heightWithWidth:[textView_singleStatus frame].size.width] + 65;
200                 frame.origin.y -= (newHeight - frame.size.height);
201                 frame.size.height = newHeight;
202                         
203                 //Select the right tab view item
204                 [tabView_configuration selectTabViewItemWithIdentifier:@"singlestatus"];
205         } else {
206                 /* Show the multistatus tableview tab if accounts are in different states, which includes the case of only one
207                  * away state being in use but not all online accounts currently making use of it.
208                  */
209                 int                             requiredHeight;
211                 _awayAccounts = [[self awayAccounts] retain];
213                 [tableView_multiStatus reloadData];
215                 requiredHeight = (([tableView_multiStatus rowHeight] + [tableView_multiStatus intercellSpacing].height) *
216                                                   [_awayAccounts count]);
218                 newHeight = requiredHeight + 65;
219                 frame.origin.y -= (newHeight - frame.size.height);
220                 frame.size.height = newHeight;
222                 /* Multiple statuses */
223                 [tabView_configuration selectTabViewItemWithIdentifier:@"multistatus"];
224         }
225         
226         //Perform the window resizing as needed
227         [window setFrame:frame display:YES animate:YES];
231  * @brief Return the attributed status title for a status
233  * This method puts statusIcon into an NSTextAttachment and prefixes statusState's status message or title with it.
234  */
235 - (NSAttributedString *)attributedStatusTitleForStatus:(AIStatus *)statusState withIcon:(NSImage *)statusIcon
237         NSMutableAttributedString       *statusTitle;
238         NSTextAttachment                        *attachment;
239         NSTextAttachmentCell            *cell;
240         NSAttributedString                      *statusMessage;
241         
242         if ((statusMessage = [statusState statusMessage]) &&
243            ([statusMessage length])) {
244                 //Use the status message if it is set
245                 statusTitle = [statusMessage mutableCopy];
246                 [[statusTitle mutableString] insertString:@" "
247                                                                                   atIndex:0];
249         } else {
250                 //If it isn't, use the title
251                 NSDictionary                            *attributesDict;
253                 attributesDict = [NSDictionary dictionaryWithObject:[NSFont systemFontOfSize:0]
254                                                                                                          forKey:NSFontAttributeName];
256                 statusTitle = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@" %@",[statusState title]]
257                                                                                                                           attributes:attributesDict];
258         }
260         //Insert the image at the beginning
261         cell = [[NSTextAttachmentCell alloc] init];
262         [cell setImage:statusIcon];
264         attachment = [[NSTextAttachment alloc] init];
265         [attachment setAttachmentCell:cell];
266         [cell release];
268         [statusTitle insertAttributedString:[NSAttributedString attributedStringWithAttachment:attachment]
269                                                                 atIndex:0];
270         [attachment release];
272         return [statusTitle autorelease];
276  * @brief Return an array of all away accounts
277  */
278 - (NSArray *)awayAccounts
279 {       
280         NSMutableArray  *awayAccounts = [NSMutableArray array]; 
281         NSEnumerator    *enumerator = [[[adium accountController] accounts] objectEnumerator];
282         AIAccount               *account;
283         
284         while ((account = [enumerator nextObject])) {
285                 if ([account online] || [account integerStatusObjectForKey:@"Connecting"]) {
286                         AIStatus        *statusState = [account statusState];
287                         if ([statusState statusType] != AIAvailableStatusType) {
288                                 [awayAccounts addObject:account];
289                         }
290                 }
291         }
293         return awayAccounts;
297  * @brief Return from away
298  */
299 - (IBAction)returnFromAway:(id)sender
301         NSTabViewItem   *selectedTabViewItem = [tabView_configuration selectedTabViewItem];
302         AIStatus                *availableStatusState = [[adium statusController] defaultInitialStatusState];
304         [self retain];
306         if ([[selectedTabViewItem identifier] isEqualToString:@"singlestatus"]) {
307                 //Put all accounts in the Available status state
308                 [[adium statusController] applyState:availableStatusState
309                                                                   toAccounts:[self awayAccounts]];
311         } else {
312                 //Multistatus
313                 NSArray *selectedAccounts;
314                 
315                 selectedAccounts = [[tableView_multiStatus arrayOfSelectedItemsUsingSourceArray:_awayAccounts] copy];
316                 
317                 if ([selectedAccounts count]) {
318                         //Apply the available status state to only the selected accounts
319                         [[adium statusController] applyState:availableStatusState
320                                                                           toAccounts:selectedAccounts];
321                 } else {
322                         //No selection: Put all accounts in the Available status state
323                         [[adium statusController] applyState:availableStatusState
324                                                                           toAccounts:[self awayAccounts]];
325                 }
327                 [selectedAccounts release];
328         }
329         
330         [self release];
334  * @brief Perform initial setup for the multistatus table
335  */
336 - (void)setupMultistatusTable
338         AIImageTextCell *imageTextCell;
339         
340         imageTextCell = [[AIImageTextCell alloc] init];
341         [imageTextCell setDrawsGradientHighlight:YES];
342         [[tableView_multiStatus tableColumnWithIdentifier:@"status"] setDataCell:imageTextCell];
343         [imageTextCell release];        
346 #pragma mark Multiservice table view datasource
348 * @brief Number of rows in the table
349  */
350 - (int)numberOfRowsInTableView:(NSTableView *)tableView
352         return [_awayAccounts count];
356  * @brief Table values
358  * Object value is the account's formatted UID
359  */
360 - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
362         AIAccount       *account = [_awayAccounts objectAtIndex:row];
364         return [account formattedUID];
368  * @brief Will display a cell
370  * Set the image (status icon) and substring (status title) before display.  Cell is an AIImageTextCell.
371  */
372 - (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(int)row
374         AIAccount       *account = [_awayAccounts objectAtIndex:row];
376         [cell setImage:[AIStatusIcons statusIconForListObject:account
377                                                                                                          type:AIServiceIconSmall
378                                                                                                 direction:AIIconNormal]];
379         [cell setSubString:[[account statusState] title]];
382 - (void)localizeButtons
384         [button_return setLocalizedString:AILocalizedStringFromTableInBundle(@"Return", 
385                                                                                                                                                  @"Buttons",
386                                                                                                                                                  [NSBundle bundleForClass:[self class]],
387                                                                                                                                                  "Button to return from away in the away status window")];
390 - (void)statusIconSetChanged:(NSNotification *)inNotification
392         [self configureStatusWindow];
395 @end