William Bowling is sharing code with you

Bitbucket is a code hosting site. Unlimited public and private repositories. Free for small teams.

Don't show this again

wbowling / adium (fork of adium / adium)

Fork of Adium for patches/improvements

Clone this repository (size: 338.7 MB): HTTPS / SSH
hg clone https://bitbucket.org/wbowling/adium
hg clone ssh://hg@bitbucket.org/wbowling/adium

adium / Source / AIAppearancePreferences.m

   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
/* 
 * Adium is the legal property of its developers, whose names are listed in the copyright file included
 * with this source distribution.
 * 
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
 * General Public License as published by the Free Software Foundation; either version 2 of the License,
 * or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
 * Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this program; if not,
 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#import "AIAppearancePreferences.h"
#import "AIAppearancePreferencesPlugin.h"
#import "AIDockIconSelectionSheet.h"
#import "AIEmoticonPack.h"
#import "AIEmoticonPreferences.h"
#import "AIListLayoutWindowController.h"
#import "AIListThemeWindowController.h"
#import <AIUtilities/AIMenuAdditions.h>
#import <AIUtilities/AIImageAdditions.h>
#import <AIUtilities/AIImageDrawingAdditions.h>
#import <AIUtilities/AIPopUpButtonAdditions.h>
#import <AIUtilities/AIStringAdditions.h>
#import <Adium/AIAbstractListController.h>
#import <Adium/AIDockControllerProtocol.h>
#import <Adium/AIEmoticonControllerProtocol.h>
#import <Adium/AIIconState.h>
#import <Adium/AIServiceIcons.h>
#import <Adium/AIStatusIcons.h>
#import <Adium/ESPresetManagementController.h>
#import <Adium/ESPresetNameSheetController.h>
#import "AIMenuBarIcons.h"

typedef enum {
        AIEmoticonMenuNone = 1,
        AIEmoticonMenuMultiple
} AIEmoticonMenuTag;

@interface AIAppearancePreferences ()
- (NSMenu *)_windowStyleMenu;
- (NSMenu *)_emoticonPackMenu;
- (NSMenu *)_listLayoutMenu;
- (NSMenu *)_colorThemeMenu;
- (void)_rebuildEmoticonMenuAndSelectActivePack;
- (void)_addWindowStyleOption:(NSString *)option withTag:(NSInteger)tag toMenu:(NSMenu *)menu;
- (void)_updateSliderValues;
- (void)xtrasChanged:(NSNotification *)notification;

- (void)configureDockIconMenu;
- (void)configureStatusIconsMenu;
- (void)configureServiceIconsMenu;
- (void)configureMenuBarIconsMenu;
@end

@implementation AIAppearancePreferences

/*!
 * @brief Preference pane properties
 */
- (NSString *)paneIdentifier
{
        return @"Appearance";
}
- (NSString *)paneName{
    return AILocalizedString(@"Appearance","Appearance preferences label");
}
- (NSString *)nibName{
    return @"AppearancePrefs";
}
- (NSImage *)paneIcon
{
        return [NSImage imageNamed:@"pref-appearance" forClass:[self class]];
}

/*!
 * @brief Configure the preference view
 */
- (void)viewDidLoad
{
        [slider_windowOpacity setMinValue:0.0];
        [slider_windowOpacity setMaxValue:100.0];

        //Other list options
        [popUp_windowStyle setMenu:[self _windowStyleMenu]];
                
        //Observe preference changes
        [adium.preferenceController registerPreferenceObserver:self forGroup:PREF_GROUP_EMOTICONS];
        [adium.preferenceController registerPreferenceObserver:self forGroup:PREF_GROUP_APPEARANCE];

        //Observe xtras changes
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                                   selector:@selector(xtrasChanged:)
                                                                           name:AIXtrasDidChangeNotification
                                                                         object:nil];   
        [self xtrasChanged:nil];
}

/*!
 * @brief View will close
 */
- (void)viewWillClose
{
        [adium.preferenceController unregisterPreferenceObserver:self];
        
        [[NSNotificationCenter defaultCenter] removeObserver:self];
}

/*!
 * @brief Xtras changed, update our menus to reflect the new Xtras
 */
- (void)xtrasChanged:(NSNotification *)notification
{
        NSString *filenameExtension = [notification object];

        //Convert our filename extension into a Uniform Type Identifier so that we can robustly determine what type of Xtra this is.
        CFStringRef type = (CFStringRef)[(NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)filenameExtension, /*inConformingToUTI*/ NULL) autorelease];

        if (!type || UTTypeEqual(type, CFSTR("com.adiumx.emoticonset"))) {
                [self _rebuildEmoticonMenuAndSelectActivePack];
        }
        
        if (!type || UTTypeEqual(type, CFSTR("com.adiumx.dockicon"))) {
                [self configureDockIconMenu];
        }
        
        if (!type || UTTypeEqual(type, CFSTR("com.adiumx.serviceicons"))) {
                [self configureServiceIconsMenu];
        }
        
        if (!type || UTTypeEqual(type, CFSTR("com.adiumx.statusicons"))) {
                [self configureStatusIconsMenu];
        }
        
        if (!type || UTTypeEqual(type, CFSTR("com.adiumx.menubaricons"))) {
                [self configureMenuBarIconsMenu];
        }
        
        if (!type || UTTypeEqual(type, CFSTR("com.adiumx.contactlisttheme"))) {
                [popUp_colorTheme setMenu:[self _colorThemeMenu]];
                [popUp_colorTheme selectItemWithRepresentedObject:[adium.preferenceController preferenceForKey:KEY_LIST_THEME_NAME
                                                                                                                                                                                                   group:PREF_GROUP_APPEARANCE]];
        }

        if (!type || UTTypeEqual(type, CFSTR("com.adiumx.contactlistlayout"))) {
                [popUp_listLayout setMenu:[self _listLayoutMenu]];
                [popUp_listLayout selectItemWithRepresentedObject:[adium.preferenceController preferenceForKey:KEY_LIST_LAYOUT_NAME
                                                                                                                                                                                                   group:PREF_GROUP_APPEARANCE]];
        }
}

/*!
 * @brief Preferences changed
 *
 * Update controls in our view to reflect the changed preferences
 */
- (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key object:(AIListObject *)object
                                        preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
{
        //Emoticons
        if ([group isEqualToString:PREF_GROUP_EMOTICONS] && !firstTime) {
                [self _rebuildEmoticonMenuAndSelectActivePack];
        }
        
        //Appearance
        if ([group isEqualToString:PREF_GROUP_APPEARANCE]) {
                if (firstTime) {
                        [popUp_windowStyle selectItemWithTag:[[prefDict objectForKey:KEY_LIST_LAYOUT_WINDOW_STYLE] integerValue]];      
                        [checkBox_verticalAutosizing setState:[[prefDict objectForKey:KEY_LIST_LAYOUT_VERTICAL_AUTOSIZE] boolValue]];
                        [checkBox_horizontalAutosizing setState:[[prefDict objectForKey:KEY_LIST_LAYOUT_HORIZONTAL_AUTOSIZE] boolValue]];
                        [slider_windowOpacity setDoubleValue:([[prefDict objectForKey:KEY_LIST_LAYOUT_WINDOW_OPACITY] doubleValue] * 100.0)];
                        [slider_horizontalWidth setIntegerValue:[[prefDict objectForKey:KEY_LIST_LAYOUT_HORIZONTAL_WIDTH] integerValue]];
                        [self _updateSliderValues];
                }
                
                //Horizontal resizing label
                if (firstTime || 
                        [key isEqualToString:KEY_LIST_LAYOUT_WINDOW_STYLE] ||
                        [key isEqualToString:KEY_LIST_LAYOUT_HORIZONTAL_AUTOSIZE]) {

                        AIContactListWindowStyle windowStyle = [[prefDict objectForKey:KEY_LIST_LAYOUT_WINDOW_STYLE] integerValue];
                        BOOL horizontalAutosize = [[prefDict objectForKey:KEY_LIST_LAYOUT_HORIZONTAL_AUTOSIZE] boolValue];
                        
                        if (windowStyle == AIContactListWindowStyleStandard) {
                                //In standard mode, disable the horizontal autosizing slider if horiztonal autosizing is off
                                [textField_horizontalWidthText setLocalizedString:AILocalizedString(@"Maximum Width:",nil)];
                                [slider_horizontalWidth setEnabled:horizontalAutosize];
                                
                        } else {
                                //In all the borderless transparent modes, the horizontal autosizing slider becomes the
                                //horizontal sizing slider when autosizing is off
                                if (horizontalAutosize) {
                                        [textField_horizontalWidthText setLocalizedString:AILocalizedString(@"Maximum Width:",nil)];
                                } else {
                                        [textField_horizontalWidthText setLocalizedString:AILocalizedString(@"Width:",nil)];                    
                                }
                                [slider_horizontalWidth setEnabled:YES];
                        }
                        
                        //Configure vertical autosizing's appearance. AIListWindowController must match this behavior for this to make sense.
                        switch (windowStyle) {
                                case AIContactListWindowStyleStandard:
                                case AIContactListWindowStyleBorderless:
                                case AIContactListWindowStyleGroupChat:
                                        //Standard and borderless don't have to vertically autosize
                                        [checkBox_verticalAutosizing setEnabled:YES];
                                        [checkBox_verticalAutosizing setState:[[adium.preferenceController preferenceForKey:KEY_LIST_LAYOUT_VERTICAL_AUTOSIZE
                                                                                                                                                                                                        group:PREF_GROUP_APPEARANCE] integerValue]];
                                        break;
                                case AIContactListWindowStyleGroupBubbles:
                                case AIContactListWindowStyleContactBubbles:
                                case AIContactListWindowStyleContactBubbles_Fitted:
                                        //The bubbles styles don't show a window; force them to autosize
                                        [checkBox_verticalAutosizing setEnabled:NO];
                                        [checkBox_verticalAutosizing setState:YES];
                        }                       
                }

                //Selected menu items
                if (firstTime || [key isEqualToString:KEY_STATUS_ICON_PACK]) {
                        [popUp_statusIcons selectItemWithTitle:[prefDict objectForKey:KEY_STATUS_ICON_PACK]];
                        
                        //If the prefDict's item isn't present, we're using the default, so select that one
                        if (![popUp_statusIcons selectedItem]) {
                                [popUp_statusIcons selectItemWithTitle:[adium.preferenceController defaultPreferenceForKey:KEY_STATUS_ICON_PACK
                                                                                                                                                                                                                group:PREF_GROUP_APPEARANCE
                                                                                                                                                                                                           object:nil]];
                        }                       
                }
                if (firstTime || [key isEqualToString:KEY_SERVICE_ICON_PACK]) {
                        [popUp_serviceIcons selectItemWithTitle:[prefDict objectForKey:KEY_SERVICE_ICON_PACK]];
                        
                        //If the prefDict's item isn't present, we're using the default, so select that one
                        if (![popUp_serviceIcons selectedItem]) {
                                [popUp_serviceIcons selectItemWithTitle:[adium.preferenceController defaultPreferenceForKey:KEY_SERVICE_ICON_PACK
                                                                                                                                                                                                                group:PREF_GROUP_APPEARANCE
                                                                                                                                                                                                           object:nil]];
                        }
                }
                if (firstTime || [key isEqualToString:KEY_MENU_BAR_ICONS]) {
                        [popUp_menuBarIcons selectItemWithTitle:[prefDict objectForKey:KEY_MENU_BAR_ICONS]];
                        
                        //If the prefDict's item isn't present, we're using the default, so select that one
                        if (![popUp_menuBarIcons selectedItem]) {
                                [popUp_menuBarIcons selectItemWithTitle:[adium.preferenceController defaultPreferenceForKey:KEY_MENU_BAR_ICONS
                                                                                                                                                                                                                group:PREF_GROUP_APPEARANCE
                                                                                                                                                                                                           object:nil]];
                        }
                }
                if (firstTime || [key isEqualToString:KEY_LIST_LAYOUT_NAME]) {
                        [popUp_listLayout selectItemWithRepresentedObject:[prefDict objectForKey:KEY_LIST_LAYOUT_NAME]];
                }
                if (firstTime || [key isEqualToString:KEY_LIST_THEME_NAME]) {
                        [popUp_colorTheme selectItemWithRepresentedObject:[prefDict objectForKey:KEY_LIST_THEME_NAME]]; 
                }       
                if (firstTime || [key isEqualToString:KEY_ACTIVE_DOCK_ICON]) {
                        [popUp_dockIcon selectItemWithRepresentedObject:[prefDict objectForKey:KEY_ACTIVE_DOCK_ICON]];
                }
        }
}

/*!
 * @brief Rebuild the emoticon menu
 */
- (void)_rebuildEmoticonMenuAndSelectActivePack
{
        [popUp_emoticons setMenu:[self _emoticonPackMenu]];
        
        //Update the selected pack
        NSArray *activeEmoticonPacks = [adium.emoticonController activeEmoticonPacks];
        NSInteger               numActivePacks = [activeEmoticonPacks count];
        
        if (numActivePacks == 0) {
                [popUp_emoticons selectItemWithTag:AIEmoticonMenuNone];
        } else if (numActivePacks > 1) {
                [popUp_emoticons selectItemWithTag:AIEmoticonMenuMultiple];
        } else {
                [popUp_emoticons selectItemWithRepresentedObject:[activeEmoticonPacks objectAtIndex:0]];
        }
}

/*!
 * @brief Save changed preferences
 */
- (IBAction)changePreference:(id)sender
{
        if (sender == popUp_statusIcons) {
        [adium.preferenceController setPreference:[[sender selectedItem] title]
                                             forKey:KEY_STATUS_ICON_PACK
                                              group:PREF_GROUP_APPEARANCE];
                
        } else if (sender == popUp_serviceIcons) {
        [adium.preferenceController setPreference:[[sender selectedItem] title]
                                             forKey:KEY_SERVICE_ICON_PACK
                                              group:PREF_GROUP_APPEARANCE];
        } else if (sender == popUp_menuBarIcons) {
        [adium.preferenceController setPreference:[[sender selectedItem] title]
                                             forKey:KEY_MENU_BAR_ICONS
                                              group:PREF_GROUP_APPEARANCE];     
        } else if (sender == popUp_dockIcon) {
        [adium.preferenceController setPreference:[[sender selectedItem] representedObject]
                                             forKey:KEY_ACTIVE_DOCK_ICON
                                              group:PREF_GROUP_APPEARANCE];
                
        } else if (sender == popUp_listLayout) {
        [adium.preferenceController setPreference:[[sender selectedItem] title]
                                             forKey:KEY_LIST_LAYOUT_NAME
                                              group:PREF_GROUP_APPEARANCE];             
                
        } else if (sender == popUp_colorTheme) {
                [adium.preferenceController setPreference:[[sender selectedItem] title]
                                                                                         forKey:KEY_LIST_THEME_NAME
                                                                                          group:PREF_GROUP_APPEARANCE];

        } else if (sender == popUp_windowStyle) {
                [adium.preferenceController setPreference:[NSNumber numberWithInteger:[[sender selectedItem] tag]]
                                                                                         forKey:KEY_LIST_LAYOUT_WINDOW_STYLE
                                                                                          group:PREF_GROUP_APPEARANCE];
                
    } else if (sender == checkBox_verticalAutosizing) {
        [adium.preferenceController setPreference:[NSNumber numberWithBool:[sender state]]
                                             forKey:KEY_LIST_LAYOUT_VERTICAL_AUTOSIZE
                                              group:PREF_GROUP_APPEARANCE];
                
    } else if (sender == checkBox_horizontalAutosizing) {
        [adium.preferenceController setPreference:[NSNumber numberWithBool:[sender state]]
                                             forKey:KEY_LIST_LAYOUT_HORIZONTAL_AUTOSIZE
                                              group:PREF_GROUP_APPEARANCE];

    } else if (sender == slider_windowOpacity) {
        [adium.preferenceController setPreference:[NSNumber numberWithDouble:([sender doubleValue] / 100.0)]
                                             forKey:KEY_LIST_LAYOUT_WINDOW_OPACITY
                                              group:PREF_GROUP_APPEARANCE];
                [self _updateSliderValues];
                
        } else if (sender == slider_horizontalWidth) {
                NSInteger newValue = [sender integerValue];
                NSInteger oldValue = [[adium.preferenceController preferenceForKey:KEY_LIST_LAYOUT_HORIZONTAL_WIDTH
                                                                                                                                 group:PREF_GROUP_APPEARANCE] integerValue];
                if (newValue != oldValue) { 
                        [adium.preferenceController setPreference:[NSNumber numberWithInteger:newValue]
                                                                                                 forKey:KEY_LIST_LAYOUT_HORIZONTAL_WIDTH
                                                                                                  group:PREF_GROUP_APPEARANCE];
                        [self _updateSliderValues];
                }
                
        } else if (sender == popUp_emoticons) {
                if ([[sender selectedItem] tag] != AIEmoticonMenuMultiple) {
                        //Disable all active emoticons
                        NSArray                 *activePacks = [[[adium.emoticonController activeEmoticonPacks] mutableCopy] autorelease];
                        AIEmoticonPack  *pack, *selectedPack;
                        
                        selectedPack = [[sender selectedItem] representedObject];
                        
                        [adium.preferenceController delayPreferenceChangedNotifications:YES];

                        for (pack in activePacks) {
                                [adium.emoticonController setEmoticonPack:pack enabled:NO];
                        }
                        
                        //Enable the selected pack
                        if (selectedPack) [adium.emoticonController setEmoticonPack:selectedPack enabled:YES];

                        [adium.preferenceController delayPreferenceChangedNotifications:NO];
                }
        }
}

/*!
 *
 */
- (void)_updateSliderValues
{
        [textField_windowOpacity setStringValue:[NSString stringWithFormat:@"%ld%%", (NSInteger)[slider_windowOpacity doubleValue]]];
        [textField_horizontalWidthIndicator setStringValue:[NSString stringWithFormat:@"%ldpx",[slider_horizontalWidth integerValue]]];
}

//Emoticons ------------------------------------------------------------------------------------------------------------
#pragma mark Emoticons
/*!
 *
 */
- (IBAction)customizeEmoticons:(id)sender
{
        [AIEmoticonPreferences showEmoticionCustomizationOnWindow:[[self view] window]];
}

/*!
 *
 */
- (NSMenu *)_emoticonPackMenu
{
        NSMenu                  *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];
        NSEnumerator    *enumerator = [[adium.emoticonController availableEmoticonPacks] objectEnumerator];
        AIEmoticonPack  *pack;
        NSMenuItem              *menuItem;
                
        //Add the "No Emoticons" option
        menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"None",nil)
                                                                                                                                         target:nil
                                                                                                                                         action:nil
                                                                                                                          keyEquivalent:@""] autorelease];
        [menuItem setImage:[NSImage imageNamed:@"emoticonBlank" forClass:[self class]]];
        [menuItem setTag:AIEmoticonMenuNone];
        [menu addItem:menuItem];
        
        //Add the "Multiple packs selected" option
        if ([[adium.emoticonController activeEmoticonPacks] count] > 1) {
                menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Multiple Packs Selected",nil)
                                                                                                                                                 target:nil
                                                                                                                                                 action:nil
                                                                                                                                  keyEquivalent:@""] autorelease];
                [menuItem setImage:[NSImage imageNamed:@"emoticonBlank" forClass:[self class]]];
                [menuItem setTag:AIEmoticonMenuMultiple];
                [menu addItem:menuItem];
        }

        //Divider
        [menu addItem:[NSMenuItem separatorItem]];

        //Emoticon Packs
        while ((pack = [enumerator nextObject])) {
                menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[pack name]
                                                                                                                                                 target:nil
                                                                                                                                                 action:nil
                                                                                                                                  keyEquivalent:@""] autorelease];
                [menuItem setRepresentedObject:pack];
                [menuItem setImage:[pack menuPreviewImage]];
                [menu addItem:menuItem];
        }

        return [menu autorelease];
}


//Contact list options -------------------------------------------------------------------------------------------------
#pragma mark Contact list options
/*!
 *
 */
- (NSMenu *)_windowStyleMenu
{
        NSMenu  *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];

        [self _addWindowStyleOption:AILocalizedString(@"Regular Window",nil)
                                                withTag:AIContactListWindowStyleStandard
                                                 toMenu:menu];
        [menu addItem:[NSMenuItem separatorItem]];
        [self _addWindowStyleOption:AILocalizedString(@"Borderless Window",nil)
                                                withTag:AIContactListWindowStyleBorderless
                                                 toMenu:menu];
        [self _addWindowStyleOption:AILocalizedString(@"Group Bubbles",nil)
                                                withTag:AIContactListWindowStyleGroupBubbles
                                                 toMenu:menu];
        [self _addWindowStyleOption:AILocalizedString(@"Contact Bubbles",nil)
                                                withTag:AIContactListWindowStyleContactBubbles
                                                 toMenu:menu];
        [self _addWindowStyleOption:AILocalizedString(@"Contact Bubbles (To Fit)",nil)
                                                withTag:AIContactListWindowStyleContactBubbles_Fitted
                                                 toMenu:menu];

        return [menu autorelease];
}
- (void)_addWindowStyleOption:(NSString *)option withTag:(NSInteger)tag toMenu:(NSMenu *)menu{
    NSMenuItem  *menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:option
                                                                                                                                                                  target:nil
                                                                                                                                                                  action:nil
                                                                                                                                                   keyEquivalent:@""] autorelease];
        [menuItem setTag:tag];
        [menu addItem:menuItem];
}


//Contact list layout & theme ----------------------------------------------------------------------------------------
#pragma mark Contact list layout & theme

/*!
 * @brief Create a new theme
 */
- (IBAction)createListTheme:(id)sender
{
        NSString *theme = [adium.preferenceController preferenceForKey:KEY_LIST_THEME_NAME group:PREF_GROUP_APPEARANCE];        
        
        [ESPresetNameSheetController showPresetNameSheetWithDefaultName:[[theme stringByAppendingString:@" "] stringByAppendingString:AILocalizedString(@"(Copy)", nil)]
                                                                                                        explanatoryText:AILocalizedString(@"Enter a unique name for this new theme.",nil)
                                                                                                                   onWindow:[[self view] window]
                                                                                                        notifyingTarget:self
                                                                                                                   userInfo:@"theme"];
}

/*!
 * @brief Customize the active theme
 */
- (IBAction)customizeListTheme:(id)sender
{
        NSString *theme = [adium.preferenceController preferenceForKey:KEY_LIST_THEME_NAME group:PREF_GROUP_APPEARANCE];        
        
        [AIListThemeWindowController editListThemeWithName:theme
                                                                                          onWindow:[[self view] window]
                                                                           notifyingTarget:self];
}

/*!
 * @brief Save (or revert) changes made when editing a theme
 */
- (void)listThemeEditorWillCloseWithChanges:(BOOL)saveChanges forThemeNamed:(NSString *)name
{
        if (saveChanges) {
                //Update the modified theme
                if ([plugin createSetFromPreferenceGroup:PREF_GROUP_LIST_THEME
                                                                                withName:name
                                                                           extension:LIST_THEME_EXTENSION
                                                                                inFolder:LIST_THEME_FOLDER]) {
                        
                        [adium.preferenceController setPreference:name
                                                                                                 forKey:KEY_LIST_THEME_NAME
                                                                                                  group:PREF_GROUP_APPEARANCE];
                }
                
        } else {
                //Revert back to selected theme
                NSString *theme = [adium.preferenceController preferenceForKey:KEY_LIST_THEME_NAME group:PREF_GROUP_APPEARANCE];        
                
                //Reapply the selected theme
                [plugin applySetWithName:theme
                                           extension:LIST_THEME_EXTENSION
                                                inFolder:LIST_THEME_FOLDER
                           toPreferenceGroup:PREF_GROUP_LIST_THEME];
                           
                //Revert back to the current theme name in popUp_colorTheme component
                [popUp_colorTheme selectItemWithTitle:[adium.preferenceController preferenceForKey:KEY_LIST_THEME_NAME group:PREF_GROUP_APPEARANCE]];           
        }
}

/*!
 * @brief Manage available themes
 */
- (void)manageListThemes:(id)sender
{
        _listThemes = [plugin availableThemeSets];
        [ESPresetManagementController managePresets:_listThemes
                                                                         namedByKey:@"name"
                                                                           onWindow:[[self view] window]
                                                                   withDelegate:self];
        
        [popUp_colorTheme selectItemWithRepresentedObject:[adium.preferenceController preferenceForKey:KEY_LIST_THEME_NAME
                                                                                                                                                                                           group:PREF_GROUP_APPEARANCE]];               
}

/*!
 * @brief Create a new layout
 */
- (IBAction)createListLayout:(id)sender
{
        NSString *layout = [adium.preferenceController preferenceForKey:KEY_LIST_LAYOUT_NAME group:PREF_GROUP_APPEARANCE];
        
        [ESPresetNameSheetController showPresetNameSheetWithDefaultName:[[layout stringByAppendingString:@" "] stringByAppendingString:AILocalizedString(@"(Copy)",nil)]
                                                                                                        explanatoryText:AILocalizedString(@"Enter a unique name for this new layout.",nil)
                                                                                                                   onWindow:[[self view] window]
                                                                                                        notifyingTarget:self
                                                                                                                   userInfo:@"layout"];
}

/*!
 * @brief Customize the active layout
 */
- (IBAction)customizeListLayout:(id)sender
{
        NSString *theme = [adium.preferenceController preferenceForKey:KEY_LIST_LAYOUT_NAME group:PREF_GROUP_APPEARANCE];       
        
        [AIListLayoutWindowController editListLayoutWithName:theme
                                                                                          onWindow:[[self view] window]
                                                                           notifyingTarget:self];
}

/*!
 * @brief Save (or revert) changes made when editing a layout
 */
- (void)listLayoutEditorWillCloseWithChanges:(BOOL)saveChanges forLayoutNamed:(NSString *)name
{
        if (saveChanges) {
                //Update the modified layout
                if ([plugin createSetFromPreferenceGroup:PREF_GROUP_LIST_LAYOUT
                                                                                withName:name
                                                                           extension:LIST_LAYOUT_EXTENSION
                                                                                inFolder:LIST_LAYOUT_FOLDER]) {
                        
                        [adium.preferenceController setPreference:name
                                                                                                 forKey:KEY_LIST_LAYOUT_NAME
                                                                                                  group:PREF_GROUP_APPEARANCE];
                }
                
        } else {
                //Revert back to selected layout
                NSString *layout = [adium.preferenceController preferenceForKey:KEY_LIST_LAYOUT_NAME group:PREF_GROUP_APPEARANCE];      

                //Reapply the selected layout
                [plugin applySetWithName:layout
                                           extension:LIST_LAYOUT_EXTENSION
                                                inFolder:LIST_LAYOUT_FOLDER
                           toPreferenceGroup:PREF_GROUP_LIST_LAYOUT];
                           
                //Revert back to the current layout name in popUp_listLayout component
                [popUp_listLayout selectItemWithTitle:[adium.preferenceController preferenceForKey:KEY_LIST_LAYOUT_NAME group:PREF_GROUP_APPEARANCE]];
        }
}

/*!
 * @brief Manage available layouts
 */
- (void)manageListLayouts:(id)sender
{
        _listLayouts = [plugin availableLayoutSets];
        [ESPresetManagementController managePresets:_listLayouts
                                                                         namedByKey:@"name"
                                                                           onWindow:[[self view] window]
                                                                   withDelegate:self];

        [popUp_listLayout selectItemWithRepresentedObject:[adium.preferenceController preferenceForKey:KEY_LIST_LAYOUT_NAME
                                                                                                                                                                                           group:PREF_GROUP_APPEARANCE]];               
}

/*!
 * @brief Validate a layout or theme name to ensure it is unique
 */
- (BOOL)presetNameSheetController:(ESPresetNameSheetController *)controller
                          shouldAcceptNewName:(NSString *)newName
                                                 userInfo:(id)userInfo
{
        NSEnumerator    *enumerator;
        NSDictionary    *presetDict;

        //Scan the correct presets to ensure this name doesn't already exist
        if ([userInfo isEqualToString:@"theme"]) {
                enumerator = [[plugin availableThemeSets] objectEnumerator];
        } else {
                enumerator = [[plugin availableLayoutSets] objectEnumerator];
        }
        
        while ((presetDict = [enumerator nextObject])) {
                if ([newName isEqualToString:[presetDict objectForKey:@"name"]]) return NO;
        }
        
        return YES;
}

/*!
 * @brief Create a new theme with the user supplied name, activate and edit it
 */
- (void)presetNameSheetControllerDidEnd:(ESPresetNameSheetController *)controller 
                                                         returnCode:(ESPresetNameSheetReturnCode)returnCode
                                                                newName:(NSString *)newName
                                                           userInfo:(id)userInfo
{
        switch (returnCode) {
                case ESPresetNameSheetOkayReturn:
                        //User has created a new theme/layout   : show the editor
                        if ([userInfo isEqualToString:@"theme"]) {
                                [self performSelector:@selector(_editListThemeWithName:) withObject:newName afterDelay:0];
                        } else {
                                [self performSelector:@selector(_editListLayoutWithName:) withObject:newName afterDelay:0];
                        }
                break;
                        
                case ESPresetNameSheetCancelReturn:
                        //User has canceled the operation       : revert back to the current theme 
                        if ([userInfo isEqualToString:@"theme"]) {
                                [popUp_colorTheme selectItemWithTitle:[adium.preferenceController preferenceForKey:KEY_LIST_THEME_NAME group:PREF_GROUP_APPEARANCE]];
                        } else {
                                [popUp_listLayout selectItemWithTitle:[adium.preferenceController preferenceForKey:KEY_LIST_LAYOUT_NAME group:PREF_GROUP_APPEARANCE]];
                        }                       
                break;  
        }
}
- (void)_editListThemeWithName:(NSString *)name{
        [AIListThemeWindowController editListThemeWithName:name
                                                                                          onWindow:[[self view] window]
                                                                           notifyingTarget:self];
}
- (void)_editListLayoutWithName:(NSString *)name{
        [AIListLayoutWindowController editListLayoutWithName:name
                                                                                                onWindow:[[self view] window]
                                                                                 notifyingTarget:self];
}

/*!
 * 
 */
- (NSArray *)renamePreset:(NSDictionary *)preset toName:(NSString *)newName inPresets:(NSArray *)presets renamedPreset:(id *)renamedPreset
{
        NSArray         *newPresets;
        
        if (presets == _listLayouts) {
                [plugin renameSetWithName:[preset objectForKey:@"name"]
                                                extension:LIST_LAYOUT_EXTENSION
                                                 inFolder:LIST_LAYOUT_FOLDER
                                                   toName:newName];             
                _listLayouts = [plugin availableLayoutSets];
                newPresets = _listLayouts;
                
        } else if (presets == _listThemes) {
                [plugin renameSetWithName:[preset objectForKey:@"name"]
                                                extension:LIST_THEME_EXTENSION
                                                 inFolder:LIST_THEME_FOLDER
                                                   toName:newName];             
                _listThemes = [plugin availableThemeSets];
                newPresets = _listThemes;
                
        } else {
                newPresets = nil;
        }
        
        //Return the new duplicate by reference for the preset controller
        if (renamedPreset) {
                NSDictionary    *aPreset;
                
                for (aPreset in newPresets) {
                        if ([newName isEqualToString:[aPreset objectForKey:@"name"]]) {
                                *renamedPreset = aPreset;
                                break;
                        }
                }
        }
        
        return newPresets;
}

/*!
 * 
 */
- (NSArray *)duplicatePreset:(NSDictionary *)preset inPresets:(NSArray *)presets createdDuplicate:(id *)duplicatePreset
{
        NSString        *newName = [NSString stringWithFormat:@"%@ (%@)", [preset objectForKey:@"name"], AILocalizedString(@"Copy",nil)];
        NSArray         *newPresets = nil;
        
        if (presets == _listLayouts) {
                [plugin duplicateSetWithName:[preset objectForKey:@"name"]
                                                   extension:LIST_LAYOUT_EXTENSION
                                                        inFolder:LIST_LAYOUT_FOLDER
                                                         newName:newName];              
                _listLayouts = [plugin availableLayoutSets];
                newPresets = _listLayouts;
                
        } else if (presets == _listThemes) {
                [plugin duplicateSetWithName:[preset objectForKey:@"name"]
                                                   extension:LIST_THEME_EXTENSION
                                                        inFolder:LIST_THEME_FOLDER
                                                         newName:newName];
                _listThemes = [plugin availableThemeSets];
                newPresets = _listThemes;
        }
        
        //Return the new duplicate by reference for the preset controller
        if (duplicatePreset) {
                NSDictionary    *aPreset;
                
                for (aPreset in newPresets) {
                        if ([newName isEqualToString:[aPreset objectForKey:@"name"]]) {
                                *duplicatePreset = aPreset;
                                break;
                        }
                }
        }

        return newPresets;
}

/*!
 * 
 */
- (NSArray *)deletePreset:(NSDictionary *)preset inPresets:(NSArray *)presets
{
        if (presets == _listLayouts) {
                [plugin deleteSetWithName:[preset objectForKey:@"name"]
                                                extension:LIST_LAYOUT_EXTENSION
                                                 inFolder:LIST_LAYOUT_FOLDER];          
                _listLayouts = [plugin availableLayoutSets];
                
                return _listLayouts;
                
        } else if (presets == _listThemes) {
                [plugin deleteSetWithName:[preset objectForKey:@"name"]
                                                extension:LIST_THEME_EXTENSION
                                                 inFolder:LIST_THEME_FOLDER];           
                _listThemes = [plugin availableThemeSets];
                
                return _listThemes;
                
        } else {
                return nil;
        }
}

/*!
 *
 */
- (NSMenu *)_listLayoutMenu
{
        NSMenu                  *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];
        NSEnumerator    *enumerator = [[plugin availableLayoutSets] objectEnumerator];
        NSDictionary    *set;
        NSMenuItem              *menuItem;
        NSString                *name;
        
        //Available Layouts
        while ((set = [enumerator nextObject])) {
                name = [set objectForKey:@"name"];
                menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:name
                                                                                                                                                 target:nil
                                                                                                                                                 action:nil
                                                                                                                                  keyEquivalent:@""] autorelease];
                [menuItem setRepresentedObject:name];
                [menu addItem:menuItem];
        }
        
        //Divider
        [menu addItem:[NSMenuItem separatorItem]];

        //Preset management     
        menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[AILocalizedString(@"Add New Layout",nil) stringByAppendingEllipsis]
                                                                                                                                         target:self
                                                                                                                                         action:@selector(createListLayout:)
                                                                                                                          keyEquivalent:@""] autorelease];
        [menu addItem:menuItem];
        
        menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[AILocalizedString(@"Edit Layouts",nil) stringByAppendingEllipsis]
                                                                                                                                         target:self
                                                                                                                                         action:@selector(manageListLayouts:)
                                                                                                                          keyEquivalent:@""] autorelease];
        [menu addItem:menuItem];
        
        return [menu autorelease];      
}

/*!
 *
 */
- (NSMenu *)_colorThemeMenu
{
        NSMenu                  *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];
        NSEnumerator    *enumerator = [[plugin availableThemeSets] objectEnumerator];
        NSDictionary    *set;
        NSMenuItem              *menuItem;
        NSString                *name;
        
        //Available themes
        while ((set = [enumerator nextObject])) {
                name = [set objectForKey:@"name"];
                menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:name
                                                                                                                                                 target:nil
                                                                                                                                                 action:nil
                                                                                                                                  keyEquivalent:@""] autorelease];
                [menuItem setRepresentedObject:name];
                [menu addItem:menuItem];
        }

        //Divider
        [menu addItem:[NSMenuItem separatorItem]];
        
        //Preset management     
        menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[AILocalizedString(@"Add New Theme",nil) stringByAppendingEllipsis]
                                                                                                                                         target:self
                                                                                                                                         action:@selector(createListTheme:)
                                                                                                                          keyEquivalent:@""] autorelease];
        [menu addItem:menuItem];
        
        menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[AILocalizedString(@"Edit Themes",nil) stringByAppendingEllipsis]
                                                                                                                                         target:self
                                                                                                                                         action:@selector(manageListThemes:)
                                                                                                                          keyEquivalent:@""] autorelease];
        [menu addItem:menuItem];
        
        return [menu autorelease];      
}


//Dock icons -----------------------------------------------------------------------------------------------------------
#pragma mark Dock icons
/*!
 *
 */
- (IBAction)showAllDockIcons:(id)sender
{
        [AIDockIconSelectionSheet showDockIconSelectorOnWindow:[[self view] window]];
}

/*!
 * @brief Return the menu item for a dock icon
 */
- (NSMenuItem *)meuItemForDockIconPackAtPath:(NSString *)packPath
{
        NSMenuItem      *menuItem;
        NSString        *name = nil;
        NSString        *packName = [[packPath lastPathComponent] stringByDeletingPathExtension];
        AIIconState     *preview = nil;
        
        [adium.dockController getName:&name
                                           previewState:&preview
                                  forIconPackAtPath:packPath];
        
        if (!name) {
                name = packName;
        }
        
        menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:name
                                                                                                                                         target:nil
                                                                                                                                         action:nil
                                                                                                                          keyEquivalent:@""] autorelease];
        [menuItem setRepresentedObject:packName];
        [menuItem setImage:[[preview image] imageByScalingForMenuItem]];
        
        return menuItem;
}

/*!
 * @brief Returns an array of menu items of all dock icon packs
 */
- (NSArray *)_dockIconMenuArray
{
        NSMutableArray          *menuItemArray = [NSMutableArray array];
        NSEnumerator            *enumerator;
        NSString                        *packPath;

        enumerator = [[adium.dockController availableDockIconPacks] objectEnumerator];
        while ((packPath = [enumerator nextObject])) {
                [menuItemArray addObject:[self meuItemForDockIconPackAtPath:packPath]];
        }

        [menuItemArray sortUsingSelector:@selector(titleCompare:)];

        return menuItemArray;
}

/*!
 * @brief Configure the dock icon meu initially or after the xtras change
 *
 * Initially, the dock icon menu just has the currently selected icon; the others will be generated lazily if the icon is displayed, in menuNeedsUpdate:
 */
- (void)configureDockIconMenu
{
        NSMenu          *tempMenu = [[[NSMenu allocWithZone:[NSMenu menuZone]] init] autorelease];
        NSString        *iconPath;
        NSString        *activePackName = [adium.preferenceController preferenceForKey:KEY_ACTIVE_DOCK_ICON
                                                                                                                                                   group:PREF_GROUP_APPEARANCE];
        iconPath = [adium pathOfPackWithName:activePackName
                                                           extension:@"AdiumIcon"
                                          resourceFolderName:FOLDER_DOCK_ICONS];
        
        [tempMenu addItem:[self meuItemForDockIconPackAtPath:iconPath]];
        [tempMenu setDelegate:self];
        [tempMenu setTitle:@"Temporary Dock Icon Menu"];

        [popUp_dockIcon setMenu:tempMenu];
        [popUp_dockIcon selectItemWithRepresentedObject:activePackName];
}

//Status, Service and Menu Bar icons ---------------------------------------------------------------------------------------------
#pragma mark Status, service and menu bar icons
- (NSMenuItem *)menuItemForIconPackAtPath:(NSString *)packPath class:(Class)iconClass
{
        NSString        *name = [[packPath lastPathComponent] stringByDeletingPathExtension];
        NSMenuItem      *menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:name
                                                                                                                                                                  target:nil
                                                                                                                                                                  action:nil
                                                                                                                                                   keyEquivalent:@""] autorelease];
        [menuItem setRepresentedObject:name];
        [menuItem setImage:[iconClass previewMenuImageForIconPackAtPath:packPath]];     

        return menuItem;
}

/*!
 * @brief Builds and returns an icon pack menu
 *
 * @param packs NSArray of icon pack file paths
 * @param iconClass The controller class (AIStatusIcons, AIServiceIcons) for icon pack previews
 */
- (NSArray *)_iconPackMenuArrayForPacks:(NSArray *)packs class:(Class)iconClass
{
        NSMutableArray  *menuItemArray = [NSMutableArray array];
        NSString                *packPath;

        for (packPath in packs) {
                [menuItemArray addObject:[self menuItemForIconPackAtPath:packPath class:iconClass]];
        }
        
        [menuItemArray sortUsingSelector:@selector(titleCompare:)];

        return menuItemArray;   
}

- (void)configureStatusIconsMenu
{
        NSMenu          *tempMenu = [[[NSMenu allocWithZone:[NSMenu menuZone]] init] autorelease];
        NSString        *iconPath;
        NSString        *activePackName = [adium.preferenceController preferenceForKey:KEY_STATUS_ICON_PACK
                                                                                                                                                   group:PREF_GROUP_APPEARANCE];
        iconPath = [adium pathOfPackWithName:activePackName
                                                           extension:@"AdiumStatusIcons"
                                          resourceFolderName:@"Status Icons"];
        
        if (!iconPath) {
                activePackName = [adium.preferenceController defaultPreferenceForKey:KEY_STATUS_ICON_PACK
                                                                                                                                                 group:PREF_GROUP_APPEARANCE
                                                                                                                                                object:nil];
                
                iconPath = [adium pathOfPackWithName:activePackName
                                                                   extension:@"AdiumStatusIcons"
                                                  resourceFolderName:@"Status Icons"];          
        }
        [tempMenu addItem:[self menuItemForIconPackAtPath:iconPath class:[AIStatusIcons class]]];
        [tempMenu setDelegate:self];
        [tempMenu setTitle:@"Temporary Status Icons Menu"];
        
        [popUp_statusIcons setMenu:tempMenu];
        [popUp_statusIcons selectItemWithRepresentedObject:activePackName];
}

- (void)configureServiceIconsMenu
{
        NSMenu          *tempMenu = [[[NSMenu allocWithZone:[NSMenu menuZone]] init] autorelease];
        NSString        *iconPath;
        NSString        *activePackName = [adium.preferenceController preferenceForKey:KEY_SERVICE_ICON_PACK
                                                                                                                                                   group:PREF_GROUP_APPEARANCE];
        iconPath = [adium pathOfPackWithName:activePackName
                                                           extension:@"AdiumServiceIcons"
                                          resourceFolderName:@"Service Icons"];
        
        if (!iconPath) {
                activePackName = [adium.preferenceController defaultPreferenceForKey:KEY_SERVICE_ICON_PACK
                                                                                                                                                 group:PREF_GROUP_APPEARANCE
                                                                                                                                                object:nil];
                
                iconPath = [adium pathOfPackWithName:activePackName
                                                                   extension:@"AdiumServiceIcons"
                                                  resourceFolderName:@"Service Icons"];         
        }
        [tempMenu addItem:[self menuItemForIconPackAtPath:iconPath class:[AIServiceIcons class]]];
        [tempMenu setDelegate:self];
        [tempMenu setTitle:@"Temporary Service Icons Menu"];
        
        [popUp_serviceIcons setMenu:tempMenu];
        [popUp_serviceIcons selectItemWithRepresentedObject:activePackName];
}

- (void)configureMenuBarIconsMenu
{
        NSMenu          *tempMenu = [[[NSMenu allocWithZone:[NSMenu menuZone]] init] autorelease];
        NSString        *iconPath;
        NSString        *activePackName = [adium.preferenceController preferenceForKey:KEY_MENU_BAR_ICONS
                                                                                                                                                   group:PREF_GROUP_APPEARANCE];
        iconPath = [adium pathOfPackWithName:activePackName
                                                           extension:@"AdiumMenuBarIcons"
                                          resourceFolderName:@"Menu Bar Icons"];
        
        if (!iconPath) {
                activePackName = [adium.preferenceController defaultPreferenceForKey:KEY_MENU_BAR_ICONS
                                                                                                                                                 group:PREF_GROUP_APPEARANCE
                                                                                                                                                object:nil];
                
                iconPath = [adium pathOfPackWithName:activePackName
                                                                   extension:@"AdiumMenuBarIcons"
                                                  resourceFolderName:@"Menu Bar Icons"];                
        }
        [tempMenu addItem:[self menuItemForIconPackAtPath:iconPath class:[AIMenuBarIcons class]]];
        [tempMenu setDelegate:self];
        [tempMenu setTitle:@"Temporary Menu Bar Icons Menu"];
        
        [popUp_menuBarIcons setMenu:tempMenu];
        [popUp_menuBarIcons selectItemWithRepresentedObject:activePackName];
}

#pragma mark Menu delegate
- (void)menuNeedsUpdate:(NSMenu *)menu
{
        NSString                *title =[menu title];
        NSString                *repObject = nil;
        NSArray                 *menuItemArray = nil;
        NSPopUpButton   *popUpButton;
        
        if ([title isEqualToString:@"Temporary Dock Icon Menu"]) {
                //If the menu has @"Temporary Dock Icon Menu" as its title, we should update it to have all dock icons, not just our selected one
                menuItemArray = [self _dockIconMenuArray];
                repObject = [adium.preferenceController preferenceForKey:KEY_ACTIVE_DOCK_ICON
                                                                                                                         group:PREF_GROUP_APPEARANCE];
                popUpButton = popUp_dockIcon;
                
        } else if ([title isEqualToString:@"Temporary Status Icons Menu"]) {            
                menuItemArray = [self _iconPackMenuArrayForPacks:[adium allResourcesForName:@"Status Icons" 
                                                                                                                                         withExtensions:@"AdiumStatusIcons"] 
                                                                                                   class:[AIStatusIcons class]];
                repObject = [adium.preferenceController preferenceForKey:KEY_STATUS_ICON_PACK
                                                                                                                         group:PREF_GROUP_APPEARANCE];
                popUpButton = popUp_statusIcons;
                
        } else if ([title isEqualToString:@"Temporary Service Icons Menu"]) {           
                menuItemArray = [self _iconPackMenuArrayForPacks:[adium allResourcesForName:@"Service Icons" 
                                                                                                                                         withExtensions:@"AdiumServiceIcons"] 
                                                                                                   class:[AIServiceIcons class]];
                repObject = [adium.preferenceController preferenceForKey:KEY_SERVICE_ICON_PACK
                                                                                                                         group:PREF_GROUP_APPEARANCE];
                popUpButton = popUp_serviceIcons;
                
        } else if ([title isEqualToString:@"Temporary Menu Bar Icons Menu"]) {
                menuItemArray = [self _iconPackMenuArrayForPacks:[adium allResourcesForName:@"Menu Bar Icons" 
                                                                                                                                         withExtensions:@"AdiumMenuBarIcons"] 
                                                                                                   class:[AIMenuBarIcons class]];
                repObject = [adium.preferenceController preferenceForKey:KEY_MENU_BAR_ICONS
                                                                                                                         group:PREF_GROUP_APPEARANCE];
                popUpButton = popUp_menuBarIcons;       
        }
        
        if (menuItemArray) {
                NSMenuItem              *menuItem;
                
                //Remove existing items
                [menu removeAllItems];
                
                //Clear the title so we know we don't need to do this again
                [menu setTitle:@""];
                
                //Add the items
                for (menuItem in menuItemArray) {
                        [menu addItem:menuItem];
                }
                
                //Clear the title so we know we don't need to do this again
                [menu setTitle:@""];
                
                //Put a checkmark by the appropriate menu item
                [popUpButton selectItemWithRepresentedObject:repObject];
        }       
}

@end