Using {{{setDefaultPermitDenyForAccount}}} on the gaim thread. Changed an autoreleas...
[adiumx.git] / Source / AIAppearancePreferences.m
blob8aaaa65411cf469f17ca87e00086702046d65793
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 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         [AIListThemeWindowController editListThemeWithName:theme
464                                                                                           onWindow:[[self view] window]
465                                                                            notifyingTarget:self];
469  * @brief Save (or revert) changes made when editing a theme
470  */
471 - (void)listThemeEditorWillCloseWithChanges:(BOOL)saveChanges forThemeNamed:(NSString *)name
473         if(saveChanges){
474                 //Update the modified theme
475                 if([AISCLViewPlugin createSetFromPreferenceGroup:PREF_GROUP_LIST_THEME
476                                                                                                 withName:name
477                                                                                            extension:LIST_THEME_EXTENSION
478                                                                                                 inFolder:LIST_THEME_FOLDER]){
479                 
480                         [[adium preferenceController] setPreference:name
481                                                                                                  forKey:KEY_LIST_THEME_NAME
482                                                                                                   group:PREF_GROUP_APPEARANCE];
483                 }
484                 
485         }else{
486                 //Revert back to selected theme
487                 NSString *theme = [[adium preferenceController] preferenceForKey:KEY_LIST_THEME_NAME group:PREF_GROUP_APPEARANCE];      
489                 [AISCLViewPlugin applySetWithName:theme
490                                                                 extension:LIST_THEME_EXTENSION
491                                                                  inFolder:LIST_THEME_FOLDER
492                                                 toPreferenceGroup:PREF_GROUP_LIST_THEME];
493         }
497  * @brief Manage available themes
498  */
499 - (void)manageListThemes:(id)sender
501         _listThemes = [AISCLViewPlugin availableThemeSets];
502         [ESPresetManagementController managePresets:_listThemes
503                                                                          namedByKey:@"name"
504                                                                            onWindow:[[self view] window]
505                                                                    withDelegate:self];
506         
507         [popUp_colorTheme selectItemWithRepresentedObject:[[adium preferenceController] preferenceForKey:KEY_LIST_THEME_NAME
508                                                                                                                                                                                            group:PREF_GROUP_APPEARANCE]];               
512  * @brief Create a new layout
513  */
514 - (IBAction)createListLayout:(id)sender
516         NSString *layout = [[adium preferenceController] preferenceForKey:KEY_LIST_LAYOUT_NAME group:PREF_GROUP_APPEARANCE];
517         
518         [ESPresetNameSheetController showPresetNameSheetWithDefaultName:[layout stringByAppendingString:@" Copy"]
519                                                                                                         explanatoryText:AILocalizedString(@"Enter a unique name for this new layout.",nil)
520                                                                                                                    onWindow:[[self view] window]
521                                                                                                         notifyingTarget:self
522                                                                                                                    userInfo:@"layout"];
526  * @brief Customize the active layout
527  */
528 - (IBAction)customizeListLayout:(id)sender
530         NSString *theme = [[adium preferenceController] preferenceForKey:KEY_LIST_LAYOUT_NAME group:PREF_GROUP_APPEARANCE];     
531         
532         [AIListLayoutWindowController editListLayoutWithName:theme
533                                                                                           onWindow:[[self view] window]
534                                                                            notifyingTarget:self];
538  * @brief Save (or revert) changes made when editing a layout
539  */
540 - (void)listLayoutEditorWillCloseWithChanges:(BOOL)saveChanges forLayoutNamed:(NSString *)name
542         if(saveChanges){
543                 //Update the modified layout
544                 if([AISCLViewPlugin createSetFromPreferenceGroup:PREF_GROUP_LIST_LAYOUT
545                                                                                                 withName:name
546                                                                                            extension:LIST_LAYOUT_EXTENSION
547                                                                                                 inFolder:LIST_LAYOUT_FOLDER]){
548                         
549                         [[adium preferenceController] setPreference:name
550                                                                                                  forKey:KEY_LIST_LAYOUT_NAME
551                                                                                                   group:PREF_GROUP_APPEARANCE];
552                 }
553                 
554         }else{
555                 //Revert back to selected layout
556                 NSString *layout = [[adium preferenceController] preferenceForKey:KEY_LIST_LAYOUT_NAME group:PREF_GROUP_APPEARANCE];    
557                 
558                 [AISCLViewPlugin applySetWithName:layout
559                                                                 extension:LIST_LAYOUT_EXTENSION
560                                                                  inFolder:LIST_LAYOUT_FOLDER
561                                                 toPreferenceGroup:PREF_GROUP_LIST_LAYOUT];
562         }
566  * @brief Manage available layouts
567  */
568 - (void)manageListLayouts:(id)sender
570         _listLayouts = [AISCLViewPlugin availableLayoutSets];
571         [ESPresetManagementController managePresets:_listLayouts
572                                                                          namedByKey:@"name"
573                                                                            onWindow:[[self view] window]
574                                                                    withDelegate:self];
576         [popUp_listLayout selectItemWithRepresentedObject:[[adium preferenceController] preferenceForKey:KEY_LIST_LAYOUT_NAME
577                                                                                                                                                                                            group:PREF_GROUP_APPEARANCE]];               
581  * @brief Validate a layout or theme name to ensure it is unique
582  */
583 - (BOOL)presetNameSheetController:(ESPresetNameSheetController *)controller
584                           shouldAcceptNewName:(NSString *)newName
585                                                  userInfo:(id)userInfo
587         NSEnumerator    *enumerator;
588         NSDictionary    *presetDict;
590         //Scan the correct presets to ensure this name doesn't already exist
591         if([userInfo isEqualToString:@"theme"]){
592                 enumerator = [[AISCLViewPlugin availableThemeSets] objectEnumerator];
593         }else{
594                 enumerator = [[AISCLViewPlugin availableLayoutSets] objectEnumerator];
595         }
596         
597         while(presetDict = [enumerator nextObject]){
598                 if([newName isEqualToString:[presetDict objectForKey:@"name"]]) return(NO);
599         }
600         
601         return(YES);
605  * @brief Create a new theme with the user supplied name, activate and edit it
606  */
607 - (void)presetNameSheetControllerDidEnd:(ESPresetNameSheetController *)controller 
608                                                          returnCode:(ESPresetNameSheetReturnCode)returnCode
609                                                                 newName:(NSString *)newName
610                                                            userInfo:(id)userInfo
612         switch(returnCode){
613                 case ESPresetNameSheetOkayReturn:
614                         if([userInfo isEqualToString:@"theme"]){
615                                 [self performSelector:@selector(_editListThemeWithName:) withObject:newName afterDelay:0.00001];
616                         }else{
617                                 [self performSelector:@selector(_editListLayoutWithName:) withObject:newName afterDelay:0.00001];
618                         }
619                 break;
620                         
621                 case ESPresetNameSheetCancelReturn:
622                         //Do nothing
623                 break;
624         }
626 - (void)_editListThemeWithName:(NSString *)name{
627         [AIListThemeWindowController editListThemeWithName:name
628                                                                                           onWindow:[[self view] window]
629                                                                            notifyingTarget:self];
631 - (void)_editListLayoutWithName:(NSString *)name{
632         [AIListLayoutWindowController editListLayoutWithName:name
633                                                                                                 onWindow:[[self view] window]
634                                                                                  notifyingTarget:self];
638  * 
639  */
640 - (NSArray *)renamePreset:(NSDictionary *)preset toName:(NSString *)newName inPresets:(NSArray *)presets renamedPreset:(id *)renamedPreset
642         NSArray         *newPresets;
644         if(presets == _listLayouts){
645                 [AISCLViewPlugin renameSetWithName:[preset objectForKey:@"name"]
646                                                                  extension:LIST_LAYOUT_EXTENSION
647                                                                   inFolder:LIST_LAYOUT_FOLDER
648                                                                         toName:newName];                
649                 _listLayouts = [AISCLViewPlugin availableLayoutSets];
650                 newPresets = _listLayouts;
651                 
652         }else if(presets == _listThemes){
653                 [AISCLViewPlugin renameSetWithName:[preset objectForKey:@"name"]
654                                                                  extension:LIST_THEME_EXTENSION
655                                                                   inFolder:LIST_THEME_FOLDER
656                                                                         toName:newName];                
657                 _listThemes = [AISCLViewPlugin availableThemeSets];
658                 newPresets = _listThemes;
660         }else{
661                 newPresets = nil;
662         }
663         
664         //Return the new duplicate by reference for the preset controller
665         if(renamedPreset){
666                 NSEnumerator    *enumerator = [newPresets objectEnumerator];
667                 NSDictionary    *aPreset;
668                 
669                 while(aPreset = [enumerator nextObject]){
670                         if([newName isEqualToString:[aPreset objectForKey:@"name"]]){
671                                 *renamedPreset = aPreset;
672                                 break;
673                         }
674                 }
675         }
676         
677         return newPresets;
681  * 
682  */
683 - (NSArray *)duplicatePreset:(NSDictionary *)preset inPresets:(NSArray *)presets createdDuplicate:(id *)duplicatePreset
685         NSString        *newName = [NSString stringWithFormat:@"%@ (%@)", [preset objectForKey:@"name"], AILocalizedString(@"Copy",nil)];
686         NSArray         *newPresets = nil;
687         
688         if(presets == _listLayouts){
689                 [AISCLViewPlugin duplicateSetWithName:[preset objectForKey:@"name"]
690                                                                         extension:LIST_LAYOUT_EXTENSION
691                                                                          inFolder:LIST_LAYOUT_FOLDER
692                                                                           newName:newName];             
693                 _listLayouts = [AISCLViewPlugin availableLayoutSets];
694                 newPresets = _listLayouts;
695                 
696         }else if(presets == _listThemes){
697                 [AISCLViewPlugin duplicateSetWithName:[preset objectForKey:@"name"]
698                                                                         extension:LIST_THEME_EXTENSION
699                                                                          inFolder:LIST_THEME_FOLDER
700                                                                           newName:newName];
701                 _listThemes = [AISCLViewPlugin availableThemeSets];
702                 newPresets = _listThemes;
703         }
705         //Return the new duplicate by reference for the preset controller
706         if(duplicatePreset){
707                 NSEnumerator    *enumerator = [newPresets objectEnumerator];
708                 NSDictionary    *aPreset;
709                 
710                 while(aPreset = [enumerator nextObject]){
711                         if([newName isEqualToString:[aPreset objectForKey:@"name"]]){
712                                 *duplicatePreset = aPreset;
713                                 break;
714                         }
715                 }
716         }
718         return newPresets;
722  * 
723  */
724 - (NSArray *)deletePreset:(NSDictionary *)preset inPresets:(NSArray *)presets
726         if(presets == _listLayouts){
727                 [AISCLViewPlugin deleteSetWithName:[preset objectForKey:@"name"]
728                                                                  extension:LIST_LAYOUT_EXTENSION
729                                                                   inFolder:LIST_LAYOUT_FOLDER];         
730                 _listLayouts = [AISCLViewPlugin availableLayoutSets];
731                 
732                 return(_listLayouts);
733         
734         }else if(presets == _listThemes){
735                 [AISCLViewPlugin deleteSetWithName:[preset objectForKey:@"name"]
736                                                                  extension:LIST_THEME_EXTENSION
737                                                                   inFolder:LIST_THEME_FOLDER];          
738                 _listThemes = [AISCLViewPlugin availableThemeSets];
739                 
740                 return(_listThemes);
742         }else{
743                 return(nil);
744         }
749  */
750 - (NSMenu *)_listLayoutMenu
752         NSMenu                  *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];
753         NSEnumerator    *enumerator = [[AISCLViewPlugin availableLayoutSets] objectEnumerator];
754         NSDictionary    *set;
755         NSMenuItem              *menuItem;
756         NSString                *name;
757         
758         //Available Layouts
759         while(set = [enumerator nextObject]){
760                 name = [set objectForKey:@"name"];
761                 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:name
762                                                                                                                                                  target:nil
763                                                                                                                                                  action:nil
764                                                                                                                                   keyEquivalent:@""] autorelease];
765                 [menuItem setRepresentedObject:name];
766                 [menu addItem:menuItem];
767         }
768         
769         //Divider
770         [menu addItem:[NSMenuItem separatorItem]];
772         //Preset management     
773         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Add New Layout...",nil)
774                                                                                                                                          target:self
775                                                                                                                                          action:@selector(createListLayout:)
776                                                                                                                           keyEquivalent:@""] autorelease];
777         [menu addItem:menuItem];
778         
779         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Edit Layouts...",nil)
780                                                                                                                                          target:self
781                                                                                                                                          action:@selector(manageListLayouts:)
782                                                                                                                           keyEquivalent:@""] autorelease];
783         [menu addItem:menuItem];
784         
785         return(menu);   
790  */
791 - (NSMenu *)_colorThemeMenu
793         NSMenu                  *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];
794         NSEnumerator    *enumerator = [[AISCLViewPlugin availableThemeSets] objectEnumerator];
795         NSDictionary    *set;
796         NSMenuItem              *menuItem;
797         NSString                *name;
798         
799         //Available themes
800         while(set = [enumerator nextObject]){
801                 name = [set objectForKey:@"name"];
802                 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:name
803                                                                                                                                                  target:nil
804                                                                                                                                                  action:nil
805                                                                                                                                   keyEquivalent:@""] autorelease];
806                 [menuItem setRepresentedObject:name];
807                 [menu addItem:menuItem];
808         }
810         //Divider
811         [menu addItem:[NSMenuItem separatorItem]];
812         
813         //Preset management     
814         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Add New Theme...",nil)
815                                                                                                                                          target:self
816                                                                                                                                          action:@selector(createListTheme:)
817                                                                                                                           keyEquivalent:@""] autorelease];
818         [menu addItem:menuItem];
819         
820         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Edit Themes...",nil)
821                                                                                                                                          target:self
822                                                                                                                                          action:@selector(manageListThemes:)
823                                                                                                                           keyEquivalent:@""] autorelease];
824         [menu addItem:menuItem];
825         
826         return(menu);   
830 //Dock icons -----------------------------------------------------------------------------------------------------------
831 #pragma mark Dock icons
834  */
835 - (IBAction)showAllDockIcons:(id)sender
837         [AIDockIconSelectionSheet showDockIconSelectorOnWindow:[[self view] window]];
841  * @brief Returns a menu of dock icon packs
842  */
843 - (NSMenu *)_dockIconMenu
845         NSMenu                  *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];
846         NSEnumerator    *enumerator = [[[adium dockController] availableDockIconPacks] objectEnumerator];
847         NSString                *packPath;
848         
849         while(packPath = [enumerator nextObject]){
850                 NSString        *name = [[packPath lastPathComponent] stringByDeletingPathExtension];
851                 AIIconState     *preview = [[adium dockController] previewStateForIconPackAtPath:packPath];
852                 
853                 NSMenuItem      *menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:name
854                                                                                                                                                                           target:nil
855                                                                                                                                                                           action:nil
856                                                                                                                                                            keyEquivalent:@""] autorelease];
857                 [menuItem setRepresentedObject:name];
858                 [menuItem setImage:[[preview image] imageByScalingToSize:NSMakeSize(18,18)]];
859                 [menu addItem:menuItem];
860         }
861         
862         return(menu);   
866 //Status and Service icons ---------------------------------------------------------------------------------------------
867 #pragma mark Status and service icons
869  * @brief Returns a menu of status icon packs
870  */
871 - (NSMenu *)_statusIconsMenu
873         return([self _iconPackMenuForPacks:[adium allResourcesForName:@"Status Icons" withExtensions:@"AdiumStatusIcons"] class:[AIStatusIcons class]]);
877  * @brief Returns a menu of service icon packs
878  */
879 - (NSMenu *)_serviceIconsMenu
881         return([self _iconPackMenuForPacks:[adium allResourcesForName:@"Service Icons" withExtensions:@"AdiumServiceIcons"] class:[AIServiceIcons class]]);
885  * @brief Builds and returns an icon pack menu
887  * @param packs NSArray of icon pack file paths
888  * @param iconClass The controller class (AIStatusIcons, AIServiceIcons) for icon pack previews
889  */
890 - (NSMenu *)_iconPackMenuForPacks:(NSArray *)packs class:(Class)iconClass
892         NSMenu                  *serviceIconsMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];
893         NSEnumerator    *enumerator = [packs objectEnumerator];
894         NSString                *packPath;
896         while(packPath = [enumerator nextObject]){
897                 NSString        *name = [[packPath lastPathComponent] stringByDeletingPathExtension];
898                 NSMenuItem      *menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:name
899                                                                                                                                                                           target:nil
900                                                                                                                                                                           action:nil
901                                                                                                                                                            keyEquivalent:@""] autorelease];
902                 [menuItem setRepresentedObject:name];
903                 [menuItem setImage:[iconClass previewMenuImageForIconPackAtPath:packPath]];
904                 [serviceIconsMenu addItem:menuItem];
905         }
906         
907         return(serviceIconsMenu);       
910 @end