1 #import "PreferencesController.h"
2 #import "MainController.h"
3 #import "HotKeyCenter.h"
4 #import <ITKit/ITWindowPositioning.h>
6 #define SENDER_STATE (([sender state] == NSOnState) ? YES : NO)
8 /*************************************************************************/
10 #pragma mark PRIVATE INTERFACE
11 /*************************************************************************/
13 @interface PreferencesController (Private)
15 - (void)setupCustomizationTables;
16 - (void)setupMenuItems;
18 - (IBAction)changeMenus:(id)sender;
19 - (void)setLaunchesAtLogin:(BOOL)flag;
23 @implementation PreferencesController
26 /*************************************************************************/
28 #pragma mark STATIC VARIABLES
29 /*************************************************************************/
31 static PreferencesController *prefs = nil;
34 /*************************************************************************/
36 #pragma mark INITIALIZATION METHODS
37 /*************************************************************************/
39 + (PreferencesController *)sharedPrefs;
42 prefs = [[self alloc] init];
49 if ( (self = [super init]) ) {
50 df = [[NSUserDefaults standardUserDefaults] retain];
57 /*************************************************************************/
59 #pragma mark ACCESSOR METHODS
60 /*************************************************************************/
67 - (void)setController:(id)object
69 [controller autorelease];
70 controller = [object retain];
74 /*************************************************************************/
76 #pragma mark INSTANCE METHODS
77 /*************************************************************************/
79 - (IBAction)showPrefsWindow:(id)sender
81 if (! window) { // If window does not exist yet, then the nib hasn't been loaded.
82 [self setupWindow]; // Load in the nib, and perform any initial setup.
83 [self setupCustomizationTables]; // Setup the DnD manu config tables.
84 [self setupMenuItems]; // Setup the arrays of menu items
85 [self setupUI]; // Sets up additional UI
86 [window setDelegate:self];
89 [window setLevel:NSStatusWindowLevel];
91 [window makeKeyAndOrderFront:self];
92 [NSApp activateIgnoringOtherApps:YES];
95 - (IBAction)changeGeneralSetting:(id)sender
97 BOOL rebuildRequired = NO;
99 if ( [sender tag] == 1010) {
100 [self setLaunchesAtLogin:SENDER_STATE];
101 } else if ( [sender tag] == 1020) {
102 [df setBool:SENDER_STATE forKey:@"LaunchPlayerWithMT"];
103 } else if ( [sender tag] == 1030) {
104 [df setInteger:[sender intValue] forKey:@"SongsInAdvance"];
105 rebuildRequired = YES;
106 } else if ( [sender tag] == 1040) {
107 // This will not be executed. Song info always shows the title of the song.
108 // [df setBool:SENDER_STATE forKey:@"showName"];
109 // rebuildRequired = YES;
110 } else if ( [sender tag] == 1050) {
111 [df setBool:SENDER_STATE forKey:@"showArtist"];
112 rebuildRequired = YES;
113 } else if ( [sender tag] == 1060) {
114 [df setBool:SENDER_STATE forKey:@"showAlbum"];
115 rebuildRequired = YES;
116 } else if ( [sender tag] == 1070) {
117 [df setBool:SENDER_STATE forKey:@"showTime"];
118 rebuildRequired = YES;
119 } else if ( [sender tag] == 1080) {
120 [df setBool:SENDER_STATE forKey:@"showTrackNumber"];
121 rebuildRequired = YES;
122 } else if ( [sender tag] == 1090) {
123 [df setBool:SENDER_STATE forKey:@"showTrackRating"];
124 rebuildRequired = YES;
127 if ( rebuildRequired ) {
128 [controller rebuildMenu];
129 // redraw song info status window, or upcoming songs here
135 - (IBAction)changeStatusWindowSetting:(id)sender
137 if ( [sender tag] == 2010) {
138 [df setInteger:[sender selectedRow] forKey:@"statusWindowVerticalPosition"];
139 [df setInteger:[sender selectedColumn] forKey:@"statusWindowHorizontalPosition"];
140 // update the window's position here
141 } else if ( [sender tag] == 2020) {
142 // update screen selection
143 } else if ( [sender tag] == 2030) {
144 // Update appearance effect
145 } else if ( [sender tag] == 2040) {
146 // Update Vanish Effect
147 } else if ( [sender tag] == 2050) {
148 // Update appearance speed
149 } else if ( [sender tag] == 2060) {
150 // Update vanish speed
151 } else if ( [sender tag] == 2070) {
152 // Update vanish delay
153 } else if ( [sender tag] == 2080) {
154 // Update "Song Info window when song changes" setting.
158 - (IBAction)changeHotKey:(id)sender
160 switch ([sender tag])
163 [self setKeyCombo:playPauseCombo];
164 [self setHotKey:@"PlayPause"];
167 [self setKeyCombo:nextTrackCombo];
168 [self setHotKey:@"NextTrack"];
171 [self setKeyCombo:prevTrackCombo];
172 [self setHotKey:@"PrevTrack"];
175 [self setKeyCombo:toggleLoopCombo];
176 [self setHotKey:@"ToggleLoop"];
179 [self setKeyCombo:toggleShuffleCombo];
180 [self setHotKey:@"ToggleShuffle"];
183 [self setKeyCombo:trackInfoCombo];
184 [self setHotKey:@"TrackInfo"];
187 [self setKeyCombo:upcomingSongsCombo];
188 [self setHotKey:@"UpcomingSongs"];
191 [self setKeyCombo:volumeIncrementCombo];
192 [self setHotKey:@"IncrementVolume"];
195 [self setKeyCombo:volumeDecrementCombo];
196 [self setHotKey:@"DecrementVolume"];
199 [self setKeyCombo:ratingIncrementCombo];
200 [self setHotKey:@"IncrementRating"];
203 [self setKeyCombo:ratingDecrementCombo];
204 [self setHotKey:@"DecrementRating"];
209 - (void)registerDefaults
212 NSMutableDictionary *loginWindow;
213 NSMutableArray *loginArray;
214 NSEnumerator *loginEnum;
217 [df setObject:[NSArray arrayWithObjects:
232 @"Current Track Info",
233 nil] forKey:@"menu"];
235 [df setInteger:5 forKey:@"SongsInAdvance"];
236 // [df setBool:YES forKey:@"showName"]; // Song info will always show song title.
237 [df setBool:YES forKey:@"showArtist"];
238 [df setBool:NO forKey:@"showAlbum"];
239 [df setBool:NO forKey:@"showTime"];
243 loginWindow = [[df persistentDomainForName:@"loginwindow"] mutableCopy];
244 loginArray = [loginWindow objectForKey:@"AutoLaunchedApplicationDictionary"];
245 loginEnum = [loginArray objectEnumerator];
247 while ( (anItem = [loginEnum nextObject]) ) {
248 if ( [[[anItem objectForKey:@"Path"] lastPathComponent] isEqualToString:[[[NSBundle mainBundle] bundlePath] lastPathComponent]] ) {
253 [loginWindow release];
256 // We must fix it so it is no longer suxy
258 if (NSRunInformationalAlertPanel(@"Auto-launch MenuTunes", @"Would you like MenuTunes to automatically launch at login?", @"Yes", @"No", nil) == NSOKButton) {
259 AEDesc scriptDesc, resultDesc;
260 NSString *script = [NSString stringWithFormat:@"tell application \"System Events\"\nmake new login item at end of login items with properties {path:\"%@\", kind:\"APPLICATION\"}\nend tell", [[NSBundle mainBundle] bundlePath]];
261 ComponentInstance asComponent = OpenDefaultComponent(kOSAComponentType, kAppleScriptSubtype);
263 AECreateDesc(typeChar, [script cString], [script cStringLength],
266 OSADoScript(asComponent, &scriptDesc, kOSANullScript, typeChar, kOSAModeCanInteract, &resultDesc);
268 AEDisposeDesc(&scriptDesc);
269 AEDisposeDesc(&resultDesc);
271 CloseComponent(asComponent);
276 - (IBAction)cancelHotKey:(id)sender
278 [[NSNotificationCenter defaultCenter] removeObserver:self];
279 [NSApp endSheet:keyComboPanel];
280 [keyComboPanel orderOut:nil];
283 - (IBAction)clearHotKey:(id)sender
285 [self setKeyCombo:[KeyCombo clearKeyCombo]];
288 - (IBAction)okHotKey:(id)sender
290 NSString *string = [combo userDisplayRep];
295 if ([setHotKey isEqualToString:@"PlayPause"]) {
296 if (([combo isEqual:nextTrackCombo] || [combo isEqual:prevTrackCombo] ||
297 [combo isEqual:trackInfoCombo] || [combo isEqual:upcomingSongsCombo] ||
298 [combo isEqual:ratingIncrementCombo] || [combo isEqual:ratingDecrementCombo] ||
299 [combo isEqual:volumeIncrementCombo] || [combo isEqual:volumeDecrementCombo] ||
300 [combo isEqual:toggleLoopCombo] || [combo isEqual:toggleShuffleCombo]) &&
301 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
303 [window setLevel:NSNormalWindowLevel];
304 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
305 [window setLevel:NSStatusWindowLevel];
308 playPauseCombo = [combo copy];
309 [playPauseButton setTitle:string];
310 } else if ([setHotKey isEqualToString:@"NextTrack"]) {
311 if (([combo isEqual:playPauseCombo] || [combo isEqual:prevTrackCombo] ||
312 [combo isEqual:trackInfoCombo] || [combo isEqual:upcomingSongsCombo] ||
313 [combo isEqual:ratingIncrementCombo] || [combo isEqual:ratingDecrementCombo] ||
314 [combo isEqual:volumeIncrementCombo] || [combo isEqual:volumeDecrementCombo] ||
315 [combo isEqual:toggleLoopCombo] || [combo isEqual:toggleShuffleCombo]) &&
316 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
318 [window setLevel:NSNormalWindowLevel];
319 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
320 [window setLevel:NSStatusWindowLevel];
323 nextTrackCombo = [combo copy];
324 [nextTrackButton setTitle:string];
325 } else if ([setHotKey isEqualToString:@"PrevTrack"]) {
326 if (([combo isEqual:nextTrackCombo] || [combo isEqual:playPauseCombo] ||
327 [combo isEqual:trackInfoCombo] || [combo isEqual:upcomingSongsCombo] ||
328 [combo isEqual:ratingIncrementCombo] || [combo isEqual:ratingDecrementCombo] ||
329 [combo isEqual:volumeIncrementCombo] || [combo isEqual:volumeDecrementCombo] ||
330 [combo isEqual:toggleLoopCombo] || [combo isEqual:toggleShuffleCombo]) &&
331 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
333 [window setLevel:NSNormalWindowLevel];
334 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
335 [window setLevel:NSStatusWindowLevel];
338 prevTrackCombo = [combo copy];
339 [previousTrackButton setTitle:string];
340 } else if ([setHotKey isEqualToString:@"TrackInfo"]) {
341 if (([combo isEqual:nextTrackCombo] || [combo isEqual:prevTrackCombo] ||
342 [combo isEqual:playPauseCombo] || [combo isEqual:upcomingSongsCombo] ||
343 [combo isEqual:ratingIncrementCombo] || [combo isEqual:ratingDecrementCombo] ||
344 [combo isEqual:volumeIncrementCombo] || [combo isEqual:volumeDecrementCombo] ||
345 [combo isEqual:toggleLoopCombo] || [combo isEqual:toggleShuffleCombo]) &&
346 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
348 [window setLevel:NSNormalWindowLevel];
349 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
350 [window setLevel:NSStatusWindowLevel];
353 trackInfoCombo = [combo copy];
354 [trackInfoButton setTitle:string];
355 } else if ([setHotKey isEqualToString:@"UpcomingSongs"]) {
356 if (([combo isEqual:nextTrackCombo] || [combo isEqual:prevTrackCombo] ||
357 [combo isEqual:trackInfoCombo] || [combo isEqual:playPauseCombo] ||
358 [combo isEqual:ratingIncrementCombo] || [combo isEqual:ratingDecrementCombo] ||
359 [combo isEqual:volumeIncrementCombo] || [combo isEqual:volumeDecrementCombo] ||
360 [combo isEqual:toggleLoopCombo] || [combo isEqual:toggleShuffleCombo]) &&
361 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
363 [window setLevel:NSNormalWindowLevel];
364 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
365 [window setLevel:NSStatusWindowLevel];
368 upcomingSongsCombo = [combo copy];
369 [upcomingSongsButton setTitle:string];
371 } else if ([setHotKey isEqualToString:@"IncrementVolume"]) {
372 if (([combo isEqual:nextTrackCombo] || [combo isEqual:prevTrackCombo] ||
373 [combo isEqual:trackInfoCombo] || [combo isEqual:playPauseCombo] ||
374 [combo isEqual:ratingIncrementCombo] || [combo isEqual:ratingDecrementCombo] ||
375 [combo isEqual:upcomingSongsCombo] || [combo isEqual:volumeDecrementCombo] ||
376 [combo isEqual:toggleLoopCombo] || [combo isEqual:toggleShuffleCombo]) &&
377 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
379 [window setLevel:NSNormalWindowLevel];
380 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
381 [window setLevel:NSStatusWindowLevel];
384 volumeIncrementCombo = [combo copy];
385 [volumeIncrementButton setTitle:string];
386 } else if ([setHotKey isEqualToString:@"DecrementVolume"]) {
387 if (([combo isEqual:nextTrackCombo] || [combo isEqual:prevTrackCombo] ||
388 [combo isEqual:trackInfoCombo] || [combo isEqual:playPauseCombo] ||
389 [combo isEqual:ratingIncrementCombo] || [combo isEqual:ratingDecrementCombo] ||
390 [combo isEqual:volumeIncrementCombo] || [combo isEqual:upcomingSongsCombo] ||
391 [combo isEqual:toggleLoopCombo] || [combo isEqual:toggleShuffleCombo]) &&
392 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
394 [window setLevel:NSNormalWindowLevel];
395 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
396 [window setLevel:NSStatusWindowLevel];
399 volumeDecrementCombo = [combo copy];
400 [volumeDecrementButton setTitle:string];
401 } else if ([setHotKey isEqualToString:@"IncrementRating"]) {
402 if (([combo isEqual:nextTrackCombo] || [combo isEqual:prevTrackCombo] ||
403 [combo isEqual:trackInfoCombo] || [combo isEqual:playPauseCombo] ||
404 [combo isEqual:upcomingSongsCombo] || [combo isEqual:ratingDecrementCombo] ||
405 [combo isEqual:volumeIncrementCombo] || [combo isEqual:volumeDecrementCombo] ||
406 [combo isEqual:toggleLoopCombo] || [combo isEqual:toggleShuffleCombo]) &&
407 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
409 [window setLevel:NSNormalWindowLevel];
410 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
411 [window setLevel:NSStatusWindowLevel];
414 ratingIncrementCombo = [combo copy];
415 [ratingIncrementButton setTitle:string];
416 } else if ([setHotKey isEqualToString:@"DecrementRating"]) {
417 if (([combo isEqual:nextTrackCombo] || [combo isEqual:prevTrackCombo] ||
418 [combo isEqual:trackInfoCombo] || [combo isEqual:playPauseCombo] ||
419 [combo isEqual:ratingIncrementCombo] || [combo isEqual:upcomingSongsCombo] ||
420 [combo isEqual:volumeIncrementCombo] || [combo isEqual:volumeDecrementCombo] ||
421 [combo isEqual:toggleLoopCombo] || [combo isEqual:toggleShuffleCombo]) &&
422 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
424 [window setLevel:NSNormalWindowLevel];
425 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
426 [window setLevel:NSStatusWindowLevel];
429 ratingDecrementCombo = [combo copy];
430 [ratingDecrementButton setTitle:string];
431 } else if ([setHotKey isEqualToString:@"ToggleLoop"]) {
432 if (([combo isEqual:nextTrackCombo] || [combo isEqual:prevTrackCombo] ||
433 [combo isEqual:trackInfoCombo] || [combo isEqual:playPauseCombo] ||
434 [combo isEqual:ratingIncrementCombo] || [combo isEqual:ratingDecrementCombo] ||
435 [combo isEqual:volumeIncrementCombo] || [combo isEqual:volumeDecrementCombo] ||
436 [combo isEqual:upcomingSongsCombo] || [combo isEqual:toggleShuffleCombo]) &&
437 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
439 [window setLevel:NSNormalWindowLevel];
440 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
441 [window setLevel:NSStatusWindowLevel];
444 toggleLoopCombo = [combo copy];
445 [toggleLoopButton setTitle:string];
446 } else if ([setHotKey isEqualToString:@"ToggleShuffle"]) {
447 if (([combo isEqual:nextTrackCombo] || [combo isEqual:prevTrackCombo] ||
448 [combo isEqual:trackInfoCombo] || [combo isEqual:playPauseCombo] ||
449 [combo isEqual:ratingIncrementCombo] || [combo isEqual:ratingDecrementCombo] ||
450 [combo isEqual:volumeIncrementCombo] || [combo isEqual:volumeDecrementCombo] ||
451 [combo isEqual:toggleLoopCombo] || [combo isEqual:upcomingSongsCombo]) &&
452 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
454 [window setLevel:NSNormalWindowLevel];
455 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
456 [window setLevel:NSStatusWindowLevel];
459 toggleShuffleCombo = [combo copy];
460 [toggleShuffleButton setTitle:string];
462 [self cancelHotKey:sender];
467 /*************************************************************************/
469 #pragma mark HOTKEY SUPPORT METHODS
470 /*************************************************************************/
472 - (void)setHotKey:(NSString *)key
475 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyEvent:) name:@"KeyBroadcasterEvent" object:nil];
476 [NSApp beginSheet:keyComboPanel modalForWindow:window modalDelegate:self didEndSelector:nil contextInfo:nil];
479 - (void)keyEvent:(NSNotification *)note
481 NSDictionary *info = [note userInfo];
486 keyCode = [[info objectForKey:@"KeyCode"] shortValue];
487 modifiers = [[info objectForKey:@"Modifiers"] longValue];
489 newCombo = [[KeyCombo alloc] initWithKeyCode:keyCode andModifiers:modifiers];
490 [self setKeyCombo:newCombo];
493 - (void)setKeyCombo:(KeyCombo *)newCombo
497 combo = [newCombo copy];
499 string = [combo userDisplayRep];
503 [keyComboField setStringValue:string];
507 /*************************************************************************/
509 #pragma mark PRIVATE METHOD IMPLEMENTATIONS
510 /*************************************************************************/
514 if ( ! [NSBundle loadNibNamed:@"Preferences" owner:self] ) {
515 NSLog( @"Failed to load Preferences.nib" );
521 - (void)setupCustomizationTables
523 NSImageCell *imgCell = [[[NSImageCell alloc] initImageCell:nil] autorelease];
525 // Set the table view cells up
526 [imgCell setImageScaling:NSScaleNone];
527 [[menuTableView tableColumnWithIdentifier:@"submenu"] setDataCell:imgCell];
528 [[allTableView tableColumnWithIdentifier:@"submenu"] setDataCell:imgCell];
530 // Register for drag and drop
531 [menuTableView registerForDraggedTypes:[NSArray arrayWithObjects:
532 @"MenuTableViewPboardType",
533 @"AllTableViewPboardType",
535 [allTableView registerForDraggedTypes:[NSArray arrayWithObjects:
536 @"MenuTableViewPboardType",
537 @"AllTableViewPboardType",
541 - (void)setupMenuItems
543 NSEnumerator *itemEnum;
545 // Set the list of items you can have.
546 availableItems = [[NSMutableArray alloc] initWithObjects:
547 @"Current Track Info",
561 // Get our preferred menu
562 myItems = [[df arrayForKey:@"menu"] mutableCopy];
564 // Delete items in the availableItems array that are already part of the menu
565 itemEnum = [myItems objectEnumerator];
566 while ( (anItem = [itemEnum nextObject]) ) {
567 if ( ! [anItem isEqualToString:@"<separator>"] ) {
568 [availableItems removeObject:anItem];
572 // Items that show should a submenu image
573 submenuItems = [[NSArray alloc] initWithObjects:
583 NSMutableDictionary *loginwindow;
584 NSMutableArray *loginarray;
585 NSEnumerator *loginEnum;
588 // Fill in the number of songs in advance to show field
589 [songsInAdvance setIntValue:[df integerForKey:@"SongsInAdvance"]];
591 // Fill in hot key buttons
592 if ([df objectForKey:@"PlayPause"]){
593 playPauseCombo = [df keyComboForKey:@"PlayPause"];
594 [playPauseButton setTitle:[playPauseCombo userDisplayRep]];
596 playPauseCombo = [[KeyCombo alloc] init];
599 if ([df objectForKey:@"NextTrack"]) {
600 nextTrackCombo = [df keyComboForKey:@"NextTrack"];
601 [nextTrackButton setTitle:[nextTrackCombo userDisplayRep]];
603 nextTrackCombo = [[KeyCombo alloc] init];
606 if ([df objectForKey:@"PrevTrack"]) {
607 prevTrackCombo = [df keyComboForKey:@"PrevTrack"];
608 [previousTrackButton setTitle:[prevTrackCombo userDisplayRep]];
610 prevTrackCombo = [[KeyCombo alloc] init];
613 if ([df objectForKey:@"TrackInfo"]) {
614 trackInfoCombo = [df keyComboForKey:@"TrackInfo"];
615 [trackInfoButton setTitle:[trackInfoCombo userDisplayRep]];
617 trackInfoCombo = [[KeyCombo alloc] init];
620 if ([df objectForKey:@"UpcomingSongs"]) {
621 upcomingSongsCombo = [df keyComboForKey:@"UpcomingSongs"];
622 [upcomingSongsButton setTitle:[upcomingSongsCombo userDisplayRep]];
624 upcomingSongsCombo = [[KeyCombo alloc] init];
627 if ([df objectForKey:@"IncrementVolume"]) {
628 volumeIncrementCombo = [df keyComboForKey:@"IncrementVolume"];
629 [volumeIncrementButton setTitle:[volumeIncrementCombo userDisplayRep]];
631 volumeIncrementCombo = [[KeyCombo alloc] init];
634 if ([df objectForKey:@"DecrementVolume"]) {
635 volumeDecrementCombo = [df keyComboForKey:@"DecrementVolume"];
636 [volumeDecrementButton setTitle:[volumeDecrementCombo userDisplayRep]];
638 volumeDecrementCombo = [[KeyCombo alloc] init];
641 if ([df objectForKey:@"IncrementRating"]) {
642 ratingIncrementCombo = [df keyComboForKey:@"IncrementRating"];
643 [ratingIncrementButton setTitle:[ratingIncrementCombo userDisplayRep]];
645 ratingIncrementCombo = [[KeyCombo alloc] init];
648 if ([df objectForKey:@"DecrementRating"]) {
649 ratingDecrementCombo = [df keyComboForKey:@"DecrementRating"];
650 [ratingDecrementButton setTitle:[ratingDecrementCombo userDisplayRep]];
652 ratingDecrementCombo = [[KeyCombo alloc] init];
655 if ([df objectForKey:@"ToggleLoop"]) {
656 toggleLoopCombo = [df keyComboForKey:@"ToggleLoop"];
657 [toggleLoopButton setTitle:[toggleLoopCombo userDisplayRep]];
659 toggleLoopCombo = [[KeyCombo alloc] init];
662 if ([df objectForKey:@"ToggleShuffle"]) {
663 toggleShuffleCombo = [df keyComboForKey:@"ToggleShuffle"];
664 [toggleShuffleButton setTitle:[toggleShuffleCombo userDisplayRep]];
666 toggleShuffleCombo = [[KeyCombo alloc] init];
669 // Check current track info buttons
670 [albumCheckbox setState:[df boolForKey:@"showAlbum"] ? NSOnState : NSOffState];
671 [nameCheckbox setState:NSOnState]; // Song info will ALWAYS show song title.
672 [nameCheckbox setEnabled:NO]; // Song info will ALWAYS show song title.
673 [artistCheckbox setState:[df boolForKey:@"showArtist"] ? NSOnState : NSOffState];
674 [trackTimeCheckbox setState:[df boolForKey:@"showTime"] ? NSOnState : NSOffState];
676 // Set the launch at login checkbox state
678 loginwindow = [[df persistentDomainForName:@"loginwindow"] mutableCopy];
679 loginarray = [loginwindow objectForKey:@"AutoLaunchedApplicationDictionary"];
681 loginEnum = [loginarray objectEnumerator];
682 while ( (anItem = [loginEnum nextObject]) ) {
683 if ([[[anItem objectForKey:@"Path"] lastPathComponent] isEqualToString:[[[NSBundle mainBundle] bundlePath] lastPathComponent]]) {
684 [launchAtLoginCheckbox setState:NSOnState];
689 - (IBAction)changeMenus:(id)sender
691 [df setObject:myItems forKey:@"menu"];
693 [controller rebuildMenu];
696 - (void)setLaunchesAtLogin:(BOOL)flag
699 NSMutableDictionary *loginwindow;
700 NSMutableArray *loginarray;
701 ComponentInstance temp = OpenDefaultComponent(kOSAComponentType, kAppleScriptSubtype);;
706 loginwindow = [[df persistentDomainForName:@"loginwindow"] mutableCopy];
707 loginarray = [loginwindow objectForKey:@"AutoLaunchedApplicationDictionary"];
709 for (i = 0; i < [loginarray count]; i++) {
710 NSDictionary *tempDict = [loginarray objectAtIndex:i];
711 if ([[[tempDict objectForKey:@"Path"] lastPathComponent] isEqualToString:[[[NSBundle mainBundle] bundlePath] lastPathComponent]]) {
717 AEDesc scriptDesc, resultDesc;
718 NSString *script = [NSString stringWithFormat:@"tell application \"System Events\"\nmake new login item at end of login items with properties {path:\"%@\", kind:\"APPLICATION\"}\nend tell", [[NSBundle mainBundle] bundlePath]];
720 AECreateDesc(typeChar, [script cString], [script cStringLength],
723 OSADoScript(temp, &scriptDesc, kOSANullScript, typeChar, kOSAModeCanInteract, &resultDesc);
725 AEDisposeDesc(&scriptDesc);
726 AEDisposeDesc(&resultDesc);
727 CloseComponent(temp);
731 NSMutableDictionary *loginwindow;
732 NSMutableArray *loginarray;
736 loginwindow = [[df persistentDomainForName:@"loginwindow"] mutableCopy];
737 loginarray = [loginwindow objectForKey:@"AutoLaunchedApplicationDictionary"];
739 for (i = 0; i < [loginarray count]; i++) {
740 NSDictionary *tempDict = [loginarray objectAtIndex:i];
741 if ([[[tempDict objectForKey:@"Path"] lastPathComponent] isEqualToString:[[[NSBundle mainBundle] bundlePath] lastPathComponent]]) {
742 [loginarray removeObjectAtIndex:i];
743 [df setPersistentDomain:loginwindow forName:@"loginwindow"];
752 /*************************************************************************/
754 #pragma mark NSWindow DELEGATE METHODS
755 /*************************************************************************/
757 - (void)windowWillClose:(NSNotification *)note
759 [(MainController *)controller closePreferences];
763 /*************************************************************************/
765 #pragma mark NSTableView DATASOURCE METHODS
766 /*************************************************************************/
768 - (int)numberOfRowsInTableView:(NSTableView *)aTableView
770 if (aTableView == menuTableView) {
771 return [myItems count];
773 return [availableItems count];
777 - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
779 if (aTableView == menuTableView) {
780 if ([[aTableColumn identifier] isEqualToString:@"name"]) {
781 return [myItems objectAtIndex:rowIndex];
783 if ([submenuItems containsObject:[myItems objectAtIndex:rowIndex]])
785 return [NSImage imageNamed:@"submenu"];
791 if ([[aTableColumn identifier] isEqualToString:@"name"]) {
792 return [availableItems objectAtIndex:rowIndex];
794 if ([submenuItems containsObject:[availableItems objectAtIndex:rowIndex]]) {
795 return [NSImage imageNamed:@"submenu"];
803 - (BOOL)tableView:(NSTableView *)tableView writeRows:(NSArray*)rows toPasteboard:(NSPasteboard*)pboard
805 if (tableView == menuTableView) {
806 [pboard declareTypes:[NSArray arrayWithObjects:@"MenuTableViewPboardType", nil] owner:self];
807 [pboard setString:[[rows objectAtIndex:0] stringValue] forType:@"MenuTableViewPboardType"];
811 if (tableView == allTableView) {
812 [pboard declareTypes:[NSArray arrayWithObjects:@"AllTableViewPboardType", nil] owner:self];
813 [pboard setString:[[rows objectAtIndex:0] stringValue] forType:@"AllTableViewPboardType"];
819 - (BOOL)tableView:(NSTableView*)tableView acceptDrop:(id <NSDraggingInfo>)info row:(int)row dropOperation:(NSTableViewDropOperation)operation
823 NSString *dragData, *temp;
825 pb = [info draggingPasteboard];
827 if ([[pb types] containsObject:@"MenuTableViewPboardType"]) {
828 dragData = [pb stringForType:@"MenuTableViewPboardType"];
829 dragRow = [dragData intValue];
830 temp = [myItems objectAtIndex:dragRow];
831 [myItems removeObjectAtIndex:dragRow];
833 if (tableView == menuTableView) {
835 [myItems insertObject:temp atIndex:row - 1];
837 [myItems insertObject:temp atIndex:row];
840 if (![temp isEqualToString:@"<separator>"]) {
841 [availableItems addObject:temp];
844 } else if ([[pb types] containsObject:@"AllTableViewPboardType"]) {
845 dragData = [pb stringForType:@"AllTableViewPboardType"];
846 dragRow = [dragData intValue];
847 temp = [availableItems objectAtIndex:dragRow];
849 if (![temp isEqualToString:@"<separator>"]) {
850 [availableItems removeObjectAtIndex:dragRow];
852 [myItems insertObject:temp atIndex:row];
855 [menuTableView reloadData];
856 [allTableView reloadData];
857 [self changeMenus:self];
861 - (NSDragOperation)tableView:(NSTableView*)tableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)operation
863 if (tableView == allTableView) {
864 if ([[[info draggingPasteboard] types] containsObject:@"AllTableViewPboardType"]) {
865 return NSDragOperationNone;
868 if ([[[info draggingPasteboard] types] containsObject:@"MenuTableViewPboardType"]) {
869 NSString *item = [myItems objectAtIndex:[[[info draggingPasteboard] stringForType:@"MenuTableViewPboardType"] intValue]];
870 if ([item isEqualToString:@"PreferencesÉ"] || [item isEqualToString:@"Quit"]) {
871 return NSDragOperationNone;
875 [tableView setDropRow:-1 dropOperation:NSTableViewDropOn];
876 return NSDragOperationGeneric;
879 if (operation == NSTableViewDropOn || row == -1)
881 return NSDragOperationNone;
884 return NSDragOperationGeneric;
888 /*************************************************************************/
890 #pragma mark DEALLOCATION METHODS
891 /*************************************************************************/
895 [self setKeyCombo:nil];
896 [playPauseCombo release];
897 [nextTrackCombo release];
898 [prevTrackCombo release];
899 [trackInfoCombo release];
900 [upcomingSongsCombo release];
901 [keyComboPanel release];
902 [menuTableView setDataSource:nil];
903 [allTableView setDataSource:nil];
904 [controller release];
905 [availableItems release];
906 [submenuItems release];