Added `-[NSArray validateAsPropertyList]` and `-[NSDictionary validateAsPropertyList...
[adiumx.git] / Source / AIListLayoutWindowController.m
blob1157ab9a05996afcdc01ad36b24304e2e5d39e99
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 <Adium/AIPreferenceControllerProtocol.h>
18 #import "AIListLayoutWindowController.h"
19 #import "AIDockController.h"
20 #import "AISCLViewPlugin.h"
21 #import <AIUtilities/AIFontAdditions.h>
22 #import <AIUtilities/AIMenuAdditions.h>
23 #import <AIUtilities/AIPopUpButtonAdditions.h>
24 #import <AIUtilities/AIArrayAdditions.h>
25 #import <Adium/AIAbstractListController.h>
26 #import <Adium/JVFontPreviewField.h>
28 #define MAX_ALIGNMENT_CHOICES   10
30 @interface AIListLayoutWindowController (PRIVATE)
31 - (id)initWithWindowNibName:(NSString *)windowNibName name:(NSString *)inName notifyingTarget:(id)inTarget;
32 - (void)configureControls;
33 - (void)configureControlDimming;
34 - (void)updateSliderValues;
35 - (void)updateDisplayedTabsFromPrefDict:(NSDictionary *)prefDict;
36 - (void)updateStatusAndServiceIconMenusFromPrefDict:(NSDictionary *)prefDict;
37 - (void)updateUserIconMenuFromPrefDict:(NSDictionary *)prefDict;
38 - (NSMenu *)alignmentMenuWithChoices:(int [])alignmentChoices;
39 - (NSMenu *)positionMenuWithChoices:(int [])positionChoices;
40 - (NSMenu *)extendedStatusStyleMenu;
41 - (NSMenu *)extendedStatusPositionMenu;
42 - (NSMenu *)windowStyleMenu;
43 @end
45 @implementation AIListLayoutWindowController
47 + (id)editListLayoutWithName:(NSString *)inName onWindow:(NSWindow *)parentWindow notifyingTarget:(id)inTarget
49         AIListLayoutWindowController    *listLayoutWindow = [[self alloc] initWithWindowNibName:@"ListLayoutSheet"
50                                                                                                                                                                            name:inName
51                                                                                                                                                         notifyingTarget:inTarget];
52         
53         if (parentWindow) {
54                 [NSApp beginSheet:[listLayoutWindow window]
55                    modalForWindow:parentWindow
56                         modalDelegate:listLayoutWindow
57                    didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
58                           contextInfo:nil];
59         } else {
60                 [listLayoutWindow showWindow:nil];
61         }
62         
63         return listLayoutWindow;
66 - (id)initWithWindowNibName:(NSString *)windowNibName name:(NSString *)inName notifyingTarget:(id)inTarget
68     [super initWithWindowNibName:windowNibName];
69         
70         NSParameterAssert(inTarget && [inTarget respondsToSelector:@selector(listLayoutEditorWillCloseWithChanges:forLayoutNamed:)]);
71         
72         target = inTarget;
73         layoutName = [inName retain];
74         
75         return self;
78 - (void)dealloc
80         [layoutName release];
81     [super dealloc];
85 //Window Methods -------------------------------------------------------------------------------------------------------
86 #pragma mark Window Methods
87 - (void)windowDidLoad
89         //We'll be adding/removing this from our view
90         [tabViewItem_advancedContactBubbles retain];
91         
92         //Setup
93         [fontField_contact setShowPointSize:YES];
94         [fontField_contact setShowFontFace:YES];
95         [fontField_status setShowPointSize:YES];
96         [fontField_status setShowFontFace:YES];
97         [fontField_group setShowPointSize:YES];
98         [fontField_group setShowFontFace:YES];
99         
100         [self configureControls];
103 //Window is closing
104 - (void)windowWillClose:(id)sender
106         [super windowWillClose:sender];
107         
108         [tabViewItem_advancedContactBubbles autorelease];
109         [self autorelease];
112 //Called as the sheet closes, dismisses the sheet
113 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
115     [sheet orderOut:nil];
118 //Cancel
119 - (IBAction)cancel:(id)sender
121         [target listLayoutEditorWillCloseWithChanges:NO forLayoutNamed:layoutName];
122         [self closeWindow:sender];
125 //Okay
126 - (IBAction)okay:(id)sender
128         [target listLayoutEditorWillCloseWithChanges:YES forLayoutNamed:layoutName];
129         [self closeWindow:sender];
133 //Window Methods -------------------------------------------------------------------------------------------------------
134 - (void)configureControls
136         NSDictionary    *prefDict = [[adium preferenceController] preferencesForGroup:PREF_GROUP_LIST_LAYOUT];
137         int                             textAlignmentChoices[4];
138         
139         textAlignmentChoices[0] = NSLeftTextAlignment;
140         textAlignmentChoices[1] = NSCenterTextAlignment;
141         textAlignmentChoices[2] = NSRightTextAlignment;
142         textAlignmentChoices[3] = -1;
143         
144         [self updateDisplayedTabsFromPrefDict:prefDict];
145         
146         [self updateStatusAndServiceIconMenusFromPrefDict:prefDict];
147         
148         [self updateUserIconMenuFromPrefDict:prefDict];
149         
150         //Context text alignment
151         [popUp_contactTextAlignment setMenu:[self alignmentMenuWithChoices:textAlignmentChoices]];
152         [popUp_contactTextAlignment compatibleSelectItemWithTag:[[prefDict objectForKey:KEY_LIST_LAYOUT_ALIGNMENT] intValue]];
153         
154         //Group text alignment
155         [popUp_groupTextAlignment setMenu:[self alignmentMenuWithChoices:textAlignmentChoices]];
156         [popUp_groupTextAlignment compatibleSelectItemWithTag:[[prefDict objectForKey:KEY_LIST_LAYOUT_GROUP_ALIGNMENT] intValue]];
157         
158         //Extended Status position
159         [popUp_extendedStatusPosition setMenu:[self extendedStatusPositionMenu]];
160         [popUp_extendedStatusPosition compatibleSelectItemWithTag:[[prefDict objectForKey:KEY_LIST_LAYOUT_EXTENDED_STATUS_POSITION] intValue]];
161         
162         //Window style
163         [popUp_extendedStatusStyle setMenu:[self extendedStatusStyleMenu]];
164         [popUp_extendedStatusStyle compatibleSelectItemWithTag:[[prefDict objectForKey:KEY_LIST_LAYOUT_EXTENDED_STATUS_STYLE] intValue]];
165         
166         [slider_userIconSize setIntValue:[[prefDict objectForKey:KEY_LIST_LAYOUT_USER_ICON_SIZE] intValue]];
167         [slider_contactSpacing setIntValue:[[prefDict objectForKey:KEY_LIST_LAYOUT_CONTACT_SPACING] intValue]];
169         [slider_groupTopSpacing setIntValue:[[prefDict objectForKey:KEY_LIST_LAYOUT_GROUP_TOP_SPACING] intValue]];
170         [slider_groupTopSpacing setMinValue:0];
171         [slider_groupTopSpacing setMaxValue:16];
173         [slider_contactLeftIndent setIntValue:[[prefDict objectForKey:KEY_LIST_LAYOUT_CONTACT_LEFT_INDENT] intValue]];
174         [slider_contactRightIndent setIntValue:[[prefDict objectForKey:KEY_LIST_LAYOUT_CONTACT_RIGHT_INDENT] intValue]];
175         [self updateSliderValues];
176         
177         [fontField_contact setFont:[[prefDict objectForKey:KEY_LIST_LAYOUT_CONTACT_FONT] representedFont]];
178         [fontField_status setFont:[[prefDict objectForKey:KEY_LIST_LAYOUT_STATUS_FONT] representedFont]];
179         [fontField_group setFont:[[prefDict objectForKey:KEY_LIST_LAYOUT_GROUP_FONT] representedFont]];
180         
181         [self configureControlDimming];
184 - (void)preferenceChanged:(id)sender
186         if (sender == popUp_contactTextAlignment) {
187                 [[adium preferenceController] setPreference:[NSNumber numberWithInt:[[sender selectedItem] tag]]
188                                                                                          forKey:KEY_LIST_LAYOUT_ALIGNMENT
189                                                                                           group:PREF_GROUP_LIST_LAYOUT];
190                 
191                 NSDictionary    *prefDict;
192                 prefDict = [[adium preferenceController] preferencesForGroup:PREF_GROUP_LIST_LAYOUT];
193                 
194                 [self updateStatusAndServiceIconMenusFromPrefDict:prefDict];
195                 [self updateUserIconMenuFromPrefDict:prefDict];
196                 
197                 [self configureControlDimming];
198                 
199         } else if (sender == popUp_groupTextAlignment) {
200                 [[adium preferenceController] setPreference:[NSNumber numberWithInt:[[sender selectedItem] tag]]
201                                                                                          forKey:KEY_LIST_LAYOUT_GROUP_ALIGNMENT
202                                                                                           group:PREF_GROUP_LIST_LAYOUT];
203                 
204         } else if (sender == popUp_extendedStatusPosition) {
205                 [[adium preferenceController] setPreference:[NSNumber numberWithInt:[[sender selectedItem] tag]]
206                                                                                          forKey:KEY_LIST_LAYOUT_EXTENDED_STATUS_POSITION
207                                                                                           group:PREF_GROUP_LIST_LAYOUT];
208                 
209         } else if (sender == popUp_userIconPosition) {
210                 [[adium preferenceController] setPreference:[NSNumber numberWithInt:[[sender selectedItem] tag]]
211                                                                                          forKey:KEY_LIST_LAYOUT_USER_ICON_POSITION
212                                                                                           group:PREF_GROUP_LIST_LAYOUT];
213                 
214         } else if (sender == popUp_statusIconPosition) {
215                 [[adium preferenceController] setPreference:[NSNumber numberWithInt:[[sender selectedItem] tag]]
216                                                                                          forKey:KEY_LIST_LAYOUT_STATUS_ICON_POSITION
217                                                                                           group:PREF_GROUP_LIST_LAYOUT];
218                 
219         } else if (sender == popUp_serviceIconPosition) {
220                 [[adium preferenceController] setPreference:[NSNumber numberWithInt:[[sender selectedItem] tag]]
221                                                                                          forKey:KEY_LIST_LAYOUT_SERVICE_ICON_POSITION
222                                                                                           group:PREF_GROUP_LIST_LAYOUT];
223                 
224         } else if (sender == popUp_extendedStatusStyle) {
225                 [[adium preferenceController] setPreference:[NSNumber numberWithInt:[[sender selectedItem] tag]]
226                                                                                          forKey:KEY_LIST_LAYOUT_EXTENDED_STATUS_STYLE
227                                                                                           group:PREF_GROUP_LIST_LAYOUT];
228                 
229                 
230         } else if (sender == slider_userIconSize) {
231                 [[adium preferenceController] setPreference:[NSNumber numberWithInt:[sender intValue]]
232                                                                                          forKey:KEY_LIST_LAYOUT_USER_ICON_SIZE
233                                                                                           group:PREF_GROUP_LIST_LAYOUT];
234                 [self updateSliderValues];
235                 
236         } else if (sender == slider_contactSpacing) {
237                 [[adium preferenceController] setPreference:[NSNumber numberWithInt:[sender intValue]]
238                                                                                          forKey:KEY_LIST_LAYOUT_CONTACT_SPACING
239                                                                                           group:PREF_GROUP_LIST_LAYOUT];
240                 [self updateSliderValues];
241         } else if (sender == slider_groupTopSpacing) {
242                 [[adium preferenceController] setPreference:[NSNumber numberWithInt:[sender intValue]]
243                                                                                          forKey:KEY_LIST_LAYOUT_GROUP_TOP_SPACING
244                                                                                           group:PREF_GROUP_LIST_LAYOUT];
245                 [self updateSliderValues];
246                 
247         } else if (sender == checkBox_userIconVisible) {
248                 NSDictionary    *prefDict;
249                 
250                 [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
251                                                                                          forKey:KEY_LIST_LAYOUT_SHOW_ICON
252                                                                                           group:PREF_GROUP_LIST_LAYOUT];
253                 
254                 prefDict  = [[adium preferenceController] preferencesForGroup:PREF_GROUP_LIST_LAYOUT];
255                 //Update the status and service icon menus to show/hide the badge options
256                 [self updateStatusAndServiceIconMenusFromPrefDict:prefDict];
257                 [self configureControlDimming];
258                 
259         } else if (sender == checkBox_extendedStatusVisible) {
260                 [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
261                                                                                          forKey:KEY_LIST_LAYOUT_SHOW_EXT_STATUS
262                                                                                           group:PREF_GROUP_LIST_LAYOUT];
263                 [self configureControlDimming];
264                 
265         } else if (sender == checkBox_statusIconsVisible) {
266                 [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
267                                                                                          forKey:KEY_LIST_LAYOUT_SHOW_STATUS_ICONS
268                                                                                           group:PREF_GROUP_LIST_LAYOUT];
269                 [self configureControlDimming];
270                 
271         } else if (sender == checkBox_serviceIconsVisible) {
272                 [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
273                                                                                          forKey:KEY_LIST_LAYOUT_SHOW_SERVICE_ICONS
274                                                                                           group:PREF_GROUP_LIST_LAYOUT];
275                 [self configureControlDimming];
276                 
277     } else if (sender == checkBox_outlineBubbles) {
278         [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
279                                              forKey:KEY_LIST_LAYOUT_OUTLINE_BUBBLE
280                                               group:PREF_GROUP_LIST_LAYOUT];
281                 [self configureControlDimming];
282                 
283     } else if (sender == checkBox_drawContactBubblesWithGraadient) {
284         [[adium preferenceController] setPreference:[NSNumber numberWithBool:[sender state]]
285                                              forKey:KEY_LIST_LAYOUT_CONTACT_BUBBLE_GRADIENT
286                                               group:PREF_GROUP_LIST_LAYOUT];
287                 
288     } else if (sender == checkBox_showGroupBubbles) {
289                 BOOL shouldHideGroupBubbles = ![sender state];
290                 
291         [[adium preferenceController] setPreference:[NSNumber numberWithBool:shouldHideGroupBubbles]
292                                              forKey:KEY_LIST_LAYOUT_GROUP_HIDE_BUBBLE
293                                               group:PREF_GROUP_LIST_LAYOUT];
294                 [self configureControlDimming];
295                 
296     } else if (sender == slider_contactLeftIndent) {
297         [[adium preferenceController] setPreference:[NSNumber numberWithInt:[sender intValue]]
298                                              forKey:KEY_LIST_LAYOUT_CONTACT_LEFT_INDENT
299                                               group:PREF_GROUP_LIST_LAYOUT];
300                 [self updateSliderValues];
301                 
302     } else if (sender == slider_contactRightIndent) {
303         [[adium preferenceController] setPreference:[NSNumber numberWithInt:[sender intValue]]
304                                              forKey:KEY_LIST_LAYOUT_CONTACT_RIGHT_INDENT
305                                               group:PREF_GROUP_LIST_LAYOUT];
306                 [self updateSliderValues];
307                 
308         } else if (sender == slider_outlineWidth) {
309                 int newValue = [sender intValue];
310                 int oldValue = [[[adium preferenceController] preferenceForKey:KEY_LIST_LAYOUT_OUTLINE_BUBBLE_WIDTH
311                                                                                                                                  group:PREF_GROUP_LIST_LAYOUT] intValue];
312                 if (newValue != oldValue) { 
313                         [[adium preferenceController] setPreference:[NSNumber numberWithInt:newValue]
314                                                                                                  forKey:KEY_LIST_LAYOUT_OUTLINE_BUBBLE_WIDTH
315                                                                                                   group:PREF_GROUP_LIST_LAYOUT];
316                         [self updateSliderValues];
317                 }
318         }
321 - (BOOL)fontPreviewField:(JVFontPreviewField *)field shouldChangeToFont:(NSFont *)font
323         return YES;
326 - (void)fontPreviewField:(JVFontPreviewField *)field didChangeToFont:(NSFont *)font
328         if (field == fontField_contact) {
329         [[adium preferenceController] setPreference:[font stringRepresentation]
330                                              forKey:KEY_LIST_LAYOUT_CONTACT_FONT
331                                               group:PREF_GROUP_LIST_LAYOUT];
332                 
333         } else if (field == fontField_status) {
334         [[adium preferenceController] setPreference:[font stringRepresentation]
335                                              forKey:KEY_LIST_LAYOUT_STATUS_FONT
336                                               group:PREF_GROUP_LIST_LAYOUT];
337                 
338         } else if (field == fontField_group) {
339         [[adium preferenceController] setPreference:[font stringRepresentation]
340                                              forKey:KEY_LIST_LAYOUT_GROUP_FONT
341                                               group:PREF_GROUP_LIST_LAYOUT];
342                 
343         }
347 - (void)updateSliderValues
349         int     iconSize = [slider_userIconSize intValue];
350         [textField_userIconSize setStringValue:[NSString stringWithFormat:@"%ix%i",iconSize,iconSize]];
351         
352         [textField_contactSpacing setStringValue:[NSString stringWithFormat:@"%ipx",[slider_contactSpacing intValue]]];
353         [textField_groupTopSpacing setStringValue:[NSString stringWithFormat:@"%ipx",[slider_groupTopSpacing intValue]]];
354         [textField_contactLeftIndent setStringValue:[NSString stringWithFormat:@"%ipx",[slider_contactLeftIndent intValue]]];
355         [textField_contactRightIndent setStringValue:[NSString stringWithFormat:@"%ipx",[slider_contactRightIndent intValue]]];
356         [textField_outlineWidthIndicator setStringValue:[NSString stringWithFormat:@"%ipx",[slider_outlineWidth intValue]]];
359 //Configure control dimming
360 - (void)configureControlDimming
362         NSDictionary    *prefDict = [[adium preferenceController] preferencesForGroup:PREF_GROUP_LIST_LAYOUT];
363         int                             windowStyle = [[[adium preferenceController] preferenceForKey:KEY_LIST_LAYOUT_WINDOW_STYLE group:PREF_GROUP_APPEARANCE] intValue];
364         
365         //Bubble to fit limitations
366         BOOL nonFitted = (windowStyle != AIContactListWindowStyleContactBubbles_Fitted);
367         if (nonFitted) {
368                 //For the non-fitted styles, enable and set the proper state
369                 [checkBox_extendedStatusVisible setEnabled:YES];
370                 [checkBox_extendedStatusVisible setState:[[prefDict objectForKey:KEY_LIST_LAYOUT_SHOW_EXT_STATUS] boolValue]];
371         } else {
372                 //For the fitted style, disable and set to NO the extendedStatus
373                 [checkBox_extendedStatusVisible setEnabled:NO];
374                 [checkBox_extendedStatusVisible setState:NO];
375         }
376         
377         if (nonFitted || ([[prefDict objectForKey:KEY_LIST_LAYOUT_ALIGNMENT] intValue] != NSCenterTextAlignment)) {
378                 //For non-fitted or non-centered fitted, enable and set the appropriate value
379                 [checkBox_userIconVisible setEnabled:YES];
380                 [checkBox_userIconVisible setState:[[prefDict objectForKey:KEY_LIST_LAYOUT_SHOW_ICON] boolValue]];
381                 
382                 [checkBox_statusIconsVisible setEnabled:YES];
383                 [checkBox_statusIconsVisible setState:[[prefDict objectForKey:KEY_LIST_LAYOUT_SHOW_STATUS_ICONS] boolValue]];
384                 
385                 [checkBox_serviceIconsVisible setEnabled:YES];
386                 [checkBox_serviceIconsVisible setState:[[prefDict objectForKey:KEY_LIST_LAYOUT_SHOW_SERVICE_ICONS] boolValue]]; 
387                 
388         } else {
389                 //For fitted and centered, disable and set to NO
390                 [checkBox_userIconVisible setEnabled:NO];
391                 [checkBox_userIconVisible setState:NO];
392                 
393                 [checkBox_statusIconsVisible setEnabled:NO];
394                 [checkBox_statusIconsVisible setState:NO];
395                 
396                 [checkBox_serviceIconsVisible setEnabled:NO];
397                 [checkBox_serviceIconsVisible setState:NO];
398         }
399         
400         
401         
402         
403         //User icon controls
404         [slider_userIconSize setEnabled:([checkBox_userIconVisible state] && [checkBox_userIconVisible isEnabled])];
405         [textField_userIconSize setEnabled:([checkBox_userIconVisible state] && [checkBox_userIconVisible isEnabled])];
406         [popUp_userIconPosition setEnabled:([checkBox_userIconVisible state] && [checkBox_userIconVisible isEnabled])];
407         
408         //Other controls
409         BOOL extendedStatusEnabled = ([checkBox_extendedStatusVisible state] && [checkBox_extendedStatusVisible isEnabled]);
410         
411         
412         [popUp_extendedStatusStyle setEnabled:extendedStatusEnabled];
413         [popUp_extendedStatusPosition setEnabled:extendedStatusEnabled];
414         [popUp_statusIconPosition setEnabled:([checkBox_statusIconsVisible state] && 
415                                                                                   [checkBox_statusIconsVisible isEnabled] &&
416                                                                                   ([popUp_statusIconPosition numberOfItems] > 0))];
417         [popUp_serviceIconPosition setEnabled:([checkBox_serviceIconsVisible state] &&
418                                                                                    [checkBox_serviceIconsVisible isEnabled] &&
419                                                                                    ([popUp_serviceIconPosition numberOfItems] > 0))];
420         [popUp_userIconPosition setEnabled:([checkBox_userIconVisible state] &&
421                                                                                 [checkBox_userIconVisible isEnabled] &&
422                                                                                 ([popUp_userIconPosition numberOfItems] > 0))];
423         
424         //Disable group spacing when not using mockie
425         [slider_groupTopSpacing setEnabled:(windowStyle == AIContactListWindowStyleGroupBubbles)];
426         [textField_groupTopSpacing setEnabled:(windowStyle == AIContactListWindowStyleGroupBubbles)];
427         
428         //Contact Bubbles Advanced
429         
430         //Only enable the outline width slider if outline width is being shown
431         [slider_outlineWidth setEnabled:[checkBox_outlineBubbles state]];
434 - (void)updateStatusAndServiceIconMenusFromPrefDict:(NSDictionary *)prefDict
436         int                             statusAndServicePositionChoices[7];
437         BOOL                    showUserIcon = [[prefDict objectForKey:KEY_LIST_LAYOUT_SHOW_ICON] boolValue];
438         int                             indexForFinishingChoices = 0;
439         
440         if ([[[adium preferenceController] preferenceForKey:KEY_LIST_LAYOUT_WINDOW_STYLE group:PREF_GROUP_APPEARANCE] intValue] != AIContactListWindowStyleContactBubbles_Fitted) {
441                 statusAndServicePositionChoices[0] = LIST_POSITION_FAR_LEFT;
442                 statusAndServicePositionChoices[1] = LIST_POSITION_LEFT;
443                 statusAndServicePositionChoices[2] = LIST_POSITION_RIGHT;
444                 statusAndServicePositionChoices[3] = LIST_POSITION_FAR_RIGHT;
445                 
446                 indexForFinishingChoices = 4;
447                 
448         } else {
449                 //For fitted pillows, only show the options which correspond to the text alignment
450                 switch ([[prefDict objectForKey:KEY_LIST_LAYOUT_ALIGNMENT] intValue]) {
451                         case NSLeftTextAlignment:
452                                 statusAndServicePositionChoices[0] = LIST_POSITION_FAR_LEFT;
453                                 statusAndServicePositionChoices[1] = LIST_POSITION_LEFT;
454                                 indexForFinishingChoices = 2;
455                                 break;
456                                 
457                         case NSRightTextAlignment:
458                                 statusAndServicePositionChoices[0] = LIST_POSITION_RIGHT;
459                                 statusAndServicePositionChoices[1] = LIST_POSITION_FAR_RIGHT;
460                                 indexForFinishingChoices = 2;
461                                 
462                                 break;
463                         case NSCenterTextAlignment:
464                                 
465                                 break;
466                 }       
467         }
468         
469         //Only show the badge choices if we are showing the user icon
470         if (showUserIcon && (indexForFinishingChoices != 0)) {
471                 statusAndServicePositionChoices[indexForFinishingChoices] = LIST_POSITION_BADGE_LEFT;
472                 statusAndServicePositionChoices[indexForFinishingChoices + 1] = LIST_POSITION_BADGE_RIGHT;
473                 statusAndServicePositionChoices[indexForFinishingChoices + 2] = -1;
474                 
475         } else {
476                 statusAndServicePositionChoices[indexForFinishingChoices] = -1;
477                 
478         }
479         
480         /* If we can't select an item in the status icon or service icon menu, that means our previous selection is no longer available;
481          * set the preference to whichever option we just 'selected' by default.
482          */
483         [popUp_statusIconPosition setMenu:[self positionMenuWithChoices:statusAndServicePositionChoices]];
484         if ([popUp_statusIconPosition numberOfItems] &&
485                 ![popUp_statusIconPosition compatibleSelectItemWithTag:[[prefDict objectForKey:KEY_LIST_LAYOUT_STATUS_ICON_POSITION] intValue]]) {
486                 [popUp_statusIconPosition selectItemAtIndex:0];
487                 [[adium preferenceController] setPreference:[NSNumber numberWithInt:[[popUp_statusIconPosition selectedItem] tag]]
488                                                                                          forKey:KEY_LIST_LAYOUT_STATUS_ICON_POSITION
489                                                                                           group:PREF_GROUP_LIST_LAYOUT];                
490         }
492         [popUp_serviceIconPosition setMenu:[self positionMenuWithChoices:statusAndServicePositionChoices]];
493         if ([popUp_serviceIconPosition numberOfItems] &&
494                 ![popUp_serviceIconPosition compatibleSelectItemWithTag:[[prefDict objectForKey:KEY_LIST_LAYOUT_SERVICE_ICON_POSITION] intValue]]) {
495                 [popUp_serviceIconPosition selectItemAtIndex:0];
496                 [[adium preferenceController] setPreference:[NSNumber numberWithInt:[[popUp_serviceIconPosition selectedItem] tag]]
497                                                                                          forKey:KEY_LIST_LAYOUT_SERVICE_ICON_POSITION
498                                                                                           group:PREF_GROUP_LIST_LAYOUT];
499         }
502 - (void)updateUserIconMenuFromPrefDict:(NSDictionary *)prefDict
504         int                             userIconPositionChoices[3];
505         
506         if ([[[adium preferenceController] preferenceForKey:KEY_LIST_LAYOUT_WINDOW_STYLE group:PREF_GROUP_APPEARANCE] intValue] != AIContactListWindowStyleContactBubbles_Fitted) {
507                 userIconPositionChoices[0] = LIST_POSITION_LEFT;
508                 userIconPositionChoices[1] = LIST_POSITION_RIGHT;
509                 userIconPositionChoices[2] = -1;
510         } else {
511                 //For fitted pillows, only show the options which correspond to the text alignment
512                 switch ([[prefDict objectForKey:KEY_LIST_LAYOUT_ALIGNMENT] intValue]) {
513                         case NSLeftTextAlignment:
514                                 userIconPositionChoices[0] = LIST_POSITION_LEFT;
515                                 userIconPositionChoices[1] = -1;
516                                 break;
517                                 
518                         case NSRightTextAlignment:              
519                                 userIconPositionChoices[0] = LIST_POSITION_RIGHT;
520                                 userIconPositionChoices[1] = -1;
521                                 break;
522                         case NSCenterTextAlignment:
523                                 userIconPositionChoices[0] = -1;                                
524                                 break;
525                 }       
526         }
527         
528         
529         //User icon position
530         [popUp_userIconPosition setMenu:[self positionMenuWithChoices:userIconPositionChoices]];
531         [popUp_userIconPosition compatibleSelectItemWithTag:[[prefDict objectForKey:KEY_LIST_LAYOUT_USER_ICON_POSITION] intValue]];
534 #pragma mark Menu generation
536 - (NSMenu *)alignmentMenuWithChoices:(int [])alignmentChoices
538     NSMenu              *alignmentMenu = [[[NSMenu allocWithZone:[NSMenu menuZone]] init] autorelease];
539         NSMenuItem      *menuItem;
540     
541         unsigned        i = 0;
542         
543         while (alignmentChoices[i] != -1) {
544                 NSString        *menuTitle = nil;
545                 
546                 switch (alignmentChoices[i]) {
547                         case NSLeftTextAlignment:       menuTitle = AILocalizedString(@"Left",nil);
548                                 break;
549                         case NSCenterTextAlignment:     menuTitle = AILocalizedString(@"Center",nil);
550                                 break;
551                         case NSRightTextAlignment:      menuTitle = AILocalizedString(@"Right",nil);
552                                 break;
553                 }
554                 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:menuTitle
555                                                                                                                                                  target:nil
556                                                                                                                                                  action:nil
557                                                                                                                                   keyEquivalent:@""] autorelease];
558                 [menuItem setTag:alignmentChoices[i]];
559                 [alignmentMenu addItem:menuItem];
560                 
561                 i++;
562         }
563         
564         return alignmentMenu;
565         
568 - (NSMenu *)positionMenuWithChoices:(int [])positionChoices
570     NSMenu              *positionMenu = [[[NSMenu allocWithZone:[NSMenu menuZone]] init] autorelease];
571     NSMenuItem  *menuItem;
572     
573         unsigned        i = 0;
574         
575         while (positionChoices[i] != -1) {
576                 NSString        *menuTitle = nil;
577                 
578                 switch (positionChoices[i]) {
579                         case LIST_POSITION_LEFT:
580                                 menuTitle = AILocalizedString(@"Left",nil);
581                                 break;
582                         case LIST_POSITION_RIGHT:
583                                 menuTitle = AILocalizedString(@"Right",nil);
584                                 break;
585                         case LIST_POSITION_FAR_LEFT: menuTitle = AILocalizedString(@"Far Left",nil);
586                                 break;
587                         case LIST_POSITION_FAR_RIGHT: menuTitle = AILocalizedString(@"Far Right",nil);
588                                 break;
589                         case LIST_POSITION_BADGE_LEFT: menuTitle = AILocalizedString(@"Badge (Lower Left)",nil);
590                                 break;
591                         case LIST_POSITION_BADGE_RIGHT: menuTitle = AILocalizedString(@"Badge (Lower Right)",nil);
592                                 break;
593                 }
594                 menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:menuTitle
595                                                                                                                                                  target:nil
596                                                                                                                                                  action:nil
597                                                                                                                                   keyEquivalent:@""] autorelease];
598                 [menuItem setTag:positionChoices[i]];
599                 [positionMenu addItem:menuItem];
600                 
601                 i++;
602         }
603         
604         return positionMenu;
607 - (NSMenu *)extendedStatusPositionMenu
609         NSMenu          *extendedStatusPositionMenu = [[[NSMenu allocWithZone:[NSMenu menuZone]] init] autorelease];
610     NSMenuItem  *menuItem;
611         
612         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Below Name",nil)
613                                                                                                                                          target:nil
614                                                                                                                                          action:nil
615                                                                                                                           keyEquivalent:@""] autorelease];
616         [menuItem setTag:EXTENDED_STATUS_POSITION_BELOW_NAME];
617         [extendedStatusPositionMenu addItem:menuItem];
618         
619         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Beside Name",nil)
620                                                                                                                                          target:nil
621                                                                                                                                          action:nil
622                                                                                                                           keyEquivalent:@""] autorelease];
623         [menuItem setTag:EXTENDED_STATUS_POSITION_BESIDE_NAME];
624         [extendedStatusPositionMenu addItem:menuItem];
625         
626         return extendedStatusPositionMenu;
629 - (NSMenu *)extendedStatusStyleMenu
631     NSMenu              *extendedStatusStyleMenu = [[[NSMenu allocWithZone:[NSMenu menuZone]] init] autorelease];
632     NSMenuItem  *menuItem;
633         
634         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Status",nil)
635                                                                                                                                          target:nil
636                                                                                                                                          action:nil
637                                                                                                                           keyEquivalent:@""] autorelease];
638         [menuItem setTag:STATUS_ONLY];
639         [extendedStatusStyleMenu addItem:menuItem];
640         
641         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Idle Time",nil)
642                                                                                                                                          target:nil
643                                                                                                                                          action:nil
644                                                                                                                           keyEquivalent:@""] autorelease];
645         [menuItem setTag:IDLE_ONLY];
646         [extendedStatusStyleMenu addItem:menuItem];
647         
648         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"(Idle) Status",nil)
649                                                                                                                                          target:nil
650                                                                                                                                          action:nil
651                                                                                                                           keyEquivalent:@""] autorelease];
652         [menuItem setTag:IDLE_AND_STATUS];
653         [extendedStatusStyleMenu addItem:menuItem];
654         
655         return extendedStatusStyleMenu;
659 #pragma mark Displayed Tabs
660 //Displayed Tabs
661 - (void)updateDisplayedTabsFromPrefDict:(NSDictionary *)prefDict
663         AIContactListWindowStyle        windowStyle;
664         BOOL                            tabViewCurrentHasAdvancedContactBubbles;
665         
666         windowStyle = [[[adium preferenceController] preferenceForKey:KEY_LIST_LAYOUT_WINDOW_STYLE group:PREF_GROUP_APPEARANCE] intValue];
667         tabViewCurrentHasAdvancedContactBubbles = ([[tabView_preferences tabViewItems] containsObjectIdenticalTo:tabViewItem_advancedContactBubbles]);
668         
669         if ((windowStyle == AIContactListWindowStyleContactBubbles_Fitted) ||
670                 (windowStyle == AIContactListWindowStyleContactBubbles)) {
671                 
672                 if (!tabViewCurrentHasAdvancedContactBubbles) {
673                         [tabView_preferences addTabViewItem:tabViewItem_advancedContactBubbles];
674                 }
675                 
676                 //Configure the controls whose state we only care about if we are showing this tab view item
677                 BOOL showGroupBubbles = ![[prefDict objectForKey:KEY_LIST_LAYOUT_GROUP_HIDE_BUBBLE] boolValue];
678                 [checkBox_showGroupBubbles setState:showGroupBubbles];
679                 
680                 [checkBox_outlineBubbles setState:[[prefDict objectForKey:KEY_LIST_LAYOUT_OUTLINE_BUBBLE] boolValue]];
681                 [checkBox_drawContactBubblesWithGraadient setState:[[prefDict objectForKey:KEY_LIST_LAYOUT_CONTACT_BUBBLE_GRADIENT] boolValue]];
682                 
683                 [slider_outlineWidth setIntValue:[[prefDict objectForKey:KEY_LIST_LAYOUT_OUTLINE_BUBBLE_WIDTH] intValue]];
684                 
685         } else {
686                 if (tabViewCurrentHasAdvancedContactBubbles) {
687                         [tabView_preferences removeTabViewItem:tabViewItem_advancedContactBubbles];
688                 }               
689         }
692 @end