Minor improvements to the localization updating script to hand a missing Scripts...
[adiumx.git] / Source / ESStatusPreferences.m
blob1bf71b50744697fdfaab594a9dab0f8e42335609
1 //
2 //  ESStatusPreferences.m
3 //  Adium
4 //
5 //  Created by Evan Schoenberg on 2/26/05.
6 //  Copyright 2006 The Adium Team. All rights reserved.
7 //
9 #import "ESStatusPreferences.h"
10 #import "AIStatusController.h"
11 #import <Adium/AIAccountControllerProtocol.h>
12 #import "ESEditStatusGroupWindowController.h"
13 #import <Adium/AIAccount.h>
14 #import <Adium/AIEditStateWindowController.h>
15 #import <Adium/AIStatusMenu.h>
16 #import <Adium/AIStatusGroup.h>
17 #import <AIUtilities/AIImageTextCell.h>
18 #import <AIUtilities/AIAutoScrollView.h>
19 #import <AIUtilities/AIVerticallyCenteredTextCell.h>
20 #import <AIUtilities/AIOutlineViewAdditions.h>
21 #import <AIUtilities/AIImageAdditions.h>
22 #import "KFTypeSelectTableView.h"
24 #define STATE_DRAG_TYPE @"AIState"
26 @interface ESStatusPreferences (PRIVATE)
27 - (void)configureOtherControls;
28 - (void)configureAutoAwayStatusStatePopUp;
29 - (void)saveTimeValues;
30 - (void)_selectStatusWithUniqueID:(NSNumber *)uniqueID inPopUpButton:(NSPopUpButton *)inPopUpButton;
32 - (BOOL)addItemIfNeeded:(NSMenuItem *)menuItem toPopUpButton:(NSPopUpButton *)popUpButton alreadyShowingAnItem:(BOOL)alreadyShowing;
33 @end
35 @implementation ESStatusPreferences
37 - (NSString *)paneIdentifier
39         return @"Status";
41 - (NSString *)paneName
43     return AILocalizedString(@"Status",nil);
45 - (NSImage *)paneIcon
47         return [NSImage imageNamed:@"pref-status" forClass:[self class]];
50 /*!
51  * @brief Nib name
52  */
53 - (NSString *)nibName{
54     return @"StatusPreferences";
57 /*!
58  * @brief Configure the preference view
59  */
60 - (void)viewDidLoad
62         //Configure the controls
63         [self configureStateList];
65         //Manually size and position our buttons
66         {
67                 NSRect  newFrame, oldFrame;
68                 
69                 //Edit, right justified and far enough away from Remove that it can't conceivably overlap
70                 oldFrame = [button_editState frame];
71                 [button_editState setTitle:AILocalizedStringFromTable(@"Edit", @"Buttons", "Verb 'edit' on a button")];
72                 [button_editState sizeToFit];
73                 newFrame = [button_editState frame];
74                 if (newFrame.size.width < oldFrame.size.width) newFrame.size.width = oldFrame.size.width;
75                 if (newFrame.size.height < oldFrame.size.height) newFrame.size.height = oldFrame.size.height;
76                 newFrame.origin.x = oldFrame.origin.x + oldFrame.size.width - newFrame.size.width;
77                 [button_editState setFrame:newFrame];
79                 //Add Group
80                 oldFrame = [button_addGroup frame];
81                 [button_addGroup setTitle:AILocalizedString(@"Add Group",nil)];
82                 [button_addGroup sizeToFit];
83                 newFrame = [button_addGroup frame];
84                 if (newFrame.size.height < oldFrame.size.height) newFrame.size.height = oldFrame.size.height;
85                 if (newFrame.size.width < oldFrame.size.width) newFrame.size.width = oldFrame.size.width;
86                 if (newFrame.size.width > oldFrame.size.width) newFrame.size.width += 8;
87                 [button_addGroup setFrame:newFrame];
88         }
89         
90         
91         /* Register as an observer of state array changes so we can refresh our list
92          * in response to changes. */
93         [[adium notificationCenter] addObserver:self
94                                                                    selector:@selector(stateArrayChanged:)
95                                                                            name:AIStatusStateArrayChangedNotification
96                                                                          object:nil];
97         [self stateArrayChanged:nil];
99         [self configureOtherControls];
103  * @brief Preference view is closing
104  */
105 - (void)viewWillClose
107         [self saveTimeValues];
108         [[adium notificationCenter] removeObserver:self];
112  * @brief Deallocate
113  */
114 - (void)dealloc
116         [super dealloc];
119 #pragma mark Status state list and controls
121 * @brief Configure the state list
123  * Configure the state list table view, setting up the custom table cells, padding, scroll view settings and other
124  * state list interface related setup.
125  */
126 - (void)configureStateList
128     AIImageTextCell                     *cell;
130         //Configure the table view
131         [outlineView_stateList setTarget:self];
132         [outlineView_stateList setDoubleAction:@selector(editState:)];
133         [outlineView_stateList setIntercellSpacing:NSMakeSize(4,4)];
134     [scrollView_stateList setAutohidesScrollers:YES];
135         
136         //Enable dragging of states
137         [outlineView_stateList registerForDraggedTypes:[NSArray arrayWithObject:STATE_DRAG_TYPE]];
138         
139     //Custom vertically-centered text cell for status state names
140     cell = [[AIVerticallyCenteredTextCell alloc] init];
141     [cell setFont:[NSFont systemFontOfSize:13]];
142     [[outlineView_stateList tableColumnWithIdentifier:@"name"] setDataCell:cell];
143         [cell release];
147  * @brief Update table control availability
149  * Updates table control availability based on the current state selection.  If no states are selected this method dims the
150  * edit and delete buttons since they require a selection to function.  The edit and delete buttons are also
151  * dimmed if the selected state is a built-in state.
152  */
153 - (void)updateTableControlAvailability
155 //      NSArray *selectedItems = [outlineView_stateList arrayOfSelectedItems];
156         NSIndexSet *selectedIndexes = [outlineView_stateList selectedRowIndexes];
157         int                     count = [selectedIndexes count];
159         [button_editState setEnabled:(count && 
160                                                                   ([[outlineView_stateList itemAtRow:[selectedIndexes firstIndex]] mutabilityType] == AIEditableStatusState))];
161         [button_deleteState setEnabled:count];
165  * @brief Invoked when the state array changes
167  * This method is invoked when the state array changes.  In response, we hold onto the new array and refresh our state
168  * list.
169  */
170 - (void)stateArrayChanged:(NSNotification *)notification
172         [outlineView_stateList reloadData];
173         [self updateTableControlAvailability];
174         
175         //Update the auto away status pop up as necessary
176         [self configureAutoAwayStatusStatePopUp];
179 //State Editing --------------------------------------------------------------------------------------------------------
180 #pragma mark State Editing
182 * @brief Edit the selected state
184  * Opens an edit state sheet for the selected state.  If the sheet is closed with success our
185  * customStatusState:changedTo: method will be invoked and we can save the changes
186  */
187 - (IBAction)editState:(id)sender
189         int                             selectedRow = [outlineView_stateList selectedRow];
190         AIStatusItem    *statusState = [outlineView_stateList itemAtRow:selectedRow];
191         
192         if (statusState) {
193                 if ([statusState isKindOfClass:[AIStatus class]]) {
194                         [AIEditStateWindowController editCustomState:(AIStatus *)statusState
195                                                                                                  forType:[statusState statusType]
196                                                                                           andAccount:nil
197                                                                                   withSaveOption:NO
198                                                                                                 onWindow:[[self view] window]
199                                                                                  notifyingTarget:self];
200                         
201                 } else if ([statusState isKindOfClass:[AIStatusGroup class]]) {
202                         [ESEditStatusGroupWindowController editStatusGroup:(AIStatusGroup *)statusState
203                                                                                                           onWindow:[[self view] window]
204                                                                                            notifyingTarget:self];                       
205                 }
206         }
210 * @brief State edited callback
212  * Invoked when the user successfully edits a state.  This method adds the new or updated state to Adium's state array.
213  */
214 - (void)customStatusState:(AIStatus *)originalState changedTo:(AIStatus *)newState forAccount:(AIAccount *)account
216         if (originalState) {
217                 /* As far the user was concerned, this was an edit.  The unique status ID should remain the same so that anything
218                  * depending upon this status will update to using it.  Furthermore, since this may be a copy of originalState
219                  * rather than the exact same object, we should update all accounts which are using this state to use the new copy
220                  */
221                 [newState setUniqueStatusID:[originalState uniqueStatusID]];
222                 
223                 NSEnumerator    *enumerator;
224                 AIAccount               *account;
225                 
226                 enumerator = [[[adium accountController] accounts] objectEnumerator];
227                 while ((account = [enumerator nextObject])) {
228                         if ([account statusState] == originalState) {
229                                 [account setStatusStateAndRemainOffline:newState];
230                                 
231                                 [account notifyOfChangedStatusSilently:YES];
232                         }
233                 }
235                 [[originalState containingStatusGroup] replaceExistingStatusState:originalState withStatusState:newState];
237                 [originalState setUniqueStatusID:nil];
239         } else {
240                 [[adium statusController] addStatusState:newState];
241         }
242         
243         [outlineView_stateList selectItemsInArray:[NSArray arrayWithObject:newState]];
244         [outlineView_stateList scrollRowToVisible:[outlineView_stateList rowForItem:newState]];
247 - (void)finishedStatusGroupEdit:(AIStatusGroup *)inStatusGroup
249         if (![inStatusGroup containingStatusGroup]) {
250                 //Add it if it's not already in a group
251                 [[[adium statusController] rootStateGroup] addStatusItem:inStatusGroup atIndex:-1];
253         } else {
254                 //Otherwise just save
255                 [[adium statusController] savedStatusesChanged];
256         }
258         [outlineView_stateList selectItemsInArray:[NSArray arrayWithObject:inStatusGroup]];
259         [outlineView_stateList scrollRowToVisible:[outlineView_stateList rowForItem:inStatusGroup]];
263  * @brief Delete the selected state
265  * Deletes the selected state from Adium's state array.
266  */
267 - (IBAction)deleteState:(id)sender
269         NSArray          *selectedItems = [outlineView_stateList arrayOfSelectedItems];
270         
271         if ([selectedItems count]) {
272                 //Confirm deletion of a status group with contents
273                 NSEnumerator *enumerator;
274                 AIStatusItem *statusItem;
275                 int                      numberOfItems = 0;
277                 enumerator = [selectedItems objectEnumerator];
278                 while ((statusItem = [enumerator nextObject])) {
279                         if ([statusItem isKindOfClass:[AIStatusGroup class]] &&
280                                 [[(AIStatusGroup *)statusItem flatStatusSet] count]) {
281                                 numberOfItems += [[(AIStatusGroup *)statusItem flatStatusSet] count];
282                         } else {
283                                 numberOfItems++;
284                         }
285                 }
287                 if (numberOfItems > 1) {
288                         NSString *message = [NSString stringWithFormat:AILocalizedString(@"Are you sure you want to delete %i saved status items?",nil),
289                                 numberOfItems];
290                         
291                         //Warn if deleting a group containing status items
292                         NSBeginAlertSheet(AILocalizedString(@"Status Deletion Confirmation",nil),
293                                                           AILocalizedString(@"Delete", nil),
294                                                           AILocalizedString(@"Cancel", nil), nil,
295                                                           [[self view] window], self,
296                                                           @selector(sheetDidEnd:returnCode:contextInfo:), NULL,
297                                                           [selectedItems retain],
298                                                           message);                     
299                 } else {
300                         //Use an enumerator because we could be deleting multiple empty groups
301                         enumerator = [selectedItems objectEnumerator];
302                         while ((statusItem = [enumerator nextObject])) {
303                                 [[statusItem containingStatusGroup] removeStatusItem:statusItem];
304                         }
305                 }
306         }
310  * @brief Confirmed a status item deletion operation
311  */
312 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
314         NSArray *selectedItems = (NSArray *)contextInfo;
315         if (returnCode == NSAlertDefaultReturn) {
316                 NSEnumerator *enumerator;
317                 AIStatusItem *statusItem;
319                 enumerator = [selectedItems objectEnumerator];
320                 while ((statusItem = [enumerator nextObject])) {
321                         [[statusItem containingStatusGroup] removeStatusItem:statusItem];
322                 }
323         }       
324         
325         [selectedItems release];
329 * @brief Add a new state
331  * Creates a new state.  This is done by invoking an edit window without passing it a base state.  When the edit window
332  * returns successfully, it will invoke our customStatusState:changedTo: which adds the new state to Adium's state
333  * array.
334  */
335 - (IBAction)newState:(id)sender
337         [AIEditStateWindowController editCustomState:nil
338                                                                                  forType:AIAwayStatusType
339                                                                           andAccount:nil
340                                                                   withSaveOption:NO
341                                                                                 onWindow:[[self view] window]
342                                                                  notifyingTarget:self];
345 - (IBAction)addGroup:(id)sender
347         [ESEditStatusGroupWindowController editStatusGroup:nil
348                                                                                           onWindow:[[self view] window]
349                                                                            notifyingTarget:self];
352 //State List OutlinView Delegate --------------------------------------------------------------------------------------------
353 #pragma mark State List (OutlinView Delegate)
354 - (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
356         AIStatusGroup *statusGroup = (item ? item : [[adium statusController] rootStateGroup]);
357         
358         return [[statusGroup containedStatusItems] objectAtIndex:index];
361 - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
363         AIStatusGroup *statusGroup = (item ? item : [[adium statusController] rootStateGroup]);
364         
365         return [[statusGroup containedStatusItems] count];      
368 - (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
373 - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
375         NSString                *identifier = [tableColumn identifier];
376         
377         if ([identifier isEqualToString:@"icon"]) {
378                 return ([item respondsToSelector:@selector(icon)] ? [item icon] : nil);
379                 
380         } else if ([identifier isEqualToString:@"name"]) {
381                 NSImage *icon = ([item respondsToSelector:@selector(icon)] ? [item icon] : nil);
382                 
383                 if (icon) {
384                         NSMutableAttributedString *name;
386                         NSTextAttachment                *attachment;
387                         NSTextAttachmentCell    *cell;
388                         
389                         NSSize                                  iconSize = [icon size];
390                         
391                         if ((iconSize.width > 13) || (iconSize.height > 13)) {
392                                 icon = [icon imageByScalingToSize:NSMakeSize(13, 13)];
393                         }
395                         cell = [[[NSTextAttachmentCell alloc] init] autorelease];
396                         [cell setImage:icon];
397                         
398                         attachment = [[[NSTextAttachment alloc] init] autorelease];
399                         [attachment setAttachmentCell:cell];
400                         
401                         name = [[NSAttributedString attributedStringWithAttachment:attachment] mutableCopy];
402                         [name appendAttributedString:[[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@" %@",([item title] ? [item title] : @"")]
403                                                                                                                                                   attributes:nil] autorelease]];
404                         return [name autorelease];
405                 } else {
406                         return [item title]; 
407                 }
408         }
409         
410         return nil;
413 - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
415         return [item isKindOfClass:[AIStatusGroup class]];
419 * @brief Delete the selected row
420  */
421 - (void)outlineViewDeleteSelectedRows:(NSTableView *)tableView
423     [self deleteState:nil];
427 * @brief Selection change
428  */
429 - (void)outlineViewSelectionDidChange:(NSNotification *)notification
431         [self updateTableControlAvailability];
435 * @brief Drag start
436  */
437 - (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard
439     draggingItems = [items retain];
440         
441     [pboard declareTypes:[NSArray arrayWithObject:STATE_DRAG_TYPE] owner:self];
442     [pboard setString:@"State" forType:STATE_DRAG_TYPE]; //Arbitrary state
444     return YES;
447 - (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index
449     if (index == NSOutlineViewDropOnItemIndex && ![item isKindOfClass:[AIStatusGroup class]]) {
450                 AIStatusGroup *dropItem = [item containingStatusGroup];
451                 if (dropItem == [[adium statusController] rootStateGroup])
452                         dropItem = nil;
454                 [outlineView setDropItem:dropItem
455                                   dropChildIndex:[[[item containingStatusGroup] containedStatusItems] indexOfObjectIdenticalTo:item]];
456         }
457      
458         return NSDragOperationPrivate;
462 * @brief Drag complete
463  */
464 - (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index
466     NSString    *avaliableType = [[info draggingPasteboard] availableTypeFromArray:[NSArray arrayWithObject:STATE_DRAG_TYPE]];
467     if ([avaliableType isEqualToString:STATE_DRAG_TYPE]) {              
468                 [[adium statusController] setDelayStatusMenuRebuilding:YES];
470                 if (!item) item = [[adium statusController] rootStateGroup];
472                 NSEnumerator *enumerator;
473                 AIStatusItem *statusItem;
474                 
475                 enumerator = [draggingItems objectEnumerator];
477                 while ((statusItem = [enumerator nextObject])) {
478                         if ([statusItem containingStatusGroup] == item) {
479                                 BOOL shouldIncrement = NO;
480                                 if ([[[statusItem containingStatusGroup] containedStatusItems] indexOfObject:statusItem] > index) {
481                                         shouldIncrement = YES;
482                                 }
483                                 
484                                 //Move the state and select it in the new location
485                                 [item moveStatusItem:statusItem toIndex:index];
486                                 
487                                 if (shouldIncrement) index++;
488                         } else {
489                                 //Don't let an object be moved into itself...
490                                 if (item != statusItem) {
491                                         [statusItem retain];
492                                         [[statusItem containingStatusGroup] removeStatusItem:statusItem];
493                                         [item addStatusItem:statusItem atIndex:index];
494                                         [statusItem release];
495                                         
496                                         index++;
497                                 }
498                         }
499                 }
501                 //Notify and reselect outside of the NSOutlineView callback
502                 [self performSelector:@selector(reselectDraggedItems:)
503                                    withObject:draggingItems
504                                    afterDelay:0];
506                 [draggingItems release]; draggingItems = nil;
508         return YES;
509     } else {
510         return NO;
511     }
514 - (void)reselectDraggedItems:(NSArray *)theDraggedItems
516         [[adium statusController] setDelayStatusMenuRebuilding:NO];
518         [outlineView_stateList selectItemsInArray:theDraggedItems];
519         [outlineView_stateList scrollRowToVisible:[outlineView_stateList rowForItem:[theDraggedItems objectAtIndex:0]]];
523 * @brief Set up KFTypeSelectTableView
525  * Only search the "name" column.
526  */
527 - (void)configureTypeSelectTableView:(KFTypeSelectTableView *)tableView
529     [tableView setSearchColumnIdentifiers:[NSSet setWithObject:@"name"]];
532 #pragma mark Other status-related controls
535  * @brief Configure initial values for idle, auto-away, etc., preferences.
536  */
538 - (void)configureOtherControls
540         NSDictionary    *prefDict = [[adium preferenceController] preferencesForGroup:PREF_GROUP_STATUS_PREFERENCES];
541         
542         [checkBox_idle setState:[[prefDict objectForKey:KEY_STATUS_REPORT_IDLE] boolValue]];
543         [textField_idleMinutes setDoubleValue:([[prefDict objectForKey:KEY_STATUS_REPORT_IDLE_INTERVAL] doubleValue] / 60.0)];
545         [checkBox_autoAway setState:[[prefDict objectForKey:KEY_STATUS_AUTO_AWAY] boolValue]];
546         [textField_autoAwayMinutes setDoubleValue:([[prefDict objectForKey:KEY_STATUS_AUTO_AWAY_INTERVAL] doubleValue] / 60.0)];
548         [checkBox_fastUserSwitching setState:[[prefDict objectForKey:KEY_STATUS_FUS] boolValue]];
549         [checkBox_screenSaver setState:[[prefDict objectForKey:KEY_STATUS_SS] boolValue]];
551         [checkBox_showStatusWindow setState:[[prefDict objectForKey:KEY_STATUS_SHOW_STATUS_WINDOW] boolValue]];
553         [self configureControlDimming];
557  * @brief Configure the pop up of states for autoAway.
559  * Should be called by stateArrayChanged: both for initial set up and for updating when the states change.
560  */
561 - (void)configureAutoAwayStatusStatePopUp
563         NSMenu          *statusStatesMenu;
564         NSNumber        *targetUniqueStatusIDNumber;
566         statusStatesMenu = [AIStatusMenu staticStatusStatesMenuNotifyingTarget:self selector:@selector(changedAutoAwayStatus:)];
567         [popUp_autoAwayStatusState setMenu:statusStatesMenu];
568         
569         statusStatesMenu = [AIStatusMenu staticStatusStatesMenuNotifyingTarget:self selector:@selector(changedFastUserSwitchingStatus:)];       
570         [popUp_fastUserSwitchingStatusState setMenu:[[statusStatesMenu copy] autorelease]];
571         
572         statusStatesMenu = [AIStatusMenu staticStatusStatesMenuNotifyingTarget:self selector:@selector(changedScreenSaverStatus:)];     
573         [popUp_screenSaverStatusState setMenu:[[statusStatesMenu copy] autorelease]];
575         //Now select the proper state, or deselect all items if there is no chosen state or the chosen state doesn't exist
576         targetUniqueStatusIDNumber = [[adium preferenceController] preferenceForKey:KEY_STATUS_AUTO_AWAY_STATUS_STATE_ID
577                                                                                                                                                   group:PREF_GROUP_STATUS_PREFERENCES];
578         [self _selectStatusWithUniqueID:targetUniqueStatusIDNumber inPopUpButton:popUp_autoAwayStatusState];
579         
580         targetUniqueStatusIDNumber = [[adium preferenceController] preferenceForKey:KEY_STATUS_FUS_STATUS_STATE_ID
581                                                                                                                                                   group:PREF_GROUP_STATUS_PREFERENCES];
582         [self _selectStatusWithUniqueID:targetUniqueStatusIDNumber inPopUpButton:popUp_fastUserSwitchingStatusState];   
583         
584         targetUniqueStatusIDNumber = [[adium preferenceController] preferenceForKey:KEY_STATUS_SS_STATUS_STATE_ID
585                                                                                                                                                   group:PREF_GROUP_STATUS_PREFERENCES];
586         [self _selectStatusWithUniqueID:targetUniqueStatusIDNumber inPopUpButton:popUp_screenSaverStatusState]; 
590  * @brief Add all items in inMenu to an array, returning the resulting array
592  * This method adds items deeply; that is, submenus and their contents are recursively included
594  * @param inMenu The menu to start from
595  * @param recursiveArray The array thus far; if nil an array will be created
597  * @result All the menu items in inMenu
598  */
599 - (NSMutableArray *)addItemsFromMenu:(NSMenu *)inMenu toArray:(NSMutableArray *)recursiveArray
601         NSArray                 *itemArray = [inMenu itemArray];
602         NSEnumerator    *enumerator;
603         NSMenuItem              *menuItem;
605         if (!recursiveArray) recursiveArray = [NSMutableArray array];
607         enumerator = [itemArray objectEnumerator];
608         while ((menuItem = [enumerator nextObject])) {
609                 [recursiveArray addObject:menuItem];
611                 if ([menuItem submenu]) {
612                         [self addItemsFromMenu:[menuItem submenu] toArray:recursiveArray];
613                 }
614         }
616         return recursiveArray;
620  * @brief Select a status with uniqueID in inPopUpButton
621  */
622 - (void)_selectStatusWithUniqueID:(NSNumber *)uniqueID inPopUpButton:(NSPopUpButton *)inPopUpButton
624         NSMenuItem      *menuItem = nil;
625         
626         if (uniqueID) {
627                 int                      targetUniqueStatusID= [uniqueID intValue];
628                 NSEnumerator *enumerator;
630                 enumerator = [[self addItemsFromMenu:[inPopUpButton menu] toArray:nil] objectEnumerator];
632                 while ((menuItem = [enumerator nextObject])) {
633                         AIStatusItem    *statusState;
634                         
635                         statusState = [[menuItem representedObject] objectForKey:@"AIStatus"];
637                         //Found the right status by matching its status ID to our preferred one
638                         if ([statusState preexistingUniqueStatusID] == targetUniqueStatusID) {
639                                 break;
640                         }
641                 }
642         }
644         if (menuItem) {
645                 [inPopUpButton selectItem:menuItem];
647                 //Add it if we weren't able to select it initially
648                 if (![inPopUpButton selectedItem]) {
649                         [self addItemIfNeeded:menuItem toPopUpButton:inPopUpButton alreadyShowingAnItem:NO];
650                         
651                         if (inPopUpButton == popUp_autoAwayStatusState) {
652                                 showingSubmenuItemInAutoAway = YES;
653                                 
654                         } else if (inPopUpButton == popUp_fastUserSwitchingStatusState) {
655                                 showingSubmenuItemInFastUserSwitching = YES;
656                                 
657                         } else if (inPopUpButton == popUp_screenSaverStatusState) {
658                                 showingSubmenuItemInScreenSaver = YES;
659                                 
660                         }
661                 }
662         }
666  * @brief Configure control dimming for idle, auto-away, etc., preferences.
667  */
668 - (void)configureControlDimming
670         BOOL    idleControlsEnabled, autoAwayControlsEnabled;
672         idleControlsEnabled = ([checkBox_idle state] == NSOnState);
673         [textField_idleMinutes setEnabled:idleControlsEnabled];
674         [stepper_idleMinutes setEnabled:idleControlsEnabled];
675         
676         autoAwayControlsEnabled = ([checkBox_autoAway state] == NSOnState);
677         [popUp_autoAwayStatusState setEnabled:autoAwayControlsEnabled];
678         [textField_autoAwayMinutes setEnabled:autoAwayControlsEnabled];
679         [stepper_autoAwayMinutes setEnabled:autoAwayControlsEnabled];
680         
681         [popUp_fastUserSwitchingStatusState setEnabled:([checkBox_fastUserSwitching state] == NSOnState)];
682         [popUp_screenSaverStatusState setEnabled:([checkBox_screenSaver state] == NSOnState)];
686  * @brief Change preference
688  * Sent when controls are clicked
689  */
690 - (void)changePreference:(id)sender
692         if (sender == checkBox_idle) {
693                 [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
694                                                                                          forKey:KEY_STATUS_REPORT_IDLE
695                                                                                           group:PREF_GROUP_STATUS_PREFERENCES];
696                 [self configureControlDimming];
697                 
698         } else if (sender == checkBox_autoAway) {
699                 [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
700                                                                                          forKey:KEY_STATUS_AUTO_AWAY
701                                                                                           group:PREF_GROUP_STATUS_PREFERENCES];
702                 [self configureControlDimming];
703                 
704         } else if (sender == checkBox_showStatusWindow) {
705                 [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
706                                                                                          forKey:KEY_STATUS_SHOW_STATUS_WINDOW
707                                                                                           group:PREF_GROUP_STATUS_PREFERENCES];         
708                 
709         } else if (sender == checkBox_fastUserSwitching) {
710                 [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
711                                                                                          forKey:KEY_STATUS_FUS
712                                                                                           group:PREF_GROUP_STATUS_PREFERENCES];
713                 [self configureControlDimming];
714                 
715         } else if (sender == checkBox_screenSaver) {
716                 [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
717                                                                                          forKey:KEY_STATUS_SS
718                                                                                           group:PREF_GROUP_STATUS_PREFERENCES];
719                 [self configureControlDimming];
720                 
721         }
725  * @brief If menuItem is not selectable in popUpButton, add it and select it
727  * Menu items located within submenus can't be directly selected. This method will add a spearator item and then the item itself
728  * to the bottom of popUpButton if needed.  alreadyShowing should be YES if a similarly set separate + item exists; it will be removed
729  * first.
731  * @result YES if the item was added to popUpButton.
732  */
733 - (BOOL)addItemIfNeeded:(NSMenuItem *)menuItem toPopUpButton:(NSPopUpButton *)popUpButton alreadyShowingAnItem:(BOOL)alreadyShowing
735         BOOL    nowShowing = NO;
736         NSMenu  *menu = [popUpButton menu];
738         [menuItem retain];
739         if (alreadyShowing) {
740                 int count = [menu numberOfItems];
741                 [menu removeItemAtIndex:--count];
742                 [menu removeItemAtIndex:--count];                       
743         }
744         
745         if ([popUpButton selectedItem] != menuItem) {
746                 NSMenuItem  *imitationMenuItem = [menuItem copy];
747                 
748                 [menu addItem:[NSMenuItem separatorItem]];
749                 [menu addItem:imitationMenuItem];
750                 
751                 [popUpButton selectItem:imitationMenuItem];
752                 [imitationMenuItem release];
753                 
754                 nowShowing = YES;
755         }       
756         [menuItem release];
757         
758         return nowShowing;
760 - (void)changedAutoAwayStatus:(id)sender
762         AIStatus        *statusState = [[sender representedObject] objectForKey:@"AIStatus"];
764         [[adium preferenceController] setPreference:[statusState uniqueStatusID]
765                                                                                  forKey:KEY_STATUS_AUTO_AWAY_STATUS_STATE_ID
766                                                                                   group:PREF_GROUP_STATUS_PREFERENCES];
768         showingSubmenuItemInAutoAway = [self addItemIfNeeded:sender
769                                                                                    toPopUpButton:popUp_autoAwayStatusState
770                                                                         alreadyShowingAnItem:showingSubmenuItemInAutoAway];
773 - (void)changedFastUserSwitchingStatus:(id)sender
775         AIStatus        *statusState = [[sender representedObject] objectForKey:@"AIStatus"];
777         [[adium preferenceController] setPreference:[statusState uniqueStatusID]
778                                                                                  forKey:KEY_STATUS_FUS_STATUS_STATE_ID
779                                                                                   group:PREF_GROUP_STATUS_PREFERENCES];
780         
781         showingSubmenuItemInFastUserSwitching = [self addItemIfNeeded:sender
782                                                                                                         toPopUpButton:popUp_fastUserSwitchingStatusState
783                                                                                          alreadyShowingAnItem:showingSubmenuItemInFastUserSwitching];
786 - (void)changedScreenSaverStatus:(id)sender
788         AIStatus        *statusState = [[sender representedObject] objectForKey:@"AIStatus"];
789         
790         [[adium preferenceController] setPreference:[statusState uniqueStatusID]
791                                                                                  forKey:KEY_STATUS_SS_STATUS_STATE_ID
792                                                                                   group:PREF_GROUP_STATUS_PREFERENCES];
793         
794         showingSubmenuItemInScreenSaver = [self addItemIfNeeded:sender
795                                                                                                         toPopUpButton:popUp_screenSaverStatusState
796                                                                                          alreadyShowingAnItem:showingSubmenuItemInScreenSaver];
800  * @brief Control text did end editing
802  * In an attempt to get closer to a live-apply of preferences, save the preference when the
803  * text field loses focus.  See saveTimeValues for more information.
804  */
805 - (void)controlTextDidEndEditing:(NSNotification *)notification
807         [self saveTimeValues];
811  * @brief Save time text field values
813  * We can't get notified when the associated NSStepper is clicked, so we just save as requested.
814  * This method should be called before the view closes.
815  */
816 - (void)saveTimeValues
818         [[adium preferenceController] setPreference:[NSNumber numberWithDouble:([textField_idleMinutes doubleValue]*60.0)]
819                                                                                  forKey:KEY_STATUS_REPORT_IDLE_INTERVAL
820                                                                                   group:PREF_GROUP_STATUS_PREFERENCES];
822         [[adium preferenceController] setPreference:[NSNumber numberWithDouble:([textField_autoAwayMinutes doubleValue]*60.0)]
823                                                                                  forKey:KEY_STATUS_AUTO_AWAY_INTERVAL
824                                                                                   group:PREF_GROUP_STATUS_PREFERENCES];
827 @end