Merged [15040]: Trying some magic: 5 seconds after the last unreachable host is repor...
[adiumx.git] / Source / AIAppearancePreferences.m
blobdbd9d72c7143f078266d9675ba90c9e3a46ff948
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 "AIAppearancePreferences.h"
18 #import "AIAppearancePreferencesPlugin.h"
19 #import "AIDockController.h"
20 #import "AIDockIconSelectionSheet.h"
21 #import "AIEmoticonPack.h"
22 #import "AIEmoticonPreferences.h"
23 #import "AIListLayoutWindowController.h"
24 #import "AIListThemeWindowController.h"
25 #import <AIUtilities/AIMenuAdditions.h>
26 #import <AIUtilities/ESImageAdditions.h>
27 #import <AIUtilities/AIPopUpButtonAdditions.h>
28 #import <Adium/AIEmoticonController.h>
29 #import <Adium/AIIconState.h>
30 #import <Adium/AIServiceIcons.h>
31 #import <Adium/AIStatusIcons.h>
32 #import <Adium/ESPresetManagementController.h>
33 #import <Adium/ESPresetNameSheetController.h>
35 #warning crosslink
36 #import "AISCLViewPlugin.h"
38 typedef enum {
39         AIEmoticonMenuNone = 1,
40         AIEmoticonMenuMultiple
41 } AIEmoticonMenuTag;
43 @interface AIAppearancePreferences (PRIVATE)
44 - (NSMenu *)_windowStyleMenu;
45 - (NSMenu *)_dockIconMenu;
46 - (NSMenu *)_emoticonPackMenu;
47 - (NSMenu *)_statusIconsMenu;
48 - (NSMenu *)_serviceIconsMenu;
49 - (NSMenu *)_listLayoutMenu;
50 - (NSMenu *)_colorThemeMenu;
51 - (void)_rebuildEmoticonMenuAndSelectActivePack;
52 - (NSMenu *)_iconPackMenuForPacks:(NSArray *)packs class:(Class)iconClass;
53 - (void)_addWindowStyleOption:(NSString *)option withTag:(int)tag toMenu:(NSMenu *)menu;
54 - (void)_updateSliderValues;
55 @end
57 @implementation AIAppearancePreferences
59 /*!
60  * @brief Preference pane properties
61  */
62 - (PREFERENCE_CATEGORY)category{
63     return(AIPref_Appearance);
65 - (NSString *)label{
66     return(AILocalizedString(@"Appearance","Appearance preferences label"));
68 - (NSString *)nibName{
69     return(@"AppearancePrefs");
72 /*!
73  * @brief Configure the preference view
74  */
75 - (void)viewDidLoad
77     NSDictionary        *prefDict = [[adium preferenceController] preferencesForGroup:PREF_GROUP_APPEARANCE];
78         
79         //Other list options
80         [popUp_windowStyle setMenu:[self _windowStyleMenu]];
81         [popUp_windowStyle compatibleSelectItemWithTag:[[prefDict objectForKey:KEY_LIST_LAYOUT_WINDOW_STYLE] intValue]];        
82         [checkBox_verticalAutosizing setState:[[prefDict objectForKey:KEY_LIST_LAYOUT_VERTICAL_AUTOSIZE] boolValue]];
83         [checkBox_horizontalAutosizing setState:[[prefDict objectForKey:KEY_LIST_LAYOUT_HORIZONTAL_AUTOSIZE] boolValue]];
84         [slider_windowOpacity setFloatValue:([[prefDict objectForKey:KEY_LIST_LAYOUT_WINDOW_OPACITY] floatValue] * 100.0)];
85         [slider_horizontalWidth setIntValue:[[prefDict objectForKey:KEY_LIST_LAYOUT_HORIZONTAL_WIDTH] intValue]];
86         [self _updateSliderValues];
88         //Localized strings
89         [label_serviceIcons setLocalizedString:AILocalizedString(@"Service icons:","Label for preference to select the icon pack to used for service (AIM, MSN, etc.)")];
90         [label_statusIcons setLocalizedString:AILocalizedString(@"Status icons:","Label for preference to select status icon pack")];
91         [label_dockIcons setLocalizedString:AILocalizedString(@"Dock icons:","Label for preference to select dock icon")];
92                 
93         //Observe preference changes
94         [[adium preferenceController] registerPreferenceObserver:self forGroup:PREF_GROUP_EMOTICONS];
95         [[adium preferenceController] registerPreferenceObserver:self forGroup:PREF_GROUP_APPEARANCE];
97         //Observe xtras changes
98         [[adium notificationCenter] addObserver:self
99                                                                    selector:@selector(xtrasChanged:)
100                                                                            name:Adium_Xtras_Changed
101                                                                          object:nil];   
102         [self xtrasChanged:nil];
106  * @brief View will close
107  */
108 - (void)viewWillClose
110         [[adium preferenceController] unregisterPreferenceObserver:self];
111         
112         [[adium notificationCenter] removeObserver:self];
116  * @brief Xtras changed, update our menus to reflect the new Xtras
117  */
118 - (void)xtrasChanged:(NSNotification *)notification
120         NSString                *type = [[notification object] lowercaseString];
121         NSDictionary    *prefDict = [[adium preferenceController] preferencesForGroup:PREF_GROUP_APPEARANCE];
123         if(!type || [type isEqualToString:@"adiumemoticonset"]){
124                 [self _rebuildEmoticonMenuAndSelectActivePack];
125         }
126         
127         if(!type || [type isEqualToString:@"adiumicon"]){
128                 [popUp_dockIcon setMenu:[self _dockIconMenu]];
129                 [popUp_dockIcon selectItemWithTitle:[prefDict objectForKey:KEY_ACTIVE_DOCK_ICON]];
130         }
131         
132         if(!type || [type isEqualToString:@"adiumserviceicons"]){
133                 [popUp_serviceIcons setMenu:[self _serviceIconsMenu]];
134                 [popUp_serviceIcons selectItemWithTitle:[prefDict objectForKey:KEY_SERVICE_ICON_PACK]];
135         }
136         
137         if(!type || [type isEqualToString:@"adiumstatusicons"]){
138                 [popUp_statusIcons setMenu:[self _statusIconsMenu]];
139                 [popUp_statusIcons selectItemWithTitle:[prefDict objectForKey:KEY_STATUS_ICON_PACK]];           
140         }
141         
142         if(!type || [type isEqualToString:@"listtheme"]){
143                 [popUp_colorTheme setMenu:[self _colorThemeMenu]];
144                 [popUp_colorTheme selectItemWithRepresentedObject:[prefDict objectForKey:KEY_LIST_THEME_NAME]]; 
145         }
147         if(!type || [type isEqualToString:@"listlayout"]){
148                 [popUp_listLayout setMenu:[self _listLayoutMenu]];
149                 [popUp_listLayout selectItemWithRepresentedObject:[prefDict objectForKey:KEY_LIST_LAYOUT_NAME]];
150         }
154  * @brief Preferences changed
156  * Update controls in our view to reflect the changed preferences
157  */
158 - (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key object:(AIListObject *)object
159                                         preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
161         //Emoticons
162         if([group isEqualToString:PREF_GROUP_EMOTICONS]){
163                 [self _rebuildEmoticonMenuAndSelectActivePack];
164         }
165         
166         //Appearance
167         if([group isEqualToString:PREF_GROUP_APPEARANCE]){
168                 
169                 //Horizontal resizing label
170                 if(firstTime || 
171                    [key isEqualToString:KEY_LIST_LAYOUT_WINDOW_STYLE] ||
172                    [key isEqualToString:KEY_LIST_LAYOUT_HORIZONTAL_AUTOSIZE]){
173                         
174                         int windowMode = [[prefDict objectForKey:KEY_LIST_LAYOUT_WINDOW_STYLE] intValue];
175                         BOOL horizontalAutosize = [[prefDict objectForKey:KEY_LIST_LAYOUT_HORIZONTAL_AUTOSIZE] boolValue];
176                         
177                         if(windowMode == WINDOW_STYLE_STANDARD){
178                                 //In standard mode, disable the horizontal autosizing slider if horiztonal autosizing is off
179                                 [textField_horizontalWidthText setLocalizedString:AILocalizedString(@"Maximum width:",nil)];
180                                 [slider_horizontalWidth setEnabled:horizontalAutosize];
181                                 
182                         }else{
183                                 //In all the borderless transparent modes, the horizontal autosizing slider becomes the
184                                 //horizontal sizing slider when autosizing is off
185                                 if(horizontalAutosize){
186                                         [textField_horizontalWidthText setLocalizedString:AILocalizedString(@"Maximum width:",nil)];
187                                 }else{
188                                         [textField_horizontalWidthText setLocalizedString:AILocalizedString(@"Width:",nil)];                    
189                                 }
190                                 [slider_horizontalWidth setEnabled:YES];
191                         }
192                         
193                 }
195                 //Selected menu items
196                 if(firstTime || [key isEqualToString:KEY_STATUS_ICON_PACK]){
197                         [popUp_statusIcons selectItemWithTitle:[prefDict objectForKey:KEY_STATUS_ICON_PACK]];
198                         
199                         //If the prefDict's item isn't present, we're using the default, so select that one
200                         if(![popUp_serviceIcons selectedItem]){
201                                 [popUp_serviceIcons selectItemWithTitle:[[adium preferenceController] defaultPreferenceForKey:KEY_STATUS_ICON_PACK
202                                                                                                                                                                                                                 group:PREF_GROUP_APPEARANCE
203                                                                                                                                                                                                            object:nil]];
204                         }                       
205                 }
206                 if(firstTime || [key isEqualToString:KEY_SERVICE_ICON_PACK]){
207                         [popUp_serviceIcons selectItemWithTitle:[prefDict objectForKey:KEY_SERVICE_ICON_PACK]];
208                         
209                         //If the prefDict's item isn't present, we're using the default, so select that one
210                         if(![popUp_serviceIcons selectedItem]){
211                                 [popUp_serviceIcons selectItemWithTitle:[[adium preferenceController] defaultPreferenceForKey:KEY_SERVICE_ICON_PACK
212                                                                                                                                                                                                                 group:PREF_GROUP_APPEARANCE
213                                                                                                                                                                                                            object:nil]];
214                         }
215                 }               
216                 if(firstTime || [key isEqualToString:KEY_LIST_LAYOUT_NAME]){
217                         [popUp_listLayout selectItemWithRepresentedObject:[prefDict objectForKey:KEY_LIST_LAYOUT_NAME]];
218                 }
219                 if(firstTime || [key isEqualToString:KEY_LIST_THEME_NAME]){
220                         [popUp_colorTheme selectItemWithRepresentedObject:[prefDict objectForKey:KEY_LIST_THEME_NAME]]; 
221                 }       
222                 if(firstTime || [key isEqualToString:KEY_ACTIVE_DOCK_ICON]){
223                         [popUp_dockIcon selectItemWithTitle:[prefDict objectForKey:KEY_ACTIVE_DOCK_ICON]];
224                 }               
225         }
229  * @brief Rebuild the emoticon menu
230  */
231 - (void)_rebuildEmoticonMenuAndSelectActivePack
233         [popUp_emoticons setMenu:[self _emoticonPackMenu]];
234         
235         //Update the selected pack
236         NSArray *activeEmoticonPacks = [[adium emoticonController] activeEmoticonPacks];
237         int             numActivePacks = [activeEmoticonPacks count];
238         
239         if(numActivePacks == 0){
240                 [popUp_emoticons compatibleSelectItemWithTag:AIEmoticonMenuNone];
241         }else if(numActivePacks > 1){
242                 [popUp_emoticons compatibleSelectItemWithTag:AIEmoticonMenuMultiple];
243         }else{
244                 [popUp_emoticons selectItemWithRepresentedObject:[activeEmoticonPacks objectAtIndex:0]];
245         }
249  * @brief Save changed preferences
250  */
251 - (IBAction)changePreference:(id)sender
253         if(sender == popUp_statusIcons){
254         [[adium preferenceController] setPreference:[[sender selectedItem] title]
255                                              forKey:KEY_STATUS_ICON_PACK
256                                               group:PREF_GROUP_APPEARANCE];
257                 
258         }else if(sender == popUp_serviceIcons){
259         [[adium preferenceController] setPreference:[[sender selectedItem] title]
260                                              forKey:KEY_SERVICE_ICON_PACK
261                                               group:PREF_GROUP_APPEARANCE];
262                 
263         }else if(sender == popUp_dockIcon){
264         [[adium preferenceController] setPreference:[[sender selectedItem] title]
265                                              forKey:KEY_ACTIVE_DOCK_ICON
266                                               group:PREF_GROUP_APPEARANCE];
267                 
268         }else if(sender == popUp_listLayout){
269         [[adium preferenceController] setPreference:[[sender selectedItem] title]
270                                              forKey:KEY_LIST_LAYOUT_NAME
271                                               group:PREF_GROUP_APPEARANCE];
272                 
273         }else if(sender == popUp_colorTheme){
274                 [[adium preferenceController] setPreference:[[sender selectedItem] title]
275                                                                                          forKey:KEY_LIST_THEME_NAME
276                                                                                           group:PREF_GROUP_APPEARANCE];
278         }else if(sender == popUp_windowStyle){
279                 [[adium preferenceController] setPreference:[NSNumber numberWithInt:[[sender selectedItem] tag]]
280                                                                                          forKey:KEY_LIST_LAYOUT_WINDOW_STYLE
281                                                                                           group:PREF_GROUP_APPEARANCE];
282                 
283     }else if(sender == checkBox_verticalAutosizing){
284         [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
285                                              forKey:KEY_LIST_LAYOUT_VERTICAL_AUTOSIZE
286                                               group:PREF_GROUP_APPEARANCE];
287                 
288     }else if(sender == checkBox_horizontalAutosizing){
289         [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
290                                              forKey:KEY_LIST_LAYOUT_HORIZONTAL_AUTOSIZE
291                                               group:PREF_GROUP_APPEARANCE];
293     }else if(sender == slider_windowOpacity){
294         [[adium preferenceController] setPreference:[NSNumber numberWithFloat:([sender floatValue] / 100.0)]
295                                              forKey:KEY_LIST_LAYOUT_WINDOW_OPACITY
296                                               group:PREF_GROUP_APPEARANCE];
297                 [self _updateSliderValues];
298                 
299         }else if(sender == slider_horizontalWidth){
300                 int newValue = [sender intValue];
301                 int oldValue = [[[adium preferenceController] preferenceForKey:KEY_LIST_LAYOUT_HORIZONTAL_WIDTH
302                                                                                                                                  group:PREF_GROUP_APPEARANCE] intValue];
303                 if(newValue != oldValue){ 
304                         [[adium preferenceController] setPreference:[NSNumber numberWithInt:newValue]
305                                                                                                  forKey:KEY_LIST_LAYOUT_HORIZONTAL_WIDTH
306                                                                                                   group:PREF_GROUP_APPEARANCE];
307                         [self _updateSliderValues];
308                 }
309                 
310         } else if (sender == popUp_emoticons) {
311                 if ([[sender selectedItem] tag] != AIEmoticonMenuMultiple) {
312                         //Disable all active emoticons
313                         NSArray                 *activePacks = [[[[adium emoticonController] activeEmoticonPacks] mutableCopy] autorelease];
314                         NSEnumerator    *enumerator = [activePacks objectEnumerator];
315                         AIEmoticonPack  *pack, *selectedPack;
316                         
317                         selectedPack = [[sender selectedItem] representedObject];
318                         
319                         [[adium preferenceController] delayPreferenceChangedNotifications:YES];
321                         while(pack = [enumerator nextObject]){
322                                 [[adium emoticonController] setEmoticonPack:pack enabled:NO];
323                         }
324                         
325                         //Enable the selected pack
326                         if(selectedPack) [[adium emoticonController] setEmoticonPack:selectedPack enabled:YES];
328                         [[adium preferenceController] delayPreferenceChangedNotifications:NO];
329                 }
330         }
335  */
336 - (void)_updateSliderValues
338         [textField_windowOpacity setStringValue:[NSString stringWithFormat:@"%i%%", (int)[slider_windowOpacity floatValue]]];
339         [textField_horizontalWidthIndicator setStringValue:[NSString stringWithFormat:@"%ipx",[slider_horizontalWidth intValue]]];
343 //Emoticons ------------------------------------------------------------------------------------------------------------
344 #pragma mark Emoticons
347  */
348 - (IBAction)customizeEmoticons:(id)sender
350         [AIEmoticonPreferences showEmoticionCustomizationOnWindow:[[self view] window]];
355  */
356 - (NSMenu *)_emoticonPackMenu
358         NSMenu                  *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];
359         NSEnumerator    *enumerator = [[[adium emoticonController] availableEmoticonPacks] objectEnumerator];
360         AIEmoticonPack  *pack;
361         NSMenuItem              *menuItem;
362                 
363         //Add the "No Emoticons" option
364         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"None",nil)
365                                                                                                                                          target:nil
366                                                                                                                                          action:nil
367                                                                                                                           keyEquivalent:@""] autorelease];
368         [menuItem setImage:[NSImage imageNamed:@"emoticonBlank" forClass:[self class]]];
369         [menuItem setTag:AIEmoticonMenuNone];
370         [menu addItem:menuItem];
371         
372         //Add the "Multiple packs selected" option
373         if([[[adium emoticonController] activeEmoticonPacks] count] > 1){
374                 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Multiple Packs Selected",nil)
375                                                                                                                                                  target:nil
376                                                                                                                                                  action:nil
377                                                                                                                                   keyEquivalent:@""] autorelease];
378                 [menuItem setImage:[NSImage imageNamed:@"emoticonBlank" forClass:[self class]]];
379                 [menuItem setTag:AIEmoticonMenuMultiple];
380                 [menu addItem:menuItem];
381         }
383         //Divider
384         [menu addItem:[NSMenuItem separatorItem]];
385         
386         //Emoticon Packs
387         while(pack = [enumerator nextObject]){
388                 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[pack name]
389                                                                                                                                                  target:nil
390                                                                                                                                                  action:nil
391                                                                                                                                   keyEquivalent:@""] autorelease];
392                 [menuItem setRepresentedObject:pack];
393                 [menuItem setImage:[[[[pack emoticons] objectAtIndex:0] image] imageByScalingToSize:NSMakeSize(16,16)]];
394                 [menu addItem:menuItem];
395         }
396         
397         
398         return([menu autorelease]);
402 //Contact list options -------------------------------------------------------------------------------------------------
403 #pragma mark Contact list options
406  */
407 - (NSMenu *)_windowStyleMenu
409         NSMenu  *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];
411         [self _addWindowStyleOption:AILocalizedString(@"Regular Window",nil)
412                                                 withTag:WINDOW_STYLE_STANDARD
413                                                  toMenu:menu];
414         [menu addItem:[NSMenuItem separatorItem]];
415         [self _addWindowStyleOption:AILocalizedString(@"Borderless Window",nil)
416                                                 withTag:WINDOW_STYLE_BORDERLESS
417                                                  toMenu:menu];
418         [self _addWindowStyleOption:AILocalizedString(@"Group Bubbles",nil)
419                                                 withTag:WINDOW_STYLE_MOCKIE
420                                                  toMenu:menu];
421         [self _addWindowStyleOption:AILocalizedString(@"Contact Bubbles",nil)
422                                                 withTag:WINDOW_STYLE_PILLOWS
423                                                  toMenu:menu];
424         [self _addWindowStyleOption:AILocalizedString(@"Contact Bubbles (To Fit)",nil)
425                                                 withTag:WINDOW_STYLE_PILLOWS_FITTED
426                                                  toMenu:menu];
428         return([menu autorelease]);
430 - (void)_addWindowStyleOption:(NSString *)option withTag:(int)tag toMenu:(NSMenu *)menu{
431     NSMenuItem  *menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:option
432                                                                                                                                                                   target:nil
433                                                                                                                                                                   action:nil
434                                                                                                                                                    keyEquivalent:@""] autorelease];
435         [menuItem setTag:tag];
436         [menu addItem:menuItem];
440 //Contact list layout & theme ----------------------------------------------------------------------------------------
441 #pragma mark Contact list layout & theme
443  * @brief Create a new theme
444  */
445 - (IBAction)createListTheme:(id)sender
447         NSString *theme = [[adium preferenceController] preferenceForKey:KEY_LIST_THEME_NAME group:PREF_GROUP_APPEARANCE];      
448         
449         [ESPresetNameSheetController showPresetNameSheetWithDefaultName:[theme stringByAppendingString:@" Copy"]
450                                                                                                         explanatoryText:AILocalizedString(@"Enter a unique name for this new theme.",nil)
451                                                                                                                    onWindow:[[self view] window]
452                                                                                                         notifyingTarget:self
453                                                                                                                    userInfo:@"theme"];
457  * @brief Customize the active theme
458  */
459 - (IBAction)customizeListTheme:(id)sender
461         NSString *theme = [[adium preferenceController] preferenceForKey:KEY_LIST_THEME_NAME group:PREF_GROUP_APPEARANCE];      
462         
463         //Allow alpha in our color pickers
464         [[NSColorPanel sharedColorPanel] setShowsAlpha:YES];    
466         [AIListThemeWindowController editListThemeWithName:theme
467                                                                                           onWindow:[[self view] window]
468                                                                            notifyingTarget:self];
472  * @brief Save (or revert) changes made when editing a theme
473  */
474 - (void)listThemeEditorWillCloseWithChanges:(BOOL)saveChanges forThemeNamed:(NSString *)name
476         if(saveChanges){
477                 //Update the modified theme
478                 if([AISCLViewPlugin createSetFromPreferenceGroup:PREF_GROUP_LIST_THEME
479                                                                                                 withName:name
480                                                                                            extension:LIST_THEME_EXTENSION
481                                                                                                 inFolder:LIST_THEME_FOLDER]){
482                 
483                         [[adium preferenceController] setPreference:name
484                                                                                                  forKey:KEY_LIST_THEME_NAME
485                                                                                                   group:PREF_GROUP_APPEARANCE];
486                 }
487                 
488         }else{
489                 //Revert back to selected theme
490                 NSString *theme = [[adium preferenceController] preferenceForKey:KEY_LIST_THEME_NAME group:PREF_GROUP_APPEARANCE];      
492                 [AISCLViewPlugin applySetWithName:theme
493                                                                 extension:LIST_THEME_EXTENSION
494                                                                  inFolder:LIST_THEME_FOLDER
495                                                 toPreferenceGroup:PREF_GROUP_LIST_THEME];
496         }
497         
498         //No longer allow alpha in our color pickers
499         [[NSColorPanel sharedColorPanel] setShowsAlpha:NO];
503  * @brief Manage available themes
504  */
505 - (void)manageListThemes:(id)sender
507         _listThemes = [AISCLViewPlugin availableThemeSets];
508         [ESPresetManagementController managePresets:_listThemes
509                                                                          namedByKey:@"name"
510                                                                            onWindow:[[self view] window]
511                                                                    withDelegate:self];
512         
513         [popUp_colorTheme selectItemWithRepresentedObject:[[adium preferenceController] preferenceForKey:KEY_LIST_THEME_NAME
514                                                                                                                                                                                            group:PREF_GROUP_APPEARANCE]];               
518  * @brief Create a new layout
519  */
520 - (IBAction)createListLayout:(id)sender
522         NSString *layout = [[adium preferenceController] preferenceForKey:KEY_LIST_LAYOUT_NAME group:PREF_GROUP_APPEARANCE];
523         
524         [ESPresetNameSheetController showPresetNameSheetWithDefaultName:[layout stringByAppendingString:@" Copy"]
525                                                                                                         explanatoryText:AILocalizedString(@"Enter a unique name for this new layout.",nil)
526                                                                                                                    onWindow:[[self view] window]
527                                                                                                         notifyingTarget:self
528                                                                                                                    userInfo:@"layout"];
532  * @brief Customize the active layout
533  */
534 - (IBAction)customizeListLayout:(id)sender
536         NSString *theme = [[adium preferenceController] preferenceForKey:KEY_LIST_LAYOUT_NAME group:PREF_GROUP_APPEARANCE];     
537         
538         //Allow alpha in our color pickers
539         [[NSColorPanel sharedColorPanel] setShowsAlpha:YES];    
541         [AIListLayoutWindowController editListLayoutWithName:theme
542                                                                                           onWindow:[[self view] window]
543                                                                            notifyingTarget:self];
547  * @brief Save (or revert) changes made when editing a layout
548  */
549 - (void)listLayoutEditorWillCloseWithChanges:(BOOL)saveChanges forLayoutNamed:(NSString *)name
551         if(saveChanges){
552                 //Update the modified layout
553                 if([AISCLViewPlugin createSetFromPreferenceGroup:PREF_GROUP_LIST_LAYOUT
554                                                                                                 withName:name
555                                                                                            extension:LIST_LAYOUT_EXTENSION
556                                                                                                 inFolder:LIST_LAYOUT_FOLDER]){
557                         
558                         [[adium preferenceController] setPreference:name
559                                                                                                  forKey:KEY_LIST_LAYOUT_NAME
560                                                                                                   group:PREF_GROUP_APPEARANCE];
561                 }
562                 
563         }else{
564                 //Revert back to selected layout
565                 NSString *layout = [[adium preferenceController] preferenceForKey:KEY_LIST_LAYOUT_NAME group:PREF_GROUP_APPEARANCE];    
566                 
567                 [AISCLViewPlugin applySetWithName:layout
568                                                                 extension:LIST_LAYOUT_EXTENSION
569                                                                  inFolder:LIST_LAYOUT_FOLDER
570                                                 toPreferenceGroup:PREF_GROUP_LIST_LAYOUT];
571         }
572         
573         //No longer allow alpha in our color pickers
574         [[NSColorPanel sharedColorPanel] setShowsAlpha:NO];
578  * @brief Manage available layouts
579  */
580 - (void)manageListLayouts:(id)sender
582         _listLayouts = [AISCLViewPlugin availableLayoutSets];
583         [ESPresetManagementController managePresets:_listLayouts
584                                                                          namedByKey:@"name"
585                                                                            onWindow:[[self view] window]
586                                                                    withDelegate:self];
588         [popUp_listLayout selectItemWithRepresentedObject:[[adium preferenceController] preferenceForKey:KEY_LIST_LAYOUT_NAME
589                                                                                                                                                                                            group:PREF_GROUP_APPEARANCE]];               
593  * @brief Validate a layout or theme name to ensure it is unique
594  */
595 - (BOOL)presetNameSheetController:(ESPresetNameSheetController *)controller
596                           shouldAcceptNewName:(NSString *)newName
597                                                  userInfo:(id)userInfo
599         NSEnumerator    *enumerator;
600         NSDictionary    *presetDict;
602         //Scan the correct presets to ensure this name doesn't already exist
603         if([userInfo isEqualToString:@"theme"]){
604                 enumerator = [[AISCLViewPlugin availableThemeSets] objectEnumerator];
605         }else{
606                 enumerator = [[AISCLViewPlugin availableLayoutSets] objectEnumerator];
607         }
608         
609         while(presetDict = [enumerator nextObject]){
610                 if([newName isEqualToString:[presetDict objectForKey:@"name"]]) return(NO);
611         }
612         
613         return(YES);
617  * @brief Create a new theme with the user supplied name, activate and edit it
618  */
619 - (void)presetNameSheetControllerDidEnd:(ESPresetNameSheetController *)controller 
620                                                          returnCode:(ESPresetNameSheetReturnCode)returnCode
621                                                                 newName:(NSString *)newName
622                                                            userInfo:(id)userInfo
624         switch(returnCode){
625                 case ESPresetNameSheetOkayReturn:
626                         if([userInfo isEqualToString:@"theme"]){
627                                 [self performSelector:@selector(_editListThemeWithName:) withObject:newName afterDelay:0.00001];
628                         }else{
629                                 [self performSelector:@selector(_editListLayoutWithName:) withObject:newName afterDelay:0.00001];
630                         }
631                 break;
632                         
633                 case ESPresetNameSheetCancelReturn:
634                         //Do nothing
635                 break;
636         }
638 - (void)_editListThemeWithName:(NSString *)name{
639         [AIListThemeWindowController editListThemeWithName:name
640                                                                                           onWindow:[[self view] window]
641                                                                            notifyingTarget:self];
643 - (void)_editListLayoutWithName:(NSString *)name{
644         [AIListLayoutWindowController editListLayoutWithName:name
645                                                                                                 onWindow:[[self view] window]
646                                                                                  notifyingTarget:self];
650  * 
651  */
652 - (NSArray *)renamePreset:(NSDictionary *)preset toName:(NSString *)newName inPresets:(NSArray *)presets renamedPreset:(id *)renamedPreset
654         NSArray         *newPresets;
656         if(presets == _listLayouts){
657                 [AISCLViewPlugin renameSetWithName:[preset objectForKey:@"name"]
658                                                                  extension:LIST_LAYOUT_EXTENSION
659                                                                   inFolder:LIST_LAYOUT_FOLDER
660                                                                         toName:newName];                
661                 _listLayouts = [AISCLViewPlugin availableLayoutSets];
662                 newPresets = _listLayouts;
663                 
664         }else if(presets == _listThemes){
665                 [AISCLViewPlugin renameSetWithName:[preset objectForKey:@"name"]
666                                                                  extension:LIST_THEME_EXTENSION
667                                                                   inFolder:LIST_THEME_FOLDER
668                                                                         toName:newName];                
669                 _listThemes = [AISCLViewPlugin availableThemeSets];
670                 newPresets = _listThemes;
672         }else{
673                 newPresets = nil;
674         }
675         
676         //Return the new duplicate by reference for the preset controller
677         if(renamedPreset){
678                 NSEnumerator    *enumerator = [newPresets objectEnumerator];
679                 NSDictionary    *aPreset;
680                 
681                 while(aPreset = [enumerator nextObject]){
682                         if([newName isEqualToString:[aPreset objectForKey:@"name"]]){
683                                 *renamedPreset = aPreset;
684                                 break;
685                         }
686                 }
687         }
688         
689         return newPresets;
693  * 
694  */
695 - (NSArray *)duplicatePreset:(NSDictionary *)preset inPresets:(NSArray *)presets createdDuplicate:(id *)duplicatePreset
697         NSString        *newName = [NSString stringWithFormat:@"%@ (%@)", [preset objectForKey:@"name"], AILocalizedString(@"Copy",nil)];
698         NSArray         *newPresets = nil;
699         
700         if(presets == _listLayouts){
701                 [AISCLViewPlugin duplicateSetWithName:[preset objectForKey:@"name"]
702                                                                         extension:LIST_LAYOUT_EXTENSION
703                                                                          inFolder:LIST_LAYOUT_FOLDER
704                                                                           newName:newName];             
705                 _listLayouts = [AISCLViewPlugin availableLayoutSets];
706                 newPresets = _listLayouts;
707                 
708         }else if(presets == _listThemes){
709                 [AISCLViewPlugin duplicateSetWithName:[preset objectForKey:@"name"]
710                                                                         extension:LIST_THEME_EXTENSION
711                                                                          inFolder:LIST_THEME_FOLDER
712                                                                           newName:newName];
713                 _listThemes = [AISCLViewPlugin availableThemeSets];
714                 newPresets = _listThemes;
715         }
717         //Return the new duplicate by reference for the preset controller
718         if(duplicatePreset){
719                 NSEnumerator    *enumerator = [newPresets objectEnumerator];
720                 NSDictionary    *aPreset;
721                 
722                 while(aPreset = [enumerator nextObject]){
723                         if([newName isEqualToString:[aPreset objectForKey:@"name"]]){
724                                 *duplicatePreset = aPreset;
725                                 break;
726                         }
727                 }
728         }
730         return newPresets;
734  * 
735  */
736 - (NSArray *)deletePreset:(NSDictionary *)preset inPresets:(NSArray *)presets
738         if(presets == _listLayouts){
739                 [AISCLViewPlugin deleteSetWithName:[preset objectForKey:@"name"]
740                                                                  extension:LIST_LAYOUT_EXTENSION
741                                                                   inFolder:LIST_LAYOUT_FOLDER];         
742                 _listLayouts = [AISCLViewPlugin availableLayoutSets];
743                 
744                 return(_listLayouts);
745         
746         }else if(presets == _listThemes){
747                 [AISCLViewPlugin deleteSetWithName:[preset objectForKey:@"name"]
748                                                                  extension:LIST_THEME_EXTENSION
749                                                                   inFolder:LIST_THEME_FOLDER];          
750                 _listThemes = [AISCLViewPlugin availableThemeSets];
751                 
752                 return(_listThemes);
754         }else{
755                 return(nil);
756         }
761  */
762 - (NSMenu *)_listLayoutMenu
764         NSMenu                  *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];
765         NSEnumerator    *enumerator = [[AISCLViewPlugin availableLayoutSets] objectEnumerator];
766         NSDictionary    *set;
767         NSMenuItem              *menuItem;
768         NSString                *name;
769         
770         //Available Layouts
771         while(set = [enumerator nextObject]){
772                 name = [set objectForKey:@"name"];
773                 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:name
774                                                                                                                                                  target:nil
775                                                                                                                                                  action:nil
776                                                                                                                                   keyEquivalent:@""] autorelease];
777                 [menuItem setRepresentedObject:name];
778                 [menu addItem:menuItem];
779         }
780         
781         //Divider
782         [menu addItem:[NSMenuItem separatorItem]];
784         //Preset management     
785         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Add New Layout...",nil)
786                                                                                                                                          target:self
787                                                                                                                                          action:@selector(createListLayout:)
788                                                                                                                           keyEquivalent:@""] autorelease];
789         [menu addItem:menuItem];
790         
791         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Edit Layouts...",nil)
792                                                                                                                                          target:self
793                                                                                                                                          action:@selector(manageListLayouts:)
794                                                                                                                           keyEquivalent:@""] autorelease];
795         [menu addItem:menuItem];
796         
797         return(menu);   
802  */
803 - (NSMenu *)_colorThemeMenu
805         NSMenu                  *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];
806         NSEnumerator    *enumerator = [[AISCLViewPlugin availableThemeSets] objectEnumerator];
807         NSDictionary    *set;
808         NSMenuItem              *menuItem;
809         NSString                *name;
810         
811         //Available themes
812         while(set = [enumerator nextObject]){
813                 name = [set objectForKey:@"name"];
814                 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:name
815                                                                                                                                                  target:nil
816                                                                                                                                                  action:nil
817                                                                                                                                   keyEquivalent:@""] autorelease];
818                 [menuItem setRepresentedObject:name];
819                 [menu addItem:menuItem];
820         }
822         //Divider
823         [menu addItem:[NSMenuItem separatorItem]];
824         
825         //Preset management     
826         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Add New Theme...",nil)
827                                                                                                                                          target:self
828                                                                                                                                          action:@selector(createListTheme:)
829                                                                                                                           keyEquivalent:@""] autorelease];
830         [menu addItem:menuItem];
831         
832         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Edit Themes...",nil)
833                                                                                                                                          target:self
834                                                                                                                                          action:@selector(manageListThemes:)
835                                                                                                                           keyEquivalent:@""] autorelease];
836         [menu addItem:menuItem];
837         
838         return(menu);   
842 //Dock icons -----------------------------------------------------------------------------------------------------------
843 #pragma mark Dock icons
846  */
847 - (IBAction)showAllDockIcons:(id)sender
849         [AIDockIconSelectionSheet showDockIconSelectorOnWindow:[[self view] window]];
853  * @brief Returns a menu of dock icon packs
854  */
855 - (NSMenu *)_dockIconMenu
857         NSMenu                  *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];
858         NSEnumerator    *enumerator = [[[adium dockController] availableDockIconPacks] objectEnumerator];
859         NSString                *packPath;
860         
861         while(packPath = [enumerator nextObject]){
862                 NSString        *name = [[packPath lastPathComponent] stringByDeletingPathExtension];
863                 AIIconState     *preview = [[adium dockController] previewStateForIconPackAtPath:packPath];
864                 
865                 NSMenuItem      *menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:name
866                                                                                                                                                                           target:nil
867                                                                                                                                                                           action:nil
868                                                                                                                                                            keyEquivalent:@""] autorelease];
869                 [menuItem setRepresentedObject:name];
870                 [menuItem setImage:[[preview image] imageByScalingToSize:NSMakeSize(18,18)]];
871                 [menu addItem:menuItem];
872         }
873         
874         return(menu);   
878 //Status and Service icons ---------------------------------------------------------------------------------------------
879 #pragma mark Status and service icons
881  * @brief Returns a menu of status icon packs
882  */
883 - (NSMenu *)_statusIconsMenu
885         return([self _iconPackMenuForPacks:[adium allResourcesForName:@"Status Icons" withExtensions:@"AdiumStatusIcons"] class:[AIStatusIcons class]]);
889  * @brief Returns a menu of service icon packs
890  */
891 - (NSMenu *)_serviceIconsMenu
893         return([self _iconPackMenuForPacks:[adium allResourcesForName:@"Service Icons" withExtensions:@"AdiumServiceIcons"] class:[AIServiceIcons class]]);
897  * @brief Builds and returns an icon pack menu
899  * @param packs NSArray of icon pack file paths
900  * @param iconClass The controller class (AIStatusIcons, AIServiceIcons) for icon pack previews
901  */
902 - (NSMenu *)_iconPackMenuForPacks:(NSArray *)packs class:(Class)iconClass
904         NSMenu                  *serviceIconsMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];
905         NSEnumerator    *enumerator = [packs objectEnumerator];
906         NSString                *packPath;
908         while(packPath = [enumerator nextObject]){
909                 NSString        *name = [[packPath lastPathComponent] stringByDeletingPathExtension];
910                 NSMenuItem      *menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:name
911                                                                                                                                                                           target:nil
912                                                                                                                                                                           action:nil
913                                                                                                                                                            keyEquivalent:@""] autorelease];
914                 [menuItem setRepresentedObject:name];
915                 [menuItem setImage:[iconClass previewMenuImageForIconPackAtPath:packPath]];
916                 [serviceIconsMenu addItem:menuItem];
917         }
918         
919         return(serviceIconsMenu);       
922 @end