Unescape the HREF attribute's text before passing it to NSURL which does not expect...
[adiumx.git] / Source / ESEventSoundAlertDetailPane.m
blob089e6e1ee056d381f89703e0e383eee68fb78859
1 /* 
2  * Adium is the legal property of its developers, whose names are listed in the copyright file included
3  * with this source distribution.
4  * 
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.
8  * 
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.
12  * 
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.
15  */
17 #import "AIEventSoundsPlugin.h"
18 #import <Adium/AIPreferenceControllerProtocol.h>
19 #import "AISoundController.h"
20 #import "ESEventSoundAlertDetailPane.h"
21 #import <AIUtilities/AIMenuAdditions.h>
22 #import <AIUtilities/AIStringAdditions.h>
23 #import <AIUtilities/AIImageAdditions.h>
24 #import <Adium/AISoundSet.h>
25 #import <Adium/AILocalizationTextField.h>
27 #define PLAY_A_SOUND                    AILocalizedString(@"Play a sound",nil)
28 #define KEY_DEFAULT_SOUND_DICT  @"Default Sound Dict"
30 @interface ESEventSoundAlertDetailPane (PRIVATE)
31 - (NSMenu *)soundListMenu;
32 - (void)addSound:(NSString *)soundPath toMenu:(NSMenu *)soundMenu;
33 @end
35 /*!
36  * @class ESEventSoundAlertDetailPane
37  * @brief Details pane for the Play Sound action
38  */
39 @implementation ESEventSoundAlertDetailPane
41 /*!
42  * @brief Nib name
43  */
44 - (NSString *)nibName{
45     return @"EventSoundContactAlert";    
48 /*!
49  * @brief Configure the detail view
50  */
51 - (void)viewDidLoad
53         [label_sound setLocalizedString:AILocalizedString(@"Sound:",nil)];
55         /* Loading and using the real file icons is slow, and all the sound files should have the same icons anyway.  So
56          * we can cheat and load a sound icon from our bundle here (for all the menu items) for a nice speed boost. */
57         if (!soundFileIcon) soundFileIcon = [[NSImage imageNamed:@"SoundFileIcon" forClass:[self class]] retain];
58         
59         //Prepare our sound menu
60     [popUp_actionDetails setMenu:[self soundListMenu]];
61         
62         [super viewDidLoad];
65 /*!
66  * @brief View will close
67  */
68 - (void)viewWillClose
70         //The user probably does not want the sound to continue playing (especially if it's long), so stop it.
71         NSString                *soundPath = [[popUp_actionDetails selectedItem] representedObject];
72         [[adium soundController] stopPlayingSoundAtPath:soundPath];
74         [soundFileIcon release]; soundFileIcon = nil;
75         [super viewWillClose];
78 /*!
79  * @brief Configure for the action
80  */
81 - (void)configureForActionDetails:(NSDictionary *)inDetails listObject:(AIListObject *)inObject
83         NSString        *selectedSound;
84         int                     soundIndex;
85         
86         if (!inDetails) inDetails = [[adium preferenceController] preferenceForKey:KEY_DEFAULT_SOUND_DICT
87                                                                                                                                                 group:PREF_GROUP_SOUNDS];
89         //If the user has a custom sound selected, we need to create an entry in the menu for it
90         selectedSound = [inDetails objectForKey:KEY_ALERT_SOUND_PATH];
91         if (selectedSound) {
92                 if ([[popUp_actionDetails menu] indexOfItemWithRepresentedObject:selectedSound] == -1) {
93                         [self addSound:selectedSound toMenu:[popUp_actionDetails menu]];
94                 }
95                 
96                 //Set the menu to its previous setting if the stored event matches
97                 soundIndex = [popUp_actionDetails indexOfItemWithRepresentedObject:[inDetails objectForKey:KEY_ALERT_SOUND_PATH]];
98                 if (soundIndex >= 0 && soundIndex < [popUp_actionDetails numberOfItems]) {
99                         [popUp_actionDetails selectItemAtIndex:soundIndex];        
100                 }
101                 
102         } else {
103                 [popUp_actionDetails selectItemAtIndex:-1];
104         }       
108  * @brief Return our current configuration
109  */
110 - (NSDictionary *)actionDetails
112         NSString                *soundPath = [[popUp_actionDetails selectedItem] representedObject];
113         NSDictionary    *actionDetails = nil;
115         if (soundPath && [soundPath length]) {
116                 actionDetails = [NSDictionary dictionaryWithObject:soundPath forKey:KEY_ALERT_SOUND_PATH];
117         }
119         //Save the preferred settings for future use as defaults
120         [[adium preferenceController] setPreference:actionDetails
121                                                                                  forKey:KEY_DEFAULT_SOUND_DICT
122                                                                                   group:PREF_GROUP_SOUNDS];
123         
124         return actionDetails;
128 //Sound Menu -----------------------------------------------------------------------------------------------------------
129 #pragma mark Sound Menu
131  * @brief Builds and returns a sound list menu
133  * The menu is organized by sound set.
134  */
135 - (NSMenu *)soundListMenu
137         NSMenu                  *soundMenu = [[NSMenu alloc] init];
138         NSEnumerator    *enumerator;
139         AISoundSet              *soundSet;
140         NSMenuItem              *menuItem;
141         
142         //Add all soundsets to our menu
143         enumerator = [[[adium soundController] soundSets] objectEnumerator];
144         while ((soundSet = [enumerator nextObject])) {
145                 NSString        *soundSetName = nil;
146                 NSArray         *soundSetContents = nil;
147                 NSEnumerator    *soundEnumerator;
148                 NSString        *soundPath;
150                 soundSetName = [soundSet name];
151                 soundSetContents = [[soundSet sounds] allValues];
153                 NSAssert1(soundSetName != nil, @"Sound set does not have a name: %@", soundSet);
154                 
155                 if (soundSetContents && [soundSetContents count]) {
156                         NSMenu  *soundsetMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];
158                         //Add an item for the set
159                         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:soundSetName
160                                                                                                                                                          target:nil
161                                                                                                                                                          action:nil
162                                                                                                                                           keyEquivalent:@""] autorelease];
163                         
164                         //Add an item for each sound
165                         soundEnumerator = [soundSetContents objectEnumerator];
166                         while ((soundPath = [soundEnumerator nextObject])) {
167                                 [self addSound:soundPath toMenu:soundsetMenu];
168                         }
169                         
170                         [menuItem setSubmenu:soundsetMenu];
171                         [soundsetMenu release];
173                         [soundMenu addItem:menuItem];
174                 }
175         }
177         //Add a divider between the sets and Other...
178         [soundMenu addItem:[NSMenuItem separatorItem]];
180         //Add the "Other..." item
181         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:OTHER_ELLIPSIS
182                                                                                                                                          target:self
183                                                                                                                                          action:@selector(selectSound:)
184                                                                                                                           keyEquivalent:@""] autorelease];            
185         [soundMenu addItem:menuItem];
186         [soundMenu setAutoenablesItems:NO];
187         
188     return [soundMenu autorelease];
192  * @brief Add a sound menu item to a menu
193  */
194 - (void)addSound:(NSString *)soundPath toMenu:(NSMenu *)soundMenu
196         NSString        *soundTitle = [[soundPath lastPathComponent] stringByDeletingPathExtension];
197         NSMenuItem      *menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:soundTitle
198                                                                                                                                                                   target:self
199                                                                                                                                                                   action:@selector(selectSound:)
200                                                                                                                                                    keyEquivalent:@""] autorelease];
201         
202         [menuItem setRepresentedObject:[soundPath stringByCollapsingBundlePath]];
203         [menuItem setImage:soundFileIcon];
204         [soundMenu addItem:menuItem];
208  * @brief Add a soundPath to the menu root if it is not yet present, then select it
210  * @param The soundPath, which should have a collapsed bundle path (to match menuItem represented objects)
211  */
212 - (void)addAndSelectSoundPath:(NSString *)soundPath
214         NSMenu  *rootMenu = [popUp_actionDetails menu];
215         int             menuIndex;
216         
217         //Check for it currently being present in the root menu
218         menuIndex = [popUp_actionDetails indexOfItemWithRepresentedObject:soundPath];
219         if (menuIndex == -1) {
220                 //Add it if it wasn't found
221                 [self addSound:soundPath toMenu:rootMenu];
222                 menuIndex = [popUp_actionDetails indexOfItemWithRepresentedObject:soundPath];                   
223         }
224         
225         if (menuIndex != -1) {
226                 [popUp_actionDetails selectItemAtIndex:menuIndex];
227         }
231  * @brief A sound was selected from a sound popUp menu
233  * Update our header and play the sound.  If "Other..." is selected, allow selection of a file.
234  */
235 - (IBAction)selectSound:(id)sender
237     NSString    *soundPath = [sender representedObject];
238     
239     if (soundPath != nil && [soundPath length] != 0) {
240         [[adium soundController] playSoundAtPath:[soundPath stringByExpandingBundlePath]]; //Play the sound
242                 //Update the menu and and the selection
243                 [self addAndSelectSoundPath:soundPath];
245                 [self detailsForHeaderChanged];
246     } else { //selected "Other..."
247         NSOpenPanel *openPanel = [NSOpenPanel openPanel];
248         
249         [openPanel 
250             beginSheetForDirectory:nil
251                               file:nil
252                              types:[NSSound soundUnfilteredFileTypes] //allow all the sounds NSSound understands
253                     modalForWindow:[view window]
254                      modalDelegate:self
255                     didEndSelector:@selector(concludeOtherPanel:returnCode:contextInfo:)
256                        contextInfo:nil];  
258     }
262  * @brief Finish up the Other... panel
264  * Play the selected sound and update the menu.
265  */
266 - (void)concludeOtherPanel:(NSOpenPanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo
268     if (returnCode == NSOKButton) {
269         NSString *soundPath = [[panel filenames] objectAtIndex:0];
270         
271         [[adium soundController] playSoundAtPath:soundPath]; //Play the sound
273         //Update the menu and and the selection
274                 [self addAndSelectSoundPath:soundPath];
276                 [self detailsForHeaderChanged];
277     }
280 @end