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 "AIEventSoundsPlugin.h"
18 #import "AIPreferenceController.h"
19 #import "AISoundController.h"
20 #import "ESEventSoundAlertDetailPane.h"
21 #import <AIUtilities/AIMenuAdditions.h>
22 #import <AIUtilities/AIStringAdditions.h>
23 #import <AIUtilities/ESImageAdditions.h>
24 #import <Adium/AILocalizationTextField.h>
26 #define PLAY_A_SOUND AILocalizedString(@"Play a sound",nil)
27 #define KEY_DEFAULT_SOUND_DICT @"Default Sound Dict"
29 @interface ESEventSoundAlertDetailPane (PRIVATE)
30 - (NSMenu *)soundListMenu;
31 - (void)addSound:(NSString *)soundPath toMenu:(NSMenu *)soundMenu;
35 * @class ESEventSoundAlertDetailPane
36 * @brief Details pane for the Play Sound action
38 @implementation ESEventSoundAlertDetailPane
43 - (NSString *)nibName{
44 return(@"EventSoundContactAlert");
48 * @brief Configure the detail view
52 [label_sound setLocalizedString:AILocalizedString(@"Sound:",nil)];
54 /* Loading and using the real file icons is slow, and all the sound files should have the same icons anyway. So
55 * we can cheat and load a sound icon from our bundle here (for all the menu items) for a nice speed boost. */
56 if(!soundFileIcon) soundFileIcon = [[NSImage imageNamed:@"SoundFileIcon" forClass:[self class]] retain];
58 //Prepare our sound menu
59 [popUp_actionDetails setMenu:[self soundListMenu]];
65 * @brief View will close
69 [soundFileIcon release]; soundFileIcon = nil;
70 [super viewWillClose];
74 * @brief Configure for the action
76 - (void)configureForActionDetails:(NSDictionary *)inDetails listObject:(AIListObject *)inObject
78 NSString *selectedSound;
81 if(!inDetails) inDetails = [[adium preferenceController] preferenceForKey:KEY_DEFAULT_SOUND_DICT
82 group:PREF_GROUP_SOUNDS];
84 //If the user has a custom sound selected, we need to create an entry in the menu for it
85 selectedSound = [inDetails objectForKey:KEY_ALERT_SOUND_PATH];
87 if([[popUp_actionDetails menu] indexOfItemWithRepresentedObject:selectedSound] == -1){
88 [self addSound:selectedSound toMenu:[popUp_actionDetails menu]];
91 //Set the menu to its previous setting if the stored event matches
92 soundIndex = [popUp_actionDetails indexOfItemWithRepresentedObject:[inDetails objectForKey:KEY_ALERT_SOUND_PATH]];
93 if(soundIndex >= 0 && soundIndex < [popUp_actionDetails numberOfItems]){
94 [popUp_actionDetails selectItemAtIndex:soundIndex];
98 [popUp_actionDetails selectItemAtIndex:-1];
103 * @brief Return our current configuration
105 - (NSDictionary *)actionDetails
107 NSString *soundPath = [[popUp_actionDetails selectedItem] representedObject];
108 NSDictionary *actionDetails = nil;
110 if(soundPath && [soundPath length]){
111 actionDetails = [NSDictionary dictionaryWithObject:soundPath forKey:KEY_ALERT_SOUND_PATH];
114 //Save the preferred settings for future use as defaults
115 [[adium preferenceController] setPreference:actionDetails
116 forKey:KEY_DEFAULT_SOUND_DICT
117 group:PREF_GROUP_SOUNDS];
119 return actionDetails;
123 //Sound Menu -----------------------------------------------------------------------------------------------------------
124 #pragma mark Sound Menu
126 * @brief Builds and returns a sound list menu
128 * The menu is organized by sound set.
130 - (NSMenu *)soundListMenu
132 NSMenu *soundMenu = [[NSMenu alloc] init];
133 NSEnumerator *enumerator;
134 NSDictionary *soundSetDict;
135 NSMenuItem *menuItem;
137 //Add all soundsets to our menu
138 enumerator = [[[adium soundController] soundSetArray] objectEnumerator];
139 while((soundSetDict = [enumerator nextObject])){
140 NSEnumerator *soundEnumerator;
142 NSArray *soundSetContents = [soundSetDict objectForKey:KEY_SOUND_SET_CONTENTS];
144 if(soundSetContents && [soundSetContents count]){
145 NSMenu *soundsetMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];
147 //Add an item for the set
148 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[[[soundSetDict objectForKey:KEY_SOUND_SET] lastPathComponent] stringByDeletingPathExtension]
151 keyEquivalent:@""] autorelease];
153 //Add an item for each sound
154 soundEnumerator = [soundSetContents objectEnumerator];
155 while((soundPath = [soundEnumerator nextObject])){
156 [self addSound:soundPath toMenu:soundsetMenu];
159 [menuItem setSubmenu:soundsetMenu];
160 [soundsetMenu release];
162 [soundMenu addItem:menuItem];
166 //Add a divider between the sets and Other...
167 [soundMenu addItem:[NSMenuItem separatorItem]];
169 //Add the "Other..." item
170 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:OTHER_ELLIPSIS
172 action:@selector(selectSound:)
173 keyEquivalent:@""] autorelease];
174 [soundMenu addItem:menuItem];
175 [soundMenu setAutoenablesItems:NO];
177 return([soundMenu autorelease]);
181 * @brief Add a sound menu item to a menu
183 - (void)addSound:(NSString *)soundPath toMenu:(NSMenu *)soundMenu
185 NSString *soundTitle = [[soundPath lastPathComponent] stringByDeletingPathExtension];
186 NSMenuItem *menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:soundTitle
188 action:@selector(selectSound:)
189 keyEquivalent:@""] autorelease];
191 [menuItem setRepresentedObject:[soundPath stringByCollapsingBundlePath]];
192 [menuItem setImage:soundFileIcon];
193 [soundMenu addItem:menuItem];
197 * @brief Add a soundPath to the menu root if it is not yet present, then select it
199 * @param The soundPath, which should have a collapsed bundle path (to match menuItem represented objects)
201 - (void)addAndSelectSoundPath:(NSString *)soundPath
203 NSMenu *rootMenu = [popUp_actionDetails menu];
206 //Check for it currently being present in the root menu
207 menuIndex = [popUp_actionDetails indexOfItemWithRepresentedObject:soundPath];
208 if (menuIndex == -1) {
209 //Add it if it wasn't found
210 [self addSound:soundPath toMenu:rootMenu];
211 menuIndex = [popUp_actionDetails indexOfItemWithRepresentedObject:soundPath];
214 if (menuIndex != -1) {
215 [popUp_actionDetails selectItemAtIndex:menuIndex];
220 * @brief A sound was selected from a sound popUp menu
222 * Update our header and play the sound. If "Other..." is selected, allow selection of a file.
224 - (IBAction)selectSound:(id)sender
226 NSString *soundPath = [sender representedObject];
228 if(soundPath != nil && [soundPath length] != 0){
229 [[adium soundController] playSoundAtPath:[soundPath stringByExpandingBundlePath]]; //Play the sound
231 //Update the menu and and the selection
232 [self addAndSelectSoundPath:soundPath];
234 [self detailsForHeaderChanged];
235 }else{ //selected "Other..."
236 NSOpenPanel *openPanel = [NSOpenPanel openPanel];
239 beginSheetForDirectory:nil
241 types:[NSSound soundUnfilteredFileTypes] //allow all the sounds NSSound understands
242 modalForWindow:[view window]
244 didEndSelector:@selector(concludeOtherPanel:returnCode:contextInfo:)
251 * @brief Finish up the Other... panel
253 * Play the selected sound and update the menu.
255 - (void)concludeOtherPanel:(NSOpenPanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo
257 if(returnCode == NSOKButton){
258 NSString *soundPath = [[panel filenames] objectAtIndex:0];
260 [[adium soundController] playSoundAtPath:soundPath]; //Play the sound
262 //Update the menu and and the selection
263 [self addAndSelectSoundPath:soundPath];
265 [self detailsForHeaderChanged];