2 * Adium is the legal property of its developers, whose names are listed in the copyright file included
3 * with this source distribution.
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.
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.
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.
17 #import "AISoundController.h"
18 #import "Adium/ESContactAlertsViewController.h"
19 #import <Adium/AIContactAlertsControllerProtocol.h>
20 #import "ESGlobalEventsPreferences.h"
21 #import "ESGlobalEventsPreferencesPlugin.h"
22 #import <Adium/ESPresetManagementController.h>
23 #import <Adium/ESPresetNameSheetController.h>
24 #import <Adium/AISoundSet.h>
25 #import <AIUtilities/AIMenuAdditions.h>
26 #import <AIUtilities/AIPopUpButtonAdditions.h>
27 #import <AIUtilities/AIStringAdditions.h>
28 #import <AIUtilities/AIApplicationAdditions.h>
29 #import <AIUtilities/AIVariableHeightOutlineView.h>
30 #import <AIUtilities/AIVerticallyCenteredTextCell.h>
31 #import <AIUtilities/AIAttributedStringAdditions.h>
32 #import <AIUtilities/AIArrayAdditions.h>
33 #import <AIUtilities/AIImageAdditions.h>
34 #import <AIUtilities/AIImageTextCell.h>
36 #define PREF_GROUP_EVENT_PRESETS @"Event Presets"
37 #define CUSTOM_TITLE AILocalizedString(@"Custom",nil)
38 #define COPY_IN_PARENTHESIS AILocalizedString(@"(Copy)","Copy, in parenthesis, as a noun indicating that the preceding item is a duplicate")
40 #define VOLUME_SOUND_PATH [NSString pathWithComponents:[NSArray arrayWithObjects: \
41 @"/", @"System", @"Library", @"LoginPlugins", \
42 [@"BezelServices" stringByAppendingPathExtension:@"loginPlugin"], \
43 @"Contents", @"Resources", \
44 [@"volume" stringByAppendingPathExtension:@"aiff"], \
47 @interface ESGlobalEventsPreferences (PRIVATE)
48 - (void)popUp:(NSPopUpButton *)inPopUp shouldShowCustom:(BOOL)showCustom;
49 - (void)xtrasChanged:(NSNotification *)notification;
50 - (void)contactAlertsDidChangeForActionID:(NSString *)actionID;
53 - (NSMenu *)eventPresetsMenu;
55 - (IBAction)selectSoundSet:(id)sender;
56 - (NSMenu *)_soundSetMenu;
58 - (void)editEventsWithEventID:(NSString *)eventID;
60 - (NSString *)_localizedTitle:(NSString *)englishTitle;
62 - (void)saveCurrentEventPreset;
64 - (void)setAndConfigureEventPresetsMenu;
65 - (void)updateSoundSetSelection;
66 - (void)updateSoundSetSelectionForSoundSet:(AISoundSet *)soundSet;
69 @implementation ESGlobalEventsPreferences
70 - (NSString *)paneIdentifier
74 - (NSString *)paneName{
75 return AILocalizedString(@"Events", "Name of preferences and tab for specifying what Adium should do when events occur - for example, display a Growl alert when John signs on.");
80 - (NSString *)nibName{
81 return @"GlobalEventsPreferences";
85 return [NSImage imageNamed:@"pref-events" forClass:[self class]];
88 - (BOOL)resizableHorizontally
94 * @brief Configure the preference view
98 //Configure our global contact alerts view controller
99 [contactAlertsViewController setConfigureForGlobal:YES];
100 [contactAlertsViewController setDelegate:self];
101 [contactAlertsViewController setShowEventsInEditSheet:NO];
103 //Observe for installation of new sound sets and set up the sound set menu
104 [[adium notificationCenter] addObserver:self
105 selector:@selector(xtrasChanged:)
106 name:AIXtrasDidChangeNotification
109 //This will build the sound set menu
110 [self xtrasChanged:nil];
113 [self setAndConfigureEventPresetsMenu];
115 //And event presets to update our presets menu
116 [[adium preferenceController] registerPreferenceObserver:self forGroup:PREF_GROUP_EVENT_PRESETS];
118 //Ensure the correct sound set is selected
119 [self updateSoundSetSelection];
122 [slider_volume setFloatValue:[[[adium preferenceController] preferenceForKey:KEY_SOUND_CUSTOM_VOLUME_LEVEL
123 group:PREF_GROUP_SOUNDS] floatValue]];
128 [[button_minvolume cell] accessibilitySetOverrideValue:AILocalizedString(@"Set minimum volume", nil)
129 forAttribute:NSAccessibilityDescriptionAttribute];
130 [[button_maxvolume cell] accessibilitySetOverrideValue:AILocalizedString(@"Set maximum volume", nil)
131 forAttribute:NSAccessibilityDescriptionAttribute];
132 [[slider_volume cell] accessibilitySetOverrideValue:AILocalizedString(@"Volume", nil)
133 forAttribute:NSAccessibilityDescriptionAttribute];
135 [label_eventPreset setLocalizedString:AILocalizedString(@"Event preset:",nil)];
136 [label_soundSet setLocalizedString:AILocalizedString(@"Sound set:",nil)];
140 * @brief Preference view is closing
142 - (void)viewWillClose
144 [contactAlertsViewController viewWillClose];
145 [contactAlertsViewController release]; contactAlertsViewController = nil;
147 [[adium preferenceController] unregisterPreferenceObserver:self];
148 [[adium notificationCenter] removeObserver:self];
152 * @brief PREF_GROUP_CONTACT_ALERTS changed; update our summary data
154 - (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key
155 object:(AIListObject *)object preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
157 if ([group isEqualToString:PREF_GROUP_EVENT_PRESETS]) {
158 if (!key || [key isEqualToString:@"Event Presets"]) {
159 //Update when the available event presets change
160 [self setAndConfigureEventPresetsMenu];
166 * @brief Set if a popup should have a "Custom" menu item
168 - (void)popUp:(NSPopUpButton *)inPopUp shouldShowCustom:(BOOL)showCustom
170 NSMenuItem *lastItem = [inPopUp lastItem];
171 BOOL customIsShowing = (lastItem && (![lastItem representedObject] &&
172 [[lastItem title] isEqualToString:CUSTOM_TITLE]));
173 if (showCustom && !customIsShowing) {
174 //Add 'custom' then select it
175 [[inPopUp menu] addItem:[NSMenuItem separatorItem]];
176 [[inPopUp menu] addItemWithTitle:CUSTOM_TITLE
180 [inPopUp selectItem:[inPopUp lastItem]];
182 } else if (!showCustom && customIsShowing) {
183 //If it currently has a 'custom' item listed, remove it and the separator above it
184 [inPopUp removeItemAtIndex:([inPopUp numberOfItems]-1)];
185 [inPopUp removeItemAtIndex:([inPopUp numberOfItems]-1)];
190 * @brief Update our soundset menu if a new sound set is instaled
192 - (void)xtrasChanged:(NSNotification *)notification
194 if (!notification || [[notification object] caseInsensitiveCompare:@"AdiumSoundset"] == NSOrderedSame) {
195 //Build the soundset menu
196 [popUp_soundSet setMenu:[self _soundSetMenu]];
200 #pragma mark Event presets
203 * @brief Buld and return the event presets menu
205 * The menu will have built in presets, a divider, user-set presets, a divider, and then the preset management item(s)
207 - (NSMenu *)eventPresetsMenu
209 NSMenu *eventPresetsMenu = [[NSMenu allocWithZone:[NSMenu zone]] init];
210 NSEnumerator *enumerator;
211 NSDictionary *eventPreset;
212 NSMenuItem *menuItem;
214 //Built in event presets
215 enumerator = [[plugin builtInEventPresetsArray] objectEnumerator];
216 while ((eventPreset = [enumerator nextObject])) {
217 NSString *name = [eventPreset objectForKey:@"Name"];
219 //Add a menu item for the set
220 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[self _localizedTitle:name]
222 action:@selector(selectEventPreset:)
223 keyEquivalent:@""] autorelease];
224 [menuItem setRepresentedObject:eventPreset];
225 [eventPresetsMenu addItem:menuItem];
228 NSArray *storedEventPresetsArray = [plugin storedEventPresetsArray];
230 if ([storedEventPresetsArray count]) {
231 [eventPresetsMenu addItem:[NSMenuItem separatorItem]];
233 enumerator = [storedEventPresetsArray objectEnumerator];
234 while ((eventPreset = [enumerator nextObject])) {
235 NSString *name = [eventPreset objectForKey:@"Name"];
237 //Add a menu item for the set
238 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:name
240 action:@selector(selectEventPreset:)
241 keyEquivalent:@""] autorelease];
242 [menuItem setRepresentedObject:eventPreset];
243 [eventPresetsMenu addItem:menuItem];
248 [eventPresetsMenu addItem:[NSMenuItem separatorItem]];
250 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[AILocalizedString(@"Add New Preset",nil) stringByAppendingEllipsis]
252 action:@selector(addNewPreset:)
253 keyEquivalent:@""] autorelease];
254 [eventPresetsMenu addItem:menuItem];
256 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[AILocalizedString(@"Edit Presets",nil) stringByAppendingEllipsis]
258 action:@selector(editPresets:)
259 keyEquivalent:@""] autorelease];
260 [eventPresetsMenu addItem:menuItem];
262 return [eventPresetsMenu autorelease];
265 - (void)selectActiveEventInPopUp
267 NSString *activeEventSetName = [[adium preferenceController] preferenceForKey:KEY_ACTIVE_EVENT_SET
268 group:PREF_GROUP_EVENT_PRESETS];
270 //First try to set the localized version
271 [popUp_eventPreset selectItemWithTitle:[self _localizedTitle:activeEventSetName]];
272 //If that fails, look for one exactly matching
273 if (![popUp_eventPreset selectedItem]) [popUp_eventPreset selectItemWithTitle:activeEventSetName];
274 //And if that fails, select the first item (something went wrong, we should at least have a selection)
275 if (![popUp_eventPreset selectedItem]) [popUp_eventPreset selectItemAtIndex:0];
278 - (void)setAndConfigureEventPresetsMenu
280 [popUp_eventPreset setMenu:[self eventPresetsMenu]];
281 [self selectActiveEventInPopUp];
285 * @brief Selected an event preset
287 * Pass it to the plugin, which will perform necessary changes to our contact alerts
289 - (void)selectEventPreset:(id)sender
291 NSDictionary *eventPreset = [sender representedObject];
292 [plugin setEventPreset:eventPreset];
294 [self updateSoundSetSelection];
300 * Called by the "Add New preset..." menu item. Functions the same as duplicate from the preset management, duplicating
301 * the current event set with a new name.
303 - (void)addNewPreset:(id)sender
305 NSString *defaultName;
306 NSString *explanatoryText;
308 defaultName = [NSString stringWithFormat:@"%@ %@",
309 [self _localizedTitle:[[adium preferenceController] preferenceForKey:KEY_ACTIVE_EVENT_SET
310 group:PREF_GROUP_EVENT_PRESETS]],
311 COPY_IN_PARENTHESIS];
312 explanatoryText = AILocalizedString(@"Enter a unique name for this new event set.",nil);
314 [ESPresetNameSheetController showPresetNameSheetWithDefaultName:defaultName
315 explanatoryText:explanatoryText
316 onWindow:[[self view] window]
320 //Get our event presets menu back to its proper selection
321 [self selectActiveEventInPopUp];
325 * @brief Manage presets
327 * Called by the "Edit Presets..." menu item
329 - (void)editPresets:(id)sender
331 [ESPresetManagementController managePresets:[plugin storedEventPresetsArray]
333 onWindow:[[self view] window]
336 //Get our event presets menu back to its proper selection
337 [self selectActiveEventInPopUp];
340 - (BOOL)allowDeleteOfPreset:(NSDictionary *)preset
342 NSString *name = [preset objectForKey:@"Name"];
343 NSString *localizedTitle;
345 localizedTitle = [self _localizedTitle:[[adium preferenceController] preferenceForKey:KEY_ACTIVE_EVENT_SET
346 group:PREF_GROUP_EVENT_PRESETS]];
347 //Don't allow the active preset to be deleted
348 return (![localizedTitle isEqualToString:name]);
351 - (NSArray *)renamePreset:(NSDictionary *)preset toName:(NSString *)newName inPresets:(NSArray *)presets renamedPreset:(id *)renamedPreset
353 NSString *oldPresetName = [preset objectForKey:@"Name"];
354 NSMutableDictionary *newPreset = [preset mutableCopy];
355 NSString *localizedCurrentName = [self _localizedTitle:[[adium preferenceController] preferenceForKey:KEY_ACTIVE_EVENT_SET
356 group:PREF_GROUP_EVENT_PRESETS]];
357 [newPreset setObject:newName
360 //Mark the newly created (but still functionally identical) event set as active if the old one was active
361 if ([localizedCurrentName isEqualToString:oldPresetName]) {
362 [[adium preferenceController] setPreference:newName
363 forKey:KEY_ACTIVE_EVENT_SET
364 group:PREF_GROUP_EVENT_PRESETS];
367 //Remove the original one from the array, and add the newly-renamed one
368 [plugin deleteEventPreset:preset];
369 [plugin saveEventPreset:newPreset];
371 if (renamedPreset) *renamedPreset = newPreset;
373 //Return an updated presets array
374 return [plugin storedEventPresetsArray];
377 - (NSArray *)duplicatePreset:(NSDictionary *)preset inPresets:(NSArray *)presets createdDuplicate:(id *)duplicatePreset
379 NSMutableDictionary *newEventPreset = [preset mutableCopy];
380 NSString *newName = [NSString stringWithFormat:@"%@ %@", [preset objectForKey:@"Name"], COPY_IN_PARENTHESIS];
381 [newEventPreset setObject:newName
384 //Remove the original preset's order index
385 [newEventPreset removeObjectForKey:@"OrderIndex"];
387 //Now save the new preset
388 [plugin saveEventPreset:newEventPreset];
390 //Return the created duplicate by reference
391 if (duplicatePreset != NULL) *duplicatePreset = [[newEventPreset retain] autorelease];
394 [newEventPreset release];
396 //Return an updated presets array
397 return [plugin storedEventPresetsArray];
400 - (NSArray *)deletePreset:(NSDictionary *)preset inPresets:(NSArray *)presets
403 [plugin deleteEventPreset:preset];
405 //Return an updated presets array
406 return [plugin storedEventPresetsArray];
409 - (NSArray *)movePreset:(NSDictionary *)preset toIndex:(int)index inPresets:(NSArray *)presets presetAfterMove:(id *)presetAfterMove
411 NSMutableDictionary *newEventPreset = [preset mutableCopy];
414 newOrderIndex = [[[presets objectAtIndex:0] objectForKey:@"OrderIndex"] floatValue] / 2.0;
416 } else if (index < [presets count]) {
417 float above = [[[presets objectAtIndex:index-1] objectForKey:@"OrderIndex"] floatValue];
418 float below = [[[presets objectAtIndex:index] objectForKey:@"OrderIndex"] floatValue];
419 newOrderIndex = ((above + below) / 2.0);
422 newOrderIndex = [plugin nextOrderIndex];
425 [newEventPreset setObject:[NSNumber numberWithFloat:newOrderIndex]
426 forKey:@"OrderIndex"];
428 //Now save the new preset
429 [plugin saveEventPreset:newEventPreset];
430 if (presetAfterMove != NULL) *presetAfterMove = [[newEventPreset retain] autorelease];
431 [newEventPreset release];
433 //Return an updated presets array
434 return [plugin storedEventPresetsArray];
437 #pragma mark Contact alerts changed by user
438 - (void)contactAlertsViewController:(ESContactAlertsViewController *)inController
439 updatedAlert:(NSDictionary *)newAlert
440 oldAlert:(NSDictionary *)oldAlert
442 [self contactAlertsDidChangeForActionID:[newAlert objectForKey:KEY_ACTION_ID]];
445 - (void)contactAlertsViewController:(ESContactAlertsViewController *)inController
446 deletedAlert:(NSDictionary *)deletedAlert
448 [self contactAlertsDidChangeForActionID:[deletedAlert objectForKey:KEY_ACTION_ID]];
452 * @brief Contact alerts were changed by the user
454 - (void)contactAlertsDidChangeForActionID:(NSString *)actionID
457 [actionID isEqualToString:SOUND_ALERT_IDENTIFIER]) {
459 NSArray *alertsArray = [[adium contactAlertsController] alertsForListObject:nil
461 actionID:SOUND_ALERT_IDENTIFIER];
462 NSMenuItem *soundMenuItem;
464 if (![alertsArray count]) {
465 //We can select "None" if there are no sounds
466 soundMenuItem = (NSMenuItem *)[popUp_soundSet itemWithTitle:@"None"];
469 /* Otherwise, check to see if we remain in our proper soundset.
470 * Note that this won't detect if we return to a soundset, but that'd be an expensive search.
472 soundMenuItem = (NSMenuItem *)[popUp_soundSet selectedItem];
474 AISoundSet *soundSet = [soundMenuItem representedObject];
475 NSEnumerator *enumerator;
477 NSDictionary *sounds = [soundSet sounds];
479 if ([alertsArray count] && ![sounds count]) {
480 //If we have one or more sound alerts and there are no sounds in this sound set ("None" sound set), there's no matching soundSetMenuitem.
484 //First, check to see if any sounds which are present within this sound set have been changed
485 enumerator = [sounds keyEnumerator];
486 while ((key = [enumerator nextObject])) {
487 NSDictionary *soundAlert = [ESGlobalEventsPreferencesPlugin soundAlertForKey:key
488 inSoundsDict:sounds];
489 if (![alertsArray containsObject:soundAlert]) {
495 //Next, see if any sounds not present within this sound set have been added
497 NSDictionary *alertDict;
498 enumerator = [alertsArray objectEnumerator];
499 while ((alertDict = [enumerator nextObject])) {
500 if ([[alertDict objectForKey:KEY_ACTION_ID] isEqualToString:SOUND_ALERT_IDENTIFIER]) {
501 NSString *englishEvent = [[[AIObject sharedAdiumInstance] contactAlertsController] eventIDForEnglishDisplayName:key];
503 * If the sounds dictionary has no action for this event, or it has one but
504 * it is for a different sound than specified, the sound set has been changed
506 if (![sounds objectForKey:englishEvent] ||
507 ![[[alertDict objectForKey:KEY_ACTION_DETAILS] objectForKey:KEY_ALERT_SOUND_PATH] isEqualToString:[sounds objectForKey:englishEvent]]) {
518 [self selectSoundSet:([soundMenuItem representedObject] ? soundMenuItem : nil)];
521 [self saveCurrentEventPreset];
525 #pragma mark Sound sets
527 * @brief Called when an item in the sound set popUp is selected.
529 * Also called after the user changes sounds manually, by -[ESGlobalEventsPreferences contactAlertsDidChangeForActionID].
531 - (IBAction)selectSoundSet:(id)sender
533 //Apply the sound set so its events are in the current alerts.
535 [plugin applySoundSet:[sender representedObject]];
538 /* Update the selection, which will select Custom as appropriate. This must be done before saving the event
539 * preset so the menu is on the correct sound set to save.
541 [self updateSoundSetSelectionForSoundSet:[sender representedObject]];
543 /* Save the preset which is now updated to have the appropriate sounds;
544 * in saving, the name of the soundset, or @"", will also be saved.
546 [self saveCurrentEventPreset];
550 * @brief Revert the event set to how it was before the last attempted operation
552 - (void)revertToSavedEventSet
554 NSDictionary *eventPreset;
556 [self selectActiveEventInPopUp];
557 eventPreset = [[popUp_eventPreset selectedItem] representedObject];
559 [plugin setEventPreset:eventPreset];
561 //Ensure the correct sound set is selected
562 [self updateSoundSetSelection];
566 * @brief Build and return the event set as it should be saved
568 - (NSMutableDictionary *)currentEventSetForSaving
570 NSDictionary *eventPreset = [[popUp_eventPreset selectedItem] representedObject];
571 NSMutableDictionary *currentEventSetForSaving = [[eventPreset mutableCopy] autorelease];
573 //Set the sound set, which is just stored here for ease of preference pane display
574 NSString *soundSetName = [[[popUp_soundSet selectedItem] representedObject] name];
576 [currentEventSetForSaving setObject:soundSetName
577 forKey:KEY_EVENT_SOUND_SET];
579 [currentEventSetForSaving removeObjectForKey:KEY_EVENT_SOUND_SET];
582 //Get and store the alerts array
583 NSArray *alertsArray = [[adium contactAlertsController] alertsForListObject:nil
586 [currentEventSetForSaving setObject:alertsArray forKey:@"Events"];
588 //Ensure this set doesn't claim to be built in.
589 [currentEventSetForSaving removeObjectForKey:@"Built In"];
591 return currentEventSetForSaving;
595 //New value selected on the volume slider or chosen by clicking a volume icon
596 - (IBAction)selectVolume:(id)sender
598 float volume, oldVolume;
600 if (sender == slider_volume) {
601 volume = [slider_volume floatValue];
602 } else if (sender == button_maxvolume) {
603 volume = [slider_volume maxValue];
604 [slider_volume setDoubleValue:volume];
605 } else if (sender == button_minvolume) {
606 volume = [slider_volume minValue];
607 [slider_volume setDoubleValue:volume];
612 NSNumber *oldVolumeValue = [[adium preferenceController] preferenceForKey:KEY_SOUND_CUSTOM_VOLUME_LEVEL
613 group:PREF_GROUP_SOUNDS];
614 oldVolume = (oldVolumeValue ? [oldVolumeValue floatValue] : -1.0);
617 if (volume != oldVolume) {
618 [[adium preferenceController] setPreference:[NSNumber numberWithFloat:volume]
619 forKey:KEY_SOUND_CUSTOM_VOLUME_LEVEL
620 group:PREF_GROUP_SOUNDS];
622 //Play a sample sound
623 [[adium soundController] playSoundAtPath:VOLUME_SOUND_PATH];
627 #pragma mark Preset saving
630 * @brief Save the current event preset
632 * Called after each event change to immediately update the current preset.
633 * If a built-in preset is currently selected, this method will prompt for a new name before saving.
635 - (void)saveCurrentEventPreset
637 NSDictionary *eventPreset = [[popUp_eventPreset selectedItem] representedObject];
639 if ([eventPreset objectForKey:@"Built In"] && [[eventPreset objectForKey:@"Built In"] boolValue]) {
640 /* Perform after a delay so that if we got here as a result of a sheet-based add or edit of an event
641 * the sheet will close before we try to open a new one. */
642 [self performSelector:@selector(showPresetCopySheet:)
643 withObject:[self _localizedTitle:[eventPreset objectForKey:@"Name"]]
646 //Now save the current settings
647 [plugin saveEventPreset:[self currentEventSetForSaving]];
652 * @brief Show the sheet for naming the preset created by an attempt to modify a built-in set
654 * @param originalPresetName The name of the original set, used as a base for the new name.
656 - (void)showPresetCopySheet:(NSString *)originalPresetName
658 NSString *defaultName;
659 NSString *explanatoryText;
661 defaultName = [NSString stringWithFormat:@"%@ %@", originalPresetName, COPY_IN_PARENTHESIS];
662 explanatoryText = AILocalizedString(@"You are editing a default event set. Please enter a unique name for your modified set.",nil);
664 [ESPresetNameSheetController showPresetNameSheetWithDefaultName:defaultName
665 explanatoryText:explanatoryText
666 onWindow:[[self view] window]
671 - (BOOL)presetNameSheetController:(ESPresetNameSheetController *)controller
672 shouldAcceptNewName:(NSString *)newName
673 userInfo:(id)userInfo
675 return (![[[plugin builtInEventPresets] allKeys] containsObject:newName] &&
676 ![[[plugin storedEventPresets] allKeys] containsObject:newName]);
679 - (void)presetNameSheetControllerDidEnd:(ESPresetNameSheetController *)controller
680 returnCode:(ESPresetNameSheetReturnCode)returnCode
681 newName:(NSString *)newName
682 userInfo:(id)userInfo
684 switch (returnCode) {
685 case ESPresetNameSheetOkayReturn:
687 //XXX error if overwriting existing set?
688 NSMutableDictionary *newEventPreset = [self currentEventSetForSaving];
689 [newEventPreset setObject:newName
692 //Now save the current settings
693 [plugin saveEventPreset:newEventPreset];
696 [[adium preferenceController] setPreference:newName
697 forKey:KEY_ACTIVE_EVENT_SET
698 group:PREF_GROUP_EVENT_PRESETS];
699 [popUp_eventPreset setMenu:[self eventPresetsMenu]];
700 [popUp_eventPreset selectItemWithTitle:newName];
704 case ESPresetNameSheetCancelReturn:
706 [self revertToSavedEventSet];
713 * @brief Called when the OK button on the preset copy sheet is pressed
715 * Save the current event set under the name specified by [textField_name stringValue].
716 * Set the name of the active event set to this new name, and ensure our menu is up to date.
718 * Also, close the sheet.
720 - (IBAction)selectedNameForPresetCopy:(id)sender
725 - (void)updateSoundSetSelectionForSoundSet:(AISoundSet *)soundSet
728 [popUp_soundSet selectItemWithRepresentedObject:soundSet];
730 [self popUp:popUp_soundSet shouldShowCustom:NO];
733 [self popUp:popUp_soundSet shouldShowCustom:YES];
737 - (void)updateSoundSetSelection
739 NSEnumerator *enumerator = [[[adium soundController] soundSets] objectEnumerator];
740 AISoundSet *soundSet;
743 name = [[[popUp_eventPreset selectedItem] representedObject] objectForKey:KEY_EVENT_SOUND_SET];
744 name = [[name lastPathComponent] stringByDeletingPathExtension];
746 while ((soundSet = [enumerator nextObject])) {
747 if ([[soundSet name] isEqualToString:name]) break;
750 [self updateSoundSetSelectionForSoundSet:soundSet];
753 #define NONE AILocalizedString(@"None",nil)
755 * @brief Build and return a menu of sound set choices
757 * The menu items have an action of -[self selectSoundSet:].
759 - (NSMenu *)_soundSetMenu
761 NSMenu *soundSetMenu = [[NSMenu alloc] init];
762 NSEnumerator *enumerator = [[[adium soundController] soundSets] objectEnumerator];
763 NSMutableArray *menuItemArray = [NSMutableArray array];
764 AISoundSet *soundSet;
765 NSMenuItem *menuItem, *noneMenuItem = nil;
767 while ((soundSet = [enumerator nextObject])) {
768 menuItem = [[NSMenuItem alloc] initWithTitle:[self _localizedTitle:[soundSet name]]
770 action:@selector(selectSoundSet:)
772 representedObject:soundSet];
774 if ([[menuItem title] isEqualToString:NONE]) {
775 noneMenuItem = menuItem;
778 [menuItemArray addObject:menuItem];
783 [menuItemArray sortUsingSelector:@selector(titleCompare:)];
785 enumerator = [menuItemArray objectEnumerator];
786 while ((menuItem = [enumerator nextObject])) {
787 [soundSetMenu addItem:menuItem];
791 [soundSetMenu addItem:[NSMenuItem separatorItem]];
792 [soundSetMenu addItem:noneMenuItem];
793 [noneMenuItem release];
796 return [soundSetMenu autorelease];
799 #pragma mark Common menu methods
801 * @brief Localized a menu item title for global events preferences
803 * @result The equivalent localized title if available; otherwise, the passed English title
805 - (NSString *)_localizedTitle:(NSString *)englishTitle
807 NSString *localizedTitle = nil;
809 if ([englishTitle isEqualToString:@"None"])
810 localizedTitle = NONE;
811 else if ([englishTitle isEqualToString:@"Default Notifications"])
812 localizedTitle = AILocalizedString(@"Default Notifications",nil);
813 else if ([englishTitle isEqualToString:@"Visual Notifications"])
814 localizedTitle = AILocalizedString(@"Visual Notifications",nil);
815 else if ([englishTitle isEqualToString:@"Audio Notifications"])
816 localizedTitle = AILocalizedString(@"Audio Notifications",nil);
818 return (localizedTitle ? localizedTitle : englishTitle);