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 [label_eventPreset setLocalizedString:AILocalizedString(@"Event preset:",nil)];
129 [label_soundSet setLocalizedString:AILocalizedString(@"Sound set:",nil)];
133 * @brief Preference view is closing
135 - (void)viewWillClose
137 [contactAlertsViewController viewWillClose];
138 [contactAlertsViewController release]; contactAlertsViewController = nil;
140 [[adium preferenceController] unregisterPreferenceObserver:self];
141 [[adium notificationCenter] removeObserver:self];
145 * @brief PREF_GROUP_CONTACT_ALERTS changed; update our summary data
147 - (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key
148 object:(AIListObject *)object preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
150 if ([group isEqualToString:PREF_GROUP_EVENT_PRESETS]) {
151 if (!key || [key isEqualToString:@"Event Presets"]) {
152 //Update when the available event presets change
153 [self setAndConfigureEventPresetsMenu];
159 * @brief Set if a popup should have a "Custom" menu item
161 - (void)popUp:(NSPopUpButton *)inPopUp shouldShowCustom:(BOOL)showCustom
163 NSMenuItem *lastItem = [inPopUp lastItem];
164 BOOL customIsShowing = (lastItem && (![lastItem representedObject] &&
165 [[lastItem title] isEqualToString:CUSTOM_TITLE]));
166 if (showCustom && !customIsShowing) {
167 //Add 'custom' then select it
168 [[inPopUp menu] addItem:[NSMenuItem separatorItem]];
169 [[inPopUp menu] addItemWithTitle:CUSTOM_TITLE
173 [inPopUp selectItem:[inPopUp lastItem]];
175 } else if (!showCustom && customIsShowing) {
176 //If it currently has a 'custom' item listed, remove it and the separator above it
177 [inPopUp removeItemAtIndex:([inPopUp numberOfItems]-1)];
178 [inPopUp removeItemAtIndex:([inPopUp numberOfItems]-1)];
183 * @brief Update our soundset menu if a new sound set is instaled
185 - (void)xtrasChanged:(NSNotification *)notification
187 if (!notification || [[notification object] caseInsensitiveCompare:@"AdiumSoundset"] == NSOrderedSame) {
188 //Build the soundset menu
189 [popUp_soundSet setMenu:[self _soundSetMenu]];
193 #pragma mark Event presets
196 * @brief Buld and return the event presets menu
198 * The menu will have built in presets, a divider, user-set presets, a divider, and then the preset management item(s)
200 - (NSMenu *)eventPresetsMenu
202 NSMenu *eventPresetsMenu = [[NSMenu allocWithZone:[NSMenu zone]] init];
203 NSEnumerator *enumerator;
204 NSDictionary *eventPreset;
205 NSMenuItem *menuItem;
207 //Built in event presets
208 enumerator = [[plugin builtInEventPresetsArray] objectEnumerator];
209 while ((eventPreset = [enumerator nextObject])) {
210 NSString *name = [eventPreset objectForKey:@"Name"];
212 //Add a menu item for the set
213 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[self _localizedTitle:name]
215 action:@selector(selectEventPreset:)
216 keyEquivalent:@""] autorelease];
217 [menuItem setRepresentedObject:eventPreset];
218 [eventPresetsMenu addItem:menuItem];
221 NSArray *storedEventPresetsArray = [plugin storedEventPresetsArray];
223 if ([storedEventPresetsArray count]) {
224 [eventPresetsMenu addItem:[NSMenuItem separatorItem]];
226 enumerator = [storedEventPresetsArray objectEnumerator];
227 while ((eventPreset = [enumerator nextObject])) {
228 NSString *name = [eventPreset objectForKey:@"Name"];
230 //Add a menu item for the set
231 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:name
233 action:@selector(selectEventPreset:)
234 keyEquivalent:@""] autorelease];
235 [menuItem setRepresentedObject:eventPreset];
236 [eventPresetsMenu addItem:menuItem];
241 [eventPresetsMenu addItem:[NSMenuItem separatorItem]];
243 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[AILocalizedString(@"Add New Preset",nil) stringByAppendingEllipsis]
245 action:@selector(addNewPreset:)
246 keyEquivalent:@""] autorelease];
247 [eventPresetsMenu addItem:menuItem];
249 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[AILocalizedString(@"Edit Presets",nil) stringByAppendingEllipsis]
251 action:@selector(editPresets:)
252 keyEquivalent:@""] autorelease];
253 [eventPresetsMenu addItem:menuItem];
255 return [eventPresetsMenu autorelease];
258 - (void)selectActiveEventInPopUp
260 NSString *activeEventSetName = [[adium preferenceController] preferenceForKey:KEY_ACTIVE_EVENT_SET
261 group:PREF_GROUP_EVENT_PRESETS];
263 //First try to set the localized version
264 [popUp_eventPreset selectItemWithTitle:[self _localizedTitle:activeEventSetName]];
265 //If that fails, look for one exactly matching
266 if (![popUp_eventPreset selectedItem]) [popUp_eventPreset selectItemWithTitle:activeEventSetName];
267 //And if that fails, select the first item (something went wrong, we should at least have a selection)
268 if (![popUp_eventPreset selectedItem]) [popUp_eventPreset selectItemAtIndex:0];
271 - (void)setAndConfigureEventPresetsMenu
273 [popUp_eventPreset setMenu:[self eventPresetsMenu]];
274 [self selectActiveEventInPopUp];
278 * @brief Selected an event preset
280 * Pass it to the plugin, which will perform necessary changes to our contact alerts
282 - (void)selectEventPreset:(id)sender
284 NSDictionary *eventPreset = [sender representedObject];
285 [plugin setEventPreset:eventPreset];
287 [self updateSoundSetSelection];
293 * Called by the "Add New preset..." menu item. Functions the same as duplicate from the preset management, duplicating
294 * the current event set with a new name.
296 - (void)addNewPreset:(id)sender
298 NSString *defaultName;
299 NSString *explanatoryText;
301 defaultName = [NSString stringWithFormat:@"%@ %@",
302 [self _localizedTitle:[[adium preferenceController] preferenceForKey:KEY_ACTIVE_EVENT_SET
303 group:PREF_GROUP_EVENT_PRESETS]],
304 COPY_IN_PARENTHESIS];
305 explanatoryText = AILocalizedString(@"Enter a unique name for this new event set.",nil);
307 [ESPresetNameSheetController showPresetNameSheetWithDefaultName:defaultName
308 explanatoryText:explanatoryText
309 onWindow:[[self view] window]
313 //Get our event presets menu back to its proper selection
314 [self selectActiveEventInPopUp];
318 * @brief Manage presets
320 * Called by the "Edit Presets..." menu item
322 - (void)editPresets:(id)sender
324 [ESPresetManagementController managePresets:[plugin storedEventPresetsArray]
326 onWindow:[[self view] window]
329 //Get our event presets menu back to its proper selection
330 [self selectActiveEventInPopUp];
333 - (BOOL)allowDeleteOfPreset:(NSDictionary *)preset
335 NSString *name = [preset objectForKey:@"Name"];
336 NSString *localizedTitle;
338 localizedTitle = [self _localizedTitle:[[adium preferenceController] preferenceForKey:KEY_ACTIVE_EVENT_SET
339 group:PREF_GROUP_EVENT_PRESETS]];
340 //Don't allow the active preset to be deleted
341 return (![localizedTitle isEqualToString:name]);
344 - (NSArray *)renamePreset:(NSDictionary *)preset toName:(NSString *)newName inPresets:(NSArray *)presets renamedPreset:(id *)renamedPreset
346 NSString *oldPresetName = [preset objectForKey:@"Name"];
347 NSMutableDictionary *newPreset = [preset mutableCopy];
348 NSString *localizedCurrentName = [self _localizedTitle:[[adium preferenceController] preferenceForKey:KEY_ACTIVE_EVENT_SET
349 group:PREF_GROUP_EVENT_PRESETS]];
350 [newPreset setObject:newName
353 //Mark the newly created (but still functionally identical) event set as active if the old one was active
354 if ([localizedCurrentName isEqualToString:oldPresetName]) {
355 [[adium preferenceController] setPreference:newName
356 forKey:KEY_ACTIVE_EVENT_SET
357 group:PREF_GROUP_EVENT_PRESETS];
360 //Remove the original one from the array, and add the newly-renamed one
361 [plugin deleteEventPreset:preset];
362 [plugin saveEventPreset:newPreset];
364 if (renamedPreset) *renamedPreset = newPreset;
366 //Return an updated presets array
367 return [plugin storedEventPresetsArray];
370 - (NSArray *)duplicatePreset:(NSDictionary *)preset inPresets:(NSArray *)presets createdDuplicate:(id *)duplicatePreset
372 NSMutableDictionary *newEventPreset = [preset mutableCopy];
373 NSString *newName = [NSString stringWithFormat:@"%@ %@", [preset objectForKey:@"Name"], COPY_IN_PARENTHESIS];
374 [newEventPreset setObject:newName
377 //Remove the original preset's order index
378 [newEventPreset removeObjectForKey:@"OrderIndex"];
380 //Now save the new preset
381 [plugin saveEventPreset:newEventPreset];
383 //Return the created duplicate by reference
384 if (duplicatePreset != NULL) *duplicatePreset = [[newEventPreset retain] autorelease];
387 [newEventPreset release];
389 //Return an updated presets array
390 return [plugin storedEventPresetsArray];
393 - (NSArray *)deletePreset:(NSDictionary *)preset inPresets:(NSArray *)presets
396 [plugin deleteEventPreset:preset];
398 //Return an updated presets array
399 return [plugin storedEventPresetsArray];
402 - (NSArray *)movePreset:(NSDictionary *)preset toIndex:(int)index inPresets:(NSArray *)presets presetAfterMove:(id *)presetAfterMove
404 NSMutableDictionary *newEventPreset = [preset mutableCopy];
407 newOrderIndex = [[[presets objectAtIndex:0] objectForKey:@"OrderIndex"] floatValue] / 2.0;
409 } else if (index < [presets count]) {
410 float above = [[[presets objectAtIndex:index-1] objectForKey:@"OrderIndex"] floatValue];
411 float below = [[[presets objectAtIndex:index] objectForKey:@"OrderIndex"] floatValue];
412 newOrderIndex = ((above + below) / 2.0);
415 newOrderIndex = [plugin nextOrderIndex];
418 [newEventPreset setObject:[NSNumber numberWithFloat:newOrderIndex]
419 forKey:@"OrderIndex"];
421 //Now save the new preset
422 [plugin saveEventPreset:newEventPreset];
423 if (presetAfterMove != NULL) *presetAfterMove = [[newEventPreset retain] autorelease];
424 [newEventPreset release];
426 //Return an updated presets array
427 return [plugin storedEventPresetsArray];
430 #pragma mark Contact alerts changed by user
431 - (void)contactAlertsViewController:(ESContactAlertsViewController *)inController
432 updatedAlert:(NSDictionary *)newAlert
433 oldAlert:(NSDictionary *)oldAlert
435 [self contactAlertsDidChangeForActionID:[newAlert objectForKey:KEY_ACTION_ID]];
438 - (void)contactAlertsViewController:(ESContactAlertsViewController *)inController
439 deletedAlert:(NSDictionary *)deletedAlert
441 [self contactAlertsDidChangeForActionID:[deletedAlert objectForKey:KEY_ACTION_ID]];
445 * @brief Contact alerts were changed by the user
447 - (void)contactAlertsDidChangeForActionID:(NSString *)actionID
450 [actionID isEqualToString:SOUND_ALERT_IDENTIFIER]) {
452 NSArray *alertsArray = [[adium contactAlertsController] alertsForListObject:nil
454 actionID:SOUND_ALERT_IDENTIFIER];
455 NSMenuItem *soundMenuItem;
457 if (![alertsArray count]) {
458 //We can select "None" if there are no sounds
459 soundMenuItem = (NSMenuItem *)[popUp_soundSet itemWithTitle:@"None"];
462 /* Otherwise, check to see if we remain in our proper soundset.
463 * Note that this won't detect if we return to a soundset, but that'd be an expensive search.
465 soundMenuItem = (NSMenuItem *)[popUp_soundSet selectedItem];
467 AISoundSet *soundSet = [soundMenuItem representedObject];
468 NSEnumerator *enumerator;
470 NSDictionary *sounds = [soundSet sounds];
472 if ([alertsArray count] && ![sounds count]) {
473 //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.
477 //First, check to see if any sounds which are present within this sound set have been changed
478 enumerator = [sounds keyEnumerator];
479 while ((key = [enumerator nextObject])) {
480 NSDictionary *soundAlert = [ESGlobalEventsPreferencesPlugin soundAlertForKey:key
481 inSoundsDict:sounds];
482 if (![alertsArray containsObject:soundAlert]) {
488 //Next, see if any sounds not present within this sound set have been added
490 NSDictionary *alertDict;
491 enumerator = [alertsArray objectEnumerator];
492 while ((alertDict = [enumerator nextObject])) {
493 if ([[alertDict objectForKey:KEY_ACTION_ID] isEqualToString:SOUND_ALERT_IDENTIFIER]) {
494 NSString *englishEvent = [[[AIObject sharedAdiumInstance] contactAlertsController] eventIDForEnglishDisplayName:key];
496 * If the sounds dictionary has no action for this event, or it has one but
497 * it is for a different sound than specified, the sound set has been changed
499 if (![sounds objectForKey:englishEvent] ||
500 ![[[alertDict objectForKey:KEY_ACTION_DETAILS] objectForKey:KEY_ALERT_SOUND_PATH] isEqualToString:[sounds objectForKey:englishEvent]]) {
511 [self selectSoundSet:([soundMenuItem representedObject] ? soundMenuItem : nil)];
514 [self saveCurrentEventPreset];
518 #pragma mark Sound sets
520 * @brief Called when an item in the sound set popUp is selected.
522 * Also called after the user changes sounds manually, by -[ESGlobalEventsPreferences contactAlertsDidChangeForActionID].
524 - (IBAction)selectSoundSet:(id)sender
526 //Apply the sound set so its events are in the current alerts.
528 [plugin applySoundSet:[sender representedObject]];
531 /* Update the selection, which will select Custom as appropriate. This must be done before saving the event
532 * preset so the menu is on the correct sound set to save.
534 [self updateSoundSetSelectionForSoundSet:[sender representedObject]];
536 /* Save the preset which is now updated to have the appropriate sounds;
537 * in saving, the name of the soundset, or @"", will also be saved.
539 [self saveCurrentEventPreset];
543 * @brief Revert the event set to how it was before the last attempted operation
545 - (void)revertToSavedEventSet
547 NSDictionary *eventPreset;
549 [self selectActiveEventInPopUp];
550 eventPreset = [[popUp_eventPreset selectedItem] representedObject];
552 [plugin setEventPreset:eventPreset];
554 //Ensure the correct sound set is selected
555 [self updateSoundSetSelection];
559 * @brief Build and return the event set as it should be saved
561 - (NSMutableDictionary *)currentEventSetForSaving
563 NSDictionary *eventPreset = [[popUp_eventPreset selectedItem] representedObject];
564 NSMutableDictionary *currentEventSetForSaving = [[eventPreset mutableCopy] autorelease];
566 //Set the sound set, which is just stored here for ease of preference pane display
567 NSString *soundSetName = [[[popUp_soundSet selectedItem] representedObject] name];
569 [currentEventSetForSaving setObject:soundSetName
570 forKey:KEY_EVENT_SOUND_SET];
572 [currentEventSetForSaving removeObjectForKey:KEY_EVENT_SOUND_SET];
575 //Get and store the alerts array
576 NSArray *alertsArray = [[adium contactAlertsController] alertsForListObject:nil
579 [currentEventSetForSaving setObject:alertsArray forKey:@"Events"];
581 //Ensure this set doesn't claim to be built in.
582 [currentEventSetForSaving removeObjectForKey:@"Built In"];
584 return currentEventSetForSaving;
588 //New value selected on the volume slider or chosen by clicking a volume icon
589 - (IBAction)selectVolume:(id)sender
591 float volume, oldVolume;
593 if (sender == slider_volume) {
594 volume = [slider_volume floatValue];
595 } else if (sender == button_maxvolume) {
596 volume = [slider_volume maxValue];
597 [slider_volume setDoubleValue:volume];
598 } else if (sender == button_minvolume) {
599 volume = [slider_volume minValue];
600 [slider_volume setDoubleValue:volume];
605 NSNumber *oldVolumeValue = [[adium preferenceController] preferenceForKey:KEY_SOUND_CUSTOM_VOLUME_LEVEL
606 group:PREF_GROUP_SOUNDS];
607 oldVolume = (oldVolumeValue ? [oldVolumeValue floatValue] : -1.0);
610 if (volume != oldVolume) {
611 [[adium preferenceController] setPreference:[NSNumber numberWithFloat:volume]
612 forKey:KEY_SOUND_CUSTOM_VOLUME_LEVEL
613 group:PREF_GROUP_SOUNDS];
615 //Play a sample sound
616 [[adium soundController] playSoundAtPath:VOLUME_SOUND_PATH];
620 #pragma mark Preset saving
623 * @brief Save the current event preset
625 * Called after each event change to immediately update the current preset.
626 * If a built-in preset is currently selected, this method will prompt for a new name before saving.
628 - (void)saveCurrentEventPreset
630 NSDictionary *eventPreset = [[popUp_eventPreset selectedItem] representedObject];
632 if ([eventPreset objectForKey:@"Built In"] && [[eventPreset objectForKey:@"Built In"] boolValue]) {
633 /* Perform after a delay so that if we got here as a result of a sheet-based add or edit of an event
634 * the sheet will close before we try to open a new one. */
635 [self performSelector:@selector(showPresetCopySheet:)
636 withObject:[self _localizedTitle:[eventPreset objectForKey:@"Name"]]
639 //Now save the current settings
640 [plugin saveEventPreset:[self currentEventSetForSaving]];
645 * @brief Show the sheet for naming the preset created by an attempt to modify a built-in set
647 * @param originalPresetName The name of the original set, used as a base for the new name.
649 - (void)showPresetCopySheet:(NSString *)originalPresetName
651 NSString *defaultName;
652 NSString *explanatoryText;
654 defaultName = [NSString stringWithFormat:@"%@ %@", originalPresetName, COPY_IN_PARENTHESIS];
655 explanatoryText = AILocalizedString(@"You are editing a default event set. Please enter a unique name for your modified set.",nil);
657 [ESPresetNameSheetController showPresetNameSheetWithDefaultName:defaultName
658 explanatoryText:explanatoryText
659 onWindow:[[self view] window]
664 - (BOOL)presetNameSheetController:(ESPresetNameSheetController *)controller
665 shouldAcceptNewName:(NSString *)newName
666 userInfo:(id)userInfo
668 return (![[[plugin builtInEventPresets] allKeys] containsObject:newName] &&
669 ![[[plugin storedEventPresets] allKeys] containsObject:newName]);
672 - (void)presetNameSheetControllerDidEnd:(ESPresetNameSheetController *)controller
673 returnCode:(ESPresetNameSheetReturnCode)returnCode
674 newName:(NSString *)newName
675 userInfo:(id)userInfo
677 switch (returnCode) {
678 case ESPresetNameSheetOkayReturn:
680 //XXX error if overwriting existing set?
681 NSMutableDictionary *newEventPreset = [self currentEventSetForSaving];
682 [newEventPreset setObject:newName
685 //Now save the current settings
686 [plugin saveEventPreset:newEventPreset];
689 [[adium preferenceController] setPreference:newName
690 forKey:KEY_ACTIVE_EVENT_SET
691 group:PREF_GROUP_EVENT_PRESETS];
692 [popUp_eventPreset setMenu:[self eventPresetsMenu]];
693 [popUp_eventPreset selectItemWithTitle:newName];
697 case ESPresetNameSheetCancelReturn:
699 [self revertToSavedEventSet];
706 * @brief Called when the OK button on the preset copy sheet is pressed
708 * Save the current event set under the name specified by [textField_name stringValue].
709 * Set the name of the active event set to this new name, and ensure our menu is up to date.
711 * Also, close the sheet.
713 - (IBAction)selectedNameForPresetCopy:(id)sender
718 - (void)updateSoundSetSelectionForSoundSet:(AISoundSet *)soundSet
721 [popUp_soundSet selectItemWithRepresentedObject:soundSet];
723 [self popUp:popUp_soundSet shouldShowCustom:NO];
726 [self popUp:popUp_soundSet shouldShowCustom:YES];
730 - (void)updateSoundSetSelection
732 NSEnumerator *enumerator = [[[adium soundController] soundSets] objectEnumerator];
733 AISoundSet *soundSet;
736 name = [[[popUp_eventPreset selectedItem] representedObject] objectForKey:KEY_EVENT_SOUND_SET];
737 name = [[name lastPathComponent] stringByDeletingPathExtension];
739 while ((soundSet = [enumerator nextObject])) {
740 if ([[soundSet name] isEqualToString:name]) break;
743 [self updateSoundSetSelectionForSoundSet:soundSet];
746 #define NONE AILocalizedString(@"None",nil)
748 * @brief Build and return a menu of sound set choices
750 * The menu items have an action of -[self selectSoundSet:].
752 - (NSMenu *)_soundSetMenu
754 NSMenu *soundSetMenu = [[NSMenu alloc] init];
755 NSEnumerator *enumerator = [[[adium soundController] soundSets] objectEnumerator];
756 NSMutableArray *menuItemArray = [NSMutableArray array];
757 AISoundSet *soundSet;
758 NSMenuItem *menuItem, *noneMenuItem = nil;
760 while ((soundSet = [enumerator nextObject])) {
761 menuItem = [[NSMenuItem alloc] initWithTitle:[self _localizedTitle:[soundSet name]]
763 action:@selector(selectSoundSet:)
765 representedObject:soundSet];
767 if ([[menuItem title] isEqualToString:NONE]) {
768 noneMenuItem = menuItem;
771 [menuItemArray addObject:menuItem];
776 [menuItemArray sortUsingSelector:@selector(titleCompare:)];
778 enumerator = [menuItemArray objectEnumerator];
779 while ((menuItem = [enumerator nextObject])) {
780 [soundSetMenu addItem:menuItem];
784 [soundSetMenu addItem:[NSMenuItem separatorItem]];
785 [soundSetMenu addItem:noneMenuItem];
786 [noneMenuItem release];
789 return [soundSetMenu autorelease];
792 #pragma mark Common menu methods
794 * @brief Localized a menu item title for global events preferences
796 * @result The equivalent localized title if available; otherwise, the passed English title
798 - (NSString *)_localizedTitle:(NSString *)englishTitle
800 NSString *localizedTitle = nil;
802 if ([englishTitle isEqualToString:@"None"])
803 localizedTitle = NONE;
804 else if ([englishTitle isEqualToString:@"Default Notifications"])
805 localizedTitle = AILocalizedString(@"Default Notifications",nil);
806 else if ([englishTitle isEqualToString:@"Visual Notifications"])
807 localizedTitle = AILocalizedString(@"Visual Notifications",nil);
808 else if ([englishTitle isEqualToString:@"Audio Notifications"])
809 localizedTitle = AILocalizedString(@"Audio Notifications",nil);
811 return (localizedTitle ? localizedTitle : englishTitle);