2 // ESStatusPreferences.m
5 // Created by Evan Schoenberg on 2/26/05.
6 // Copyright 2006 The Adium Team. All rights reserved.
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;
35 @implementation ESStatusPreferences
37 - (NSString *)paneIdentifier
41 - (NSString *)paneName
43 return AILocalizedString(@"Status",nil);
47 return [NSImage imageNamed:@"pref-status" forClass:[self class]];
53 - (NSString *)nibName{
54 return @"StatusPreferences";
58 * @brief Configure the preference view
62 //Configure the controls
63 [self configureStateList];
65 //Manually size and position our buttons
67 NSRect newFrame, oldFrame;
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];
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];
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
97 [self stateArrayChanged:nil];
99 [self configureOtherControls];
103 * @brief Preference view is closing
105 - (void)viewWillClose
107 [self saveTimeValues];
108 [[adium notificationCenter] removeObserver:self];
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.
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];
136 //Enable dragging of states
137 [outlineView_stateList registerForDraggedTypes:[NSArray arrayWithObject:STATE_DRAG_TYPE]];
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];
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.
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
170 - (void)stateArrayChanged:(NSNotification *)notification
172 [outlineView_stateList reloadData];
173 [self updateTableControlAvailability];
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
187 - (IBAction)editState:(id)sender
189 int selectedRow = [outlineView_stateList selectedRow];
190 AIStatusItem *statusState = [outlineView_stateList itemAtRow:selectedRow];
193 if ([statusState isKindOfClass:[AIStatus class]]) {
194 [AIEditStateWindowController editCustomState:(AIStatus *)statusState
195 forType:[statusState statusType]
198 onWindow:[[self view] window]
199 notifyingTarget:self];
201 } else if ([statusState isKindOfClass:[AIStatusGroup class]]) {
202 [ESEditStatusGroupWindowController editStatusGroup:(AIStatusGroup *)statusState
203 onWindow:[[self view] window]
204 notifyingTarget:self];
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.
214 - (void)customStatusState:(AIStatus *)originalState changedTo:(AIStatus *)newState forAccount:(AIAccount *)account
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
221 [newState setUniqueStatusID:[originalState uniqueStatusID]];
223 NSEnumerator *enumerator;
226 enumerator = [[[adium accountController] accounts] objectEnumerator];
227 while ((account = [enumerator nextObject])) {
228 if ([account statusState] == originalState) {
229 [account setStatusStateAndRemainOffline:newState];
231 [account notifyOfChangedStatusSilently:YES];
235 [[originalState containingStatusGroup] replaceExistingStatusState:originalState withStatusState:newState];
237 [originalState setUniqueStatusID:nil];
240 [[adium statusController] addStatusState:newState];
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];
254 //Otherwise just save
255 [[adium statusController] savedStatusesChanged];
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.
267 - (IBAction)deleteState:(id)sender
269 NSArray *selectedItems = [outlineView_stateList arrayOfSelectedItems];
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];
287 if (numberOfItems > 1) {
288 NSString *message = [NSString stringWithFormat:AILocalizedString(@"Are you sure you want to delete %i saved status items?",nil),
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],
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];
310 * @brief Confirmed a status item deletion operation
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];
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
335 - (IBAction)newState:(id)sender
337 [AIEditStateWindowController editCustomState:nil
338 forType:AIAwayStatusType
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]);
358 return [[statusGroup containedStatusItems] objectAtIndex:index];
361 - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
363 AIStatusGroup *statusGroup = (item ? item : [[adium statusController] rootStateGroup]);
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];
377 if ([identifier isEqualToString:@"icon"]) {
378 return ([item respondsToSelector:@selector(icon)] ? [item icon] : nil);
380 } else if ([identifier isEqualToString:@"name"]) {
381 NSImage *icon = ([item respondsToSelector:@selector(icon)] ? [item icon] : nil);
384 NSMutableAttributedString *name;
386 NSTextAttachment *attachment;
387 NSTextAttachmentCell *cell;
389 NSSize iconSize = [icon size];
391 if ((iconSize.width > 13) || (iconSize.height > 13)) {
392 icon = [icon imageByScalingToSize:NSMakeSize(13, 13)];
395 cell = [[[NSTextAttachmentCell alloc] init] autorelease];
396 [cell setImage:icon];
398 attachment = [[[NSTextAttachment alloc] init] autorelease];
399 [attachment setAttachmentCell:cell];
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];
413 - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
415 return [item isKindOfClass:[AIStatusGroup class]];
419 * @brief Delete the selected row
421 - (void)outlineViewDeleteSelectedRows:(NSTableView *)tableView
423 [self deleteState:nil];
427 * @brief Selection change
429 - (void)outlineViewSelectionDidChange:(NSNotification *)notification
431 [self updateTableControlAvailability];
437 - (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard
439 draggingItems = [items retain];
441 [pboard declareTypes:[NSArray arrayWithObject:STATE_DRAG_TYPE] owner:self];
442 [pboard setString:@"State" forType:STATE_DRAG_TYPE]; //Arbitrary state
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])
454 [outlineView setDropItem:dropItem
455 dropChildIndex:[[[item containingStatusGroup] containedStatusItems] indexOfObjectIdenticalTo:item]];
458 return NSDragOperationPrivate;
462 * @brief Drag complete
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;
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;
484 //Move the state and select it in the new location
485 [item moveStatusItem:statusItem toIndex:index];
487 if (shouldIncrement) index++;
489 //Don't let an object be moved into itself...
490 if (item != statusItem) {
492 [[statusItem containingStatusGroup] removeStatusItem:statusItem];
493 [item addStatusItem:statusItem atIndex:index];
494 [statusItem release];
501 //Notify and reselect outside of the NSOutlineView callback
502 [self performSelector:@selector(reselectDraggedItems:)
503 withObject:draggingItems
506 [draggingItems release]; draggingItems = nil;
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.
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.
538 - (void)configureOtherControls
540 NSDictionary *prefDict = [[adium preferenceController] preferencesForGroup:PREF_GROUP_STATUS_PREFERENCES];
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]];
550 [checkBox_showStatusWindow setState:[[prefDict objectForKey:KEY_STATUS_SHOW_STATUS_WINDOW] boolValue]];
552 [self configureControlDimming];
556 * @brief Configure the pop up of states for autoAway.
558 * Should be called by stateArrayChanged: both for initial set up and for updating when the states change.
560 - (void)configureAutoAwayStatusStatePopUp
562 NSMenu *statusStatesMenu;
563 NSNumber *targetUniqueStatusIDNumber;
565 statusStatesMenu = [AIStatusMenu staticStatusStatesMenuNotifyingTarget:self selector:@selector(changedAutoAwayStatus:)];
566 [popUp_autoAwayStatusState setMenu:statusStatesMenu];
568 statusStatesMenu = [AIStatusMenu staticStatusStatesMenuNotifyingTarget:self selector:@selector(changedFastUserSwitchingStatus:)];
569 [popUp_fastUserSwitchingStatusState setMenu:[[statusStatesMenu copy] autorelease]];
571 //Now select the proper state, or deselect all items if there is no chosen state or the chosen state doesn't exist
572 targetUniqueStatusIDNumber = [[adium preferenceController] preferenceForKey:KEY_STATUS_AUTO_AWAY_STATUS_STATE_ID
573 group:PREF_GROUP_STATUS_PREFERENCES];
574 [self _selectStatusWithUniqueID:targetUniqueStatusIDNumber inPopUpButton:popUp_autoAwayStatusState];
576 targetUniqueStatusIDNumber = [[adium preferenceController] preferenceForKey:KEY_STATUS_FUS_STATUS_STATE_ID
577 group:PREF_GROUP_STATUS_PREFERENCES];
578 [self _selectStatusWithUniqueID:targetUniqueStatusIDNumber inPopUpButton:popUp_fastUserSwitchingStatusState];
582 * @brief Add all items in inMenu to an array, returning the resulting array
584 * This method adds items deeply; that is, submenus and their contents are recursively included
586 * @param inMenu The menu to start from
587 * @param recursiveArray The array thus far; if nil an array will be created
589 * @result All the menu items in inMenu
591 - (NSMutableArray *)addItemsFromMenu:(NSMenu *)inMenu toArray:(NSMutableArray *)recursiveArray
593 NSArray *itemArray = [inMenu itemArray];
594 NSEnumerator *enumerator;
595 NSMenuItem *menuItem;
597 if (!recursiveArray) recursiveArray = [NSMutableArray array];
599 enumerator = [itemArray objectEnumerator];
600 while ((menuItem = [enumerator nextObject])) {
601 [recursiveArray addObject:menuItem];
603 if ([menuItem submenu]) {
604 [self addItemsFromMenu:[menuItem submenu] toArray:recursiveArray];
608 return recursiveArray;
612 * @brief Select a status with uniqueID in inPopUpButton
614 - (void)_selectStatusWithUniqueID:(NSNumber *)uniqueID inPopUpButton:(NSPopUpButton *)inPopUpButton
616 NSMenuItem *menuItem = nil;
619 int targetUniqueStatusID= [uniqueID intValue];
620 NSEnumerator *enumerator;
622 enumerator = [[self addItemsFromMenu:[inPopUpButton menu] toArray:nil] objectEnumerator];
624 while ((menuItem = [enumerator nextObject])) {
625 AIStatusItem *statusState;
627 statusState = [[menuItem representedObject] objectForKey:@"AIStatus"];
629 //Found the right status by matching its status ID to our preferred one
630 if ([statusState preexistingUniqueStatusID] == targetUniqueStatusID) {
637 [inPopUpButton selectItem:menuItem];
639 //Add it if we weren't able to select it initially
640 if (![inPopUpButton selectedItem]) {
641 [self addItemIfNeeded:menuItem toPopUpButton:inPopUpButton alreadyShowingAnItem:NO];
643 if (inPopUpButton == popUp_autoAwayStatusState) {
644 showingSubmenuItemInAutoAway = YES;
646 } else if (inPopUpButton == popUp_fastUserSwitchingStatusState) {
647 showingSubmenuItemInFastUserSwitching = YES;
655 * @brief Configure control dimming for idle, auto-away, etc., preferences.
657 - (void)configureControlDimming
659 BOOL idleControlsEnabled, autoAwayControlsEnabled;
661 idleControlsEnabled = ([checkBox_idle state] == NSOnState);
662 [textField_idleMinutes setEnabled:idleControlsEnabled];
663 [stepper_idleMinutes setEnabled:idleControlsEnabled];
665 autoAwayControlsEnabled = ([checkBox_autoAway state] == NSOnState);
666 [popUp_autoAwayStatusState setEnabled:autoAwayControlsEnabled];
667 [textField_autoAwayMinutes setEnabled:autoAwayControlsEnabled];
668 [stepper_autoAwayMinutes setEnabled:autoAwayControlsEnabled];
670 [popUp_fastUserSwitchingStatusState setEnabled:([checkBox_fastUserSwitching state] == NSOnState)];
674 * @brief Change preference
676 * Sent when controls are clicked
678 - (void)changePreference:(id)sender
680 if (sender == checkBox_idle) {
681 [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
682 forKey:KEY_STATUS_REPORT_IDLE
683 group:PREF_GROUP_STATUS_PREFERENCES];
684 [self configureControlDimming];
686 } else if (sender == checkBox_autoAway) {
687 [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
688 forKey:KEY_STATUS_AUTO_AWAY
689 group:PREF_GROUP_STATUS_PREFERENCES];
690 [self configureControlDimming];
692 } else if (sender == checkBox_showStatusWindow) {
693 [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
694 forKey:KEY_STATUS_SHOW_STATUS_WINDOW
695 group:PREF_GROUP_STATUS_PREFERENCES];
697 } else if (sender == checkBox_fastUserSwitching) {
698 [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
699 forKey:KEY_STATUS_FUS
700 group:PREF_GROUP_STATUS_PREFERENCES];
701 [self configureControlDimming];
707 * @brief If menuItem is not selectable in popUpButton, add it and select it
709 * Menu items located within submenus can't be directly selected. This method will add a spearator item and then the item itself
710 * to the bottom of popUpButton if needed. alreadyShowing should be YES if a similarly set separate + item exists; it will be removed
713 * @result YES if the item was added to popUpButton.
715 - (BOOL)addItemIfNeeded:(NSMenuItem *)menuItem toPopUpButton:(NSPopUpButton *)popUpButton alreadyShowingAnItem:(BOOL)alreadyShowing
717 BOOL nowShowing = NO;
718 NSMenu *menu = [popUpButton menu];
721 if (alreadyShowing) {
722 int count = [menu numberOfItems];
723 [menu removeItemAtIndex:--count];
724 [menu removeItemAtIndex:--count];
727 if ([popUpButton selectedItem] != menuItem) {
728 NSMenuItem *imitationMenuItem = [menuItem copy];
730 [menu addItem:[NSMenuItem separatorItem]];
731 [menu addItem:imitationMenuItem];
733 [popUpButton selectItem:imitationMenuItem];
734 [imitationMenuItem release];
742 - (void)changedAutoAwayStatus:(id)sender
744 AIStatus *statusState = [[sender representedObject] objectForKey:@"AIStatus"];
746 [[adium preferenceController] setPreference:[statusState uniqueStatusID]
747 forKey:KEY_STATUS_AUTO_AWAY_STATUS_STATE_ID
748 group:PREF_GROUP_STATUS_PREFERENCES];
750 showingSubmenuItemInAutoAway = [self addItemIfNeeded:sender
751 toPopUpButton:popUp_autoAwayStatusState
752 alreadyShowingAnItem:showingSubmenuItemInAutoAway];
755 - (void)changedFastUserSwitchingStatus:(id)sender
757 AIStatus *statusState = [[sender representedObject] objectForKey:@"AIStatus"];
759 [[adium preferenceController] setPreference:[statusState uniqueStatusID]
760 forKey:KEY_STATUS_FUS_STATUS_STATE_ID
761 group:PREF_GROUP_STATUS_PREFERENCES];
763 showingSubmenuItemInFastUserSwitching = [self addItemIfNeeded:sender
764 toPopUpButton:popUp_fastUserSwitchingStatusState
765 alreadyShowingAnItem:showingSubmenuItemInFastUserSwitching];
769 * @brief Control text did end editing
771 * In an attempt to get closer to a live-apply of preferences, save the preference when the
772 * text field loses focus. See saveTimeValues for more information.
774 - (void)controlTextDidEndEditing:(NSNotification *)notification
776 [self saveTimeValues];
780 * @brief Save time text field values
782 * We can't get notified when the associated NSStepper is clicked, so we just save as requested.
783 * This method should be called before the view closes.
785 - (void)saveTimeValues
787 [[adium preferenceController] setPreference:[NSNumber numberWithDouble:([textField_idleMinutes doubleValue]*60.0)]
788 forKey:KEY_STATUS_REPORT_IDLE_INTERVAL
789 group:PREF_GROUP_STATUS_PREFERENCES];
791 [[adium preferenceController] setPreference:[NSNumber numberWithDouble:([textField_autoAwayMinutes doubleValue]*60.0)]
792 forKey:KEY_STATUS_AUTO_AWAY_INTERVAL
793 group:PREF_GROUP_STATUS_PREFERENCES];