Moving registerDefaults to the preferences controller where it belongs. Some other...
[MenuTunes.git] / OldMainController.m
1 #import "MainController.h"
2 #import "PreferencesController.h"
3 #import "HotKeyCenter.h"
4 #import "StatusWindow.h"
5
6 @interface MainController(Private)
7 - (ITMTRemote *)loadRemote;
8 - (void)rebuildUpcomingSongsMenu;
9 - (void)rebuildPlaylistMenu;
10 - (void)rebuildEQPresetsMenu;
11 - (void)updateRatingMenu;
12 - (void)setupHotKeys;
13 - (void)timerUpdate;
14 - (void)updateMenu;
15 - (void)setKeyEquivalentForCode:(short)code andModifiers:(long)modifiers
16         onItem:(NSMenuItem *)item;
17
18 @end
19
20 @implementation MainController
21
22 /*************************************************************************/
23 #pragma mark -
24 #pragma mark INITIALIZATION/DEALLOCATION METHODS
25 /*************************************************************************/
26
27 - (id)init
28 {
29     if ( ( self = [super init] ) ) {
30         remoteArray = [[NSMutableArray alloc] initWithCapacity:1];
31         statusWindow = [StatusWindow sharedWindow];
32     }
33     return self;
34 }
35
36 - (void)dealloc
37 {
38     if (refreshTimer) {
39         [refreshTimer invalidate];
40         [refreshTimer release];
41         refreshTimer = nil;
42     }
43     [currentRemote halt];
44     [statusItem release];
45     [menu release];
46     [super dealloc];
47 }
48
49 - (void)applicationDidFinishLaunching:(NSNotification *)note
50 {
51     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
52     currentRemote = [self loadRemote];
53     [currentRemote begin];
54     
55     //Setup for notification of the remote player launching or quitting
56     [[[NSWorkspace sharedWorkspace] notificationCenter]
57             addObserver:self
58             selector:@selector(applicationTerminated:)
59             name:NSWorkspaceDidTerminateApplicationNotification
60             object:nil];
61     
62     [[[NSWorkspace sharedWorkspace] notificationCenter]
63             addObserver:self
64             selector:@selector(applicationLaunched:)
65             name:NSWorkspaceDidLaunchApplicationNotification
66             object:nil];
67
68     if ( ! [defaults objectForKey:@"menu"] ) {  // If this is nil, defaults have never been registered.
69         [[PreferencesController sharedPrefs] registerDefaults];
70     }
71     
72     statusItem = [[ITStatusItem alloc]
73             initWithStatusBar:[NSStatusBar systemStatusBar]
74             withLength:NSSquareStatusItemLength];
75     
76     menu = [[NSMenu alloc] initWithTitle:@""];
77     if ( ( [currentRemote playerRunningState] == ITMTRemotePlayerRunning ) ) {
78         [self applicationLaunched:nil];
79     } else {
80         [self applicationTerminated:nil];
81     }
82     
83     [statusItem setImage:[NSImage imageNamed:@"menu"]];
84     [statusItem setAlternateImage:[NSImage imageNamed:@"selected_image"]];
85     // Below line of code is for creating builds for Beta Testers
86     // [statusItem setToolTip:@[NSString stringWithFormat:@"This Nontransferable Beta (Built on %s) of iThink Software's MenuTunes is Registered to: Beta Tester (betatester@somedomain.com).",__DATE__]];
87 }
88
89 - (void)applicationWillTerminate:(NSNotification *)note
90 {
91     [self clearHotKeys];
92     [[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
93 }
94
95 - (ITMTRemote *)loadRemote
96 {
97     NSString *folderPath = [[NSBundle mainBundle] builtInPlugInsPath];
98     
99     if (folderPath) {
100         NSArray      *bundlePathList = [NSBundle pathsForResourcesOfType:@"remote" inDirectory:folderPath];
101         NSEnumerator *enumerator     = [bundlePathList objectEnumerator];
102         NSString     *bundlePath;
103
104         while ( (bundlePath = [enumerator nextObject]) ) {
105             NSBundle* remoteBundle = [NSBundle bundleWithPath:bundlePath];
106
107             if (remoteBundle) {
108                 Class remoteClass = [remoteBundle principalClass];
109
110                 if ([remoteClass conformsToProtocol:@protocol(ITMTRemote)] &&
111                     [remoteClass isKindOfClass:[NSObject class]]) {
112
113                     id remote = [remoteClass remote];
114                     [remoteArray addObject:remote];
115                 }
116             }
117         }
118
119 //      if ( [remoteArray count] > 0 ) {  // UNCOMMENT WHEN WE HAVE > 1 PLUGIN
120 //          if ( [remoteArray count] > 1 ) {
121 //              [remoteArray sortUsingSelector:@selector(sortAlpha:)];
122 //          }
123 //          [self loadModuleAccessUI]; //Comment out this line to disable remote visibility
124 //      }
125     }
126 //  NSLog(@"%@", [remoteArray objectAtIndex:0]);  //DEBUG
127     return [remoteArray objectAtIndex:0];
128 }
129
130 //
131 //
132
133 - (void)applicationLaunched:(NSNotification *)note
134 {
135     if (!note || [[[note userInfo] objectForKey:@"NSApplicationName"] isEqualToString:[currentRemote playerFullName]]) {
136         [NSThread detachNewThreadSelector:@selector(startTimerInNewThread) toTarget:self withObject:nil];
137         
138         [self rebuildMenu];
139         [statusItem setMenu:menu];
140         [self setupHotKeys];
141         isAppRunning = ITMTRemotePlayerRunning;
142         return;
143     }
144     
145     isAppRunning = ITMTRemotePlayerRunning;
146 }
147
148 - (void)applicationTerminated:(NSNotification *)note
149 {
150     if (!note || [[[note userInfo] objectForKey:@"NSApplicationName"] isEqualToString:[currentRemote playerFullName]]) {        
151         NSMenu *notRunningMenu = [[NSMenu alloc] initWithTitle:@""];
152         [[notRunningMenu addItemWithTitle:[NSString stringWithFormat:@"Open %@", [currentRemote playerSimpleName]] action:@selector(showPlayer:) keyEquivalent:@""] setTarget:self];
153         [notRunningMenu addItem:[NSMenuItem separatorItem]];
154         [[notRunningMenu addItemWithTitle:@"Preferences" action:@selector(showPreferences:) keyEquivalent:@""] setTarget:self];
155         [[notRunningMenu addItemWithTitle:@"Quit" action:@selector(quitMenuTunes:) keyEquivalent:@""] setTarget:self];
156         [statusItem setMenu:[notRunningMenu autorelease]];
157         
158         [refreshTimer invalidate];
159         [refreshTimer release];
160         refreshTimer = nil;
161         [self clearHotKeys];
162         isAppRunning = NO;
163         return;
164     }
165 }
166
167 /*************************************************************************/
168 #pragma mark -
169 #pragma mark INSTANCE METHODS
170 /*************************************************************************/
171
172 - (void)startTimerInNewThread
173 {
174     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
175     NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
176     refreshTimer = [[NSTimer scheduledTimerWithTimeInterval:0.5
177                              target:self
178                              selector:@selector(timerUpdate)
179                              userInfo:nil
180                              repeats:YES] retain];
181     [runLoop run];
182     [pool release];
183 }
184
185 //Recreate the status item menu
186 - (void)rebuildMenu
187 {
188     NSArray *myMenu = [[NSUserDefaults standardUserDefaults] arrayForKey:@"menu"];
189     int i;
190     
191     trackInfoIndex = -1;
192     lastPlaylistIndex = -1;
193     didHaveAlbumName = ([[currentRemote currentSongAlbum] length] > 0);
194     didHaveArtistName = ([[currentRemote currentSongArtist] length] > 0);
195     
196     [menu autorelease];
197     menu = [[NSMenu alloc] initWithTitle:@""];
198     
199     /*while ([menu numberOfItems] > 0) {
200         [menu removeItemAtIndex:0];
201     }*/
202     
203     playPauseItem = nil;
204     lastSongIdentifier = @"0-0";
205     
206     upcomingSongsItem = nil;
207     [upcomingSongsMenu release];
208     upcomingSongsMenu = nil;
209     
210     ratingItem = nil;
211     [ratingMenu release];
212     ratingMenu = nil;
213     
214     playlistItem = nil;
215     [playlistMenu release];
216     playlistMenu = nil;
217     
218     eqItem = nil;
219     [eqMenu release];
220     eqMenu = nil;
221     
222     for (i = 0; i < [myMenu count]; i++) {
223         NSString *item = [myMenu objectAtIndex:i];
224         if ([item isEqualToString:@"Play/Pause"]) {
225             KeyCombo *tempCombo = [[NSUserDefaults standardUserDefaults] keyComboForKey:@"PlayPause"];
226             playPauseItem = [menu addItemWithTitle:@"Play"
227                                     action:@selector(playPause:)
228                                     keyEquivalent:@""];
229             
230             if (tempCombo) {
231                 [self setKeyEquivalentForCode:[tempCombo keyCode]
232                     andModifiers:[tempCombo modifiers] onItem:playPauseItem];
233                 [tempCombo release];
234             }
235         } else if ([item isEqualToString:@"Next Track"]) {
236             KeyCombo *tempCombo = [[NSUserDefaults standardUserDefaults] keyComboForKey:@"NextTrack"];
237             NSMenuItem *nextTrack = [menu addItemWithTitle:@"Next Track"
238                                         action:@selector(nextSong:)
239                                         keyEquivalent:@""];
240             
241             if (tempCombo) {
242                 [self setKeyEquivalentForCode:[tempCombo keyCode]
243                     andModifiers:[tempCombo modifiers] onItem:nextTrack];
244                 [tempCombo release];
245             }
246         } else if ([item isEqualToString:@"Previous Track"]) {
247             KeyCombo *tempCombo = [[NSUserDefaults standardUserDefaults] keyComboForKey:@"PrevTrack"];
248             NSMenuItem *prevTrack = [menu addItemWithTitle:@"Previous Track"
249                                         action:@selector(prevSong:)
250                                         keyEquivalent:@""];
251             
252             if (tempCombo) {
253                 [self setKeyEquivalentForCode:[tempCombo keyCode]
254                     andModifiers:[tempCombo modifiers] onItem:prevTrack];
255                 [tempCombo release];
256             }
257         } else if ([item isEqualToString:@"Fast Forward"]) {
258             [menu addItemWithTitle:@"Fast Forward"
259                     action:@selector(fastForward:)
260                     keyEquivalent:@""];
261         } else if ([item isEqualToString:@"Rewind"]) {
262             [menu addItemWithTitle:@"Rewind"
263                     action:@selector(rewind:)
264                     keyEquivalent:@""];
265         } else if ([item isEqualToString:@"Upcoming Songs"]) {
266             upcomingSongsItem = [menu addItemWithTitle:@"Upcoming Songs"
267                     action:nil
268                     keyEquivalent:@""];
269         } else if ([item isEqualToString:@"Playlists"]) {
270             playlistItem = [menu addItemWithTitle:@"Playlists"
271                     action:nil
272                     keyEquivalent:@""];
273         } else if ([item isEqualToString:@"EQ Presets"]) {
274             eqItem = [menu addItemWithTitle:@"EQ Presets"
275                     action:nil
276                     keyEquivalent:@""];
277         } else if ([item isEqualToString:@"PreferencesÉ"]) {
278             [menu addItemWithTitle:@"PreferencesÉ"
279                     action:@selector(showPreferences:)
280                     keyEquivalent:@""];
281         } else if ([item isEqualToString:@"Quit"]) {
282             [menu addItemWithTitle:@"Quit"
283                     action:@selector(quitMenuTunes:)
284                     keyEquivalent:@""];
285         } else if ([item isEqualToString:@"Current Track Info"]) {
286             trackInfoIndex = [menu numberOfItems];
287             [menu addItemWithTitle:@"No Song"
288                     action:nil
289                     keyEquivalent:@""];
290         } else if ([item isEqualToString:@"Song Rating"]) {
291             unichar fullstar = 0x2605;
292             unichar emptystar = 0x2606;
293             NSString *fullStarChar = [NSString stringWithCharacters:&fullstar length:1];
294             NSString *emptyStarChar = [NSString stringWithCharacters:&emptystar length:1];
295             NSMenuItem *item;
296             
297             ratingItem = [menu addItemWithTitle:@"Song Rating"
298                     action:nil
299                     keyEquivalent:@""];
300             
301             ratingMenu = [[NSMenu alloc] initWithTitle:@""];
302             
303             item = [ratingMenu addItemWithTitle:[NSString stringWithFormat:@"%@%@%@%@%@", emptyStarChar, emptyStarChar, emptyStarChar, emptyStarChar, emptyStarChar] action:@selector(selectSongRating:) keyEquivalent:@""];
304             [item setTag:0];
305             
306             item = [ratingMenu addItemWithTitle:[NSString stringWithFormat:@"%@%@%@%@%@", fullStarChar, emptyStarChar, emptyStarChar, emptyStarChar, emptyStarChar] action:@selector(selectSongRating:) keyEquivalent:@""];
307             [item setTag:20];
308             
309             item = [ratingMenu addItemWithTitle:[NSString stringWithFormat:@"%@%@%@%@%@", fullStarChar, fullStarChar, emptyStarChar, emptyStarChar, emptyStarChar] action:@selector(selectSongRating:) keyEquivalent:@""];
310             [item setTag:40];
311             
312             item = [ratingMenu addItemWithTitle:[NSString stringWithFormat:@"%@%@%@%@%@", fullStarChar, fullStarChar, fullStarChar, emptyStarChar, emptyStarChar] action:@selector(selectSongRating:) keyEquivalent:@""];
313             [item setTag:60];
314             
315             item = [ratingMenu addItemWithTitle:[NSString stringWithFormat:@"%@%@%@%@%@", fullStarChar, fullStarChar, fullStarChar, fullStarChar, emptyStarChar] action:@selector(selectSongRating:) keyEquivalent:@""];
316             [item setTag:80];
317             
318             item = [ratingMenu addItemWithTitle:[NSString stringWithFormat:@"%@%@%@%@%@", fullStarChar, fullStarChar, fullStarChar, fullStarChar, fullStarChar] action:@selector(selectSongRating:) keyEquivalent:@""];
319             [item setTag:100];
320         } else if ([item isEqualToString:@"<separator>"]) {
321             [menu addItem:[NSMenuItem separatorItem]];
322         }
323     }
324     
325     [statusItem setMenu:menu];
326     
327     [self updateMenu];
328     
329     [self clearHotKeys];
330     [self setupHotKeys];
331 }
332
333 //Rebuild the upcoming songs submenu. Can be improved a lot.
334 - (void)rebuildUpcomingSongsMenu
335 {
336     int curIndex = [currentRemote currentPlaylistIndex];
337     int numSongs = [currentRemote numberOfSongsInPlaylistAtIndex:curIndex];
338     int numSongsInAdvance = [[NSUserDefaults standardUserDefaults] integerForKey:@"SongsInAdvance"];
339     
340     if (!isPlayingRadio) {
341         if (numSongs > 0) {
342             int curTrack = [currentRemote currentSongIndex];
343             int i;
344             
345             [upcomingSongsMenu release];
346             upcomingSongsMenu = [[NSMenu alloc] initWithTitle:@""];
347             [upcomingSongsItem setSubmenu:upcomingSongsMenu];
348             [upcomingSongsItem setEnabled:YES];
349             
350             for (i = curTrack + 1; i <= curTrack + numSongsInAdvance; i++) {
351                 if (i <= numSongs) {
352                     NSString *curSong = [currentRemote songTitleAtIndex:i];
353                     NSMenuItem *songItem;
354                     songItem = [[NSMenuItem alloc] initWithTitle:curSong action:@selector(selectSong:) keyEquivalent:@""];
355                     [songItem setRepresentedObject:[NSNumber numberWithInt:i]];
356                     [upcomingSongsMenu addItem:songItem];
357                     [songItem release];
358                 } else {
359                     break;
360                 }
361             }
362         }
363     } else {
364         [upcomingSongsItem setSubmenu:nil];
365         [upcomingSongsItem setEnabled:NO];
366     }
367 }
368
369 - (void)rebuildPlaylistMenu
370 {
371     NSArray *playlists = [currentRemote playlists];
372     int i, currentPlaylist = [currentRemote currentPlaylistIndex];
373     
374     [playlistMenu release];
375     playlistMenu = [[NSMenu alloc] initWithTitle:@""];
376     
377     for (i = 0; i < [playlists count]; i++) {
378         NSString *playlistName = [playlists objectAtIndex:i];
379         NSMenuItem *tempItem;
380         tempItem = [[NSMenuItem alloc] initWithTitle:playlistName action:@selector(selectPlaylist:) keyEquivalent:@""];
381         [tempItem setTag:i + 1];
382         [playlistMenu addItem:tempItem];
383         [tempItem release];
384     }
385     [playlistItem setSubmenu:playlistMenu];
386     [playlistItem setEnabled:YES];
387     
388     if (!isPlayingRadio && currentPlaylist) {
389         [[playlistMenu itemAtIndex:currentPlaylist - 1] setState:NSOnState];
390     }
391 }
392
393 //Build a menu with the list of all available EQ presets
394 - (void)rebuildEQPresetsMenu
395 {
396     NSArray *eqPresets = [currentRemote eqPresets];
397     NSMenuItem *enabledItem;
398     int i;
399     
400     [eqMenu release];
401     eqMenu = [[NSMenu alloc] initWithTitle:@""];
402     
403     enabledItem = [eqMenu addItemWithTitle:@"Enabled"
404                           action:@selector(selectEQPreset:)
405                           keyEquivalent:@""];
406     [enabledItem setTag:-1];
407     
408     if ([currentRemote equalizerEnabled]) {
409         [enabledItem setState:NSOnState];
410     }
411     
412     [eqMenu addItem:[NSMenuItem separatorItem]];
413     
414     for (i = 0; i < [eqPresets count]; i++) {
415         NSString *name = [eqPresets objectAtIndex:i];
416         NSMenuItem *tempItem;
417         if (name) {
418             tempItem = [[NSMenuItem alloc] initWithTitle:name action:@selector(selectEQPreset:) keyEquivalent:@""];
419             [tempItem setTag:i];
420             [eqMenu addItem:tempItem];
421             [tempItem release];
422         }
423     }
424     [eqItem setSubmenu:eqMenu];
425     [eqItem setEnabled:YES];
426     
427     [[eqMenu itemAtIndex:[currentRemote currentEQPresetIndex] + 1] setState:NSOnState];
428 }
429
430 - (void)updateRatingMenu
431 {
432     int currentSongRating = ([currentRemote currentSongRating] * 5);
433     if ([currentRemote currentPlaylistIndex] && (currentSongRating != lastSongRating)) {
434         if ([currentRemote classOfPlaylistAtIndex:[currentRemote currentPlaylistIndex]] == ITMTRemotePlayerRadioPlaylist) {
435             return;
436         }
437         [[ratingMenu itemAtIndex:lastSongRating] setState:NSOffState];
438         lastSongRating = currentSongRating;
439         [[ratingMenu itemAtIndex:lastSongRating] setState:NSOnState];
440     }
441 }
442
443 - (void)timerUpdate
444 {
445     NSString *currentIdentifier = [currentRemote currentSongUniqueIdentifier];
446     if (![lastSongIdentifier isEqualToString:currentIdentifier] ||
447        (!isPlayingRadio && ([currentRemote classOfPlaylistAtIndex:[currentRemote currentPlaylistIndex]] == ITMTRemotePlayerRadioPlaylist))) {
448         [self rebuildMenu];
449     }
450     
451     [self updateRatingMenu];
452     
453     //Update Play/Pause menu item
454     if (playPauseItem){
455         if ([currentRemote playerPlayingState] == ITMTRemotePlayerPlaying) {
456             [playPauseItem setTitle:@"Pause"];
457         } else {
458             [playPauseItem setTitle:@"Play"];
459         }
460     }
461 }
462
463 - (void)updateMenu
464 {
465     NSUserDefaults *defaults;
466     int playlist = [currentRemote currentPlaylistIndex];
467     int temp;
468     
469     if ( (isAppRunning == ITMTRemotePlayerNotRunning) ) {
470         return;
471     }
472     
473     defaults = [NSUserDefaults standardUserDefaults];
474     isPlayingRadio = ([currentRemote classOfPlaylistAtIndex:playlist] == ITMTRemotePlayerRadioPlaylist);
475     
476     if (upcomingSongsItem) {
477         [self rebuildUpcomingSongsMenu];
478     }
479     
480     if (playlistItem) {
481         [self rebuildPlaylistMenu];
482     }
483     
484     if (eqItem) {
485         [self rebuildEQPresetsMenu];
486     }
487     
488     if (ratingItem) {
489         if (isPlayingRadio || !playlist) {
490             [ratingItem setEnabled:NO];
491             if ([ratingItem submenu]) {
492                 [ratingItem setSubmenu:nil];
493             }
494         } else {
495             int currentSongRating = ([currentRemote currentSongRating] * 5);
496             [[ratingMenu itemAtIndex:lastSongRating] setState:NSOffState];
497             lastSongRating = currentSongRating;
498             [[ratingMenu itemAtIndex:lastSongRating] setState:NSOnState];
499             [ratingItem setEnabled:YES];
500             [ratingItem setSubmenu:ratingMenu];
501         }
502     }
503     
504     //Set the new unique song identifier
505     lastSongIdentifier = [[currentRemote currentSongUniqueIdentifier] retain];
506     
507     //If we're in a playlist or radio mode
508     if ( (trackInfoIndex > -1) && (playlist || isPlayingRadio) ) {
509         NSString *title, *album, *artist;
510         
511         if ( (temp = [menu indexOfItemWithTitle:@"No Song"]) && (temp > -1) ) {
512             [menu removeItemAtIndex:temp];
513             [menu insertItemWithTitle:@"Now Playing" action:NULL keyEquivalent:@"" atIndex:temp];
514         }
515         
516         title = [currentRemote currentSongTitle];
517         
518         if (!isPlayingRadio) {
519             ([defaults boolForKey:@"showAlbum"]) ? (album = [currentRemote currentSongAlbum]) :
520                                                    (album = @"");
521             ([defaults boolForKey:@"showArtist"]) ? (artist = [currentRemote currentSongArtist]) :
522                                                     (artist = @"");
523             if ([defaults boolForKey:@"showTime"]) {
524                 [menu insertItemWithTitle:[NSString stringWithFormat:@"  %@", [currentRemote currentSongLength]] action:nil keyEquivalent:@"" atIndex:trackInfoIndex + 1];
525             }
526             
527             if ([artist length] > 0) {
528                 [menu insertItemWithTitle:[NSString stringWithFormat:@"  %@", artist] action:nil keyEquivalent:@"" atIndex:trackInfoIndex + 1];
529             }
530             
531             if ([album length] > 0) {
532                 [menu insertItemWithTitle:[NSString stringWithFormat:@"  %@", album] action:nil keyEquivalent:@"" atIndex:trackInfoIndex + 1];
533             }
534             
535             if ([defaults boolForKey:@"showArtist"]) {
536                 didHaveArtistName = (([artist length] > 0) ? YES : NO);
537             }
538             
539             if ([defaults boolForKey:@"showAlbum"]) {
540                 didHaveAlbumName = (([album length] > 0) ? YES : NO);
541             }
542         }
543         
544         if ([title length] > 0) {
545             [menu insertItemWithTitle:[NSString stringWithFormat:@"  %@", title] action:nil keyEquivalent:@"" atIndex:trackInfoIndex + 1];
546         }
547     }
548     [menu update];
549 }
550
551
552 //
553 //
554 // Menu Selectors
555 //
556 //
557
558 - (void)selectSong:(id)sender
559 {
560     [currentRemote switchToSongAtIndex:[[sender representedObject] intValue]];
561 }
562
563 - (void)selectPlaylist:(id)sender
564 {
565     int playlist = [sender tag];
566     [currentRemote switchToPlaylistAtIndex:playlist];
567 }
568
569 - (void)selectEQPreset:(id)sender
570 {
571     int curSet = [currentRemote currentEQPresetIndex];
572     int item = [sender tag];
573     
574     if (item == -1) {
575         [currentRemote setEqualizerEnabled:![currentRemote equalizerEnabled]];
576     } else {
577         [currentRemote setEqualizerEnabled:YES];
578         [currentRemote switchToEQAtIndex:item];
579         [[eqMenu itemAtIndex:curSet + 1] setState:NSOffState];
580         [[eqMenu itemAtIndex:item + 2] setState:NSOnState];
581     }
582 }
583
584 - (void)selectSongRating:(id)sender
585 {
586     int newRating = [sender tag];
587     [[ratingMenu itemAtIndex:lastSongRating] setState:NSOffState];
588     [sender setState:NSOnState];
589     [currentRemote setCurrentSongRating:(float)newRating / 100.0];
590     lastSongRating = newRating / 20;
591 }
592
593 - (void)playPause:(id)sender
594 {
595     ITMTRemotePlayerPlayingState state = [currentRemote playerPlayingState];
596     
597     if (state == ITMTRemotePlayerPlaying) {
598         [currentRemote pause];
599         [playPauseItem setTitle:@"Play"];
600     } else if ((state == ITMTRemotePlayerForwarding) || (state == ITMTRemotePlayerRewinding)) {
601         [currentRemote pause];
602         [currentRemote play];
603     } else {
604         [currentRemote play];
605         [playPauseItem setTitle:@"Pause"];
606     }
607 }
608
609 - (void)nextSong:(id)sender
610 {
611     [currentRemote goToNextSong];
612 }
613
614 - (void)prevSong:(id)sender
615 {
616     [currentRemote goToPreviousSong];
617 }
618
619 - (void)fastForward:(id)sender
620 {
621     [currentRemote forward];
622     [playPauseItem setTitle:@"Play"];
623 }
624
625 - (void)rewind:(id)sender
626 {
627     [currentRemote rewind];
628     [playPauseItem setTitle:@"Play"];
629 }
630
631 //
632 //
633 - (void)quitMenuTunes:(id)sender
634 {
635     [NSApp terminate:self];
636 }
637
638 - (void)showPlayer:(id)sender
639 {
640     if ( ( isAppRunning == ITMTRemotePlayerRunning) ) {
641         [currentRemote showPrimaryInterface];
642     } else {
643         if (![[NSWorkspace sharedWorkspace] launchApplication:[currentRemote playerFullName]]) {
644             NSLog(@"Error Launching Player");
645         }
646     }
647 }
648
649 - (void)showPreferences:(id)sender
650 {
651     [[PreferencesController sharedPrefs] setController:self];
652     [[PreferencesController sharedPrefs] showPrefsWindow:self];
653 }
654
655 - (void)closePreferences
656 {
657     if ( ( isAppRunning == ITMTRemotePlayerRunning) ) {
658         [self setupHotKeys];
659     }
660 }
661
662
663 //
664 //
665 // Hot key setup
666 //
667 //
668
669 - (void)clearHotKeys
670 {
671     [[HotKeyCenter sharedCenter] removeHotKey:@"PlayPause"];
672     [[HotKeyCenter sharedCenter] removeHotKey:@"NextTrack"];
673     [[HotKeyCenter sharedCenter] removeHotKey:@"PrevTrack"];
674     [[HotKeyCenter sharedCenter] removeHotKey:@"TrackInfo"];
675     [[HotKeyCenter sharedCenter] removeHotKey:@"UpcomingSongs"];
676 }
677
678 - (void)setupHotKeys
679 {
680     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
681     
682     if ([defaults objectForKey:@"PlayPause"] != nil) {
683         [[HotKeyCenter sharedCenter] addHotKey:@"PlayPause"
684                 combo:[defaults keyComboForKey:@"PlayPause"]
685                 target:self action:@selector(playPause:)];
686     }
687     
688     if ([defaults objectForKey:@"NextTrack"] != nil) {
689         [[HotKeyCenter sharedCenter] addHotKey:@"NextTrack"
690                 combo:[defaults keyComboForKey:@"NextTrack"]
691                 target:self action:@selector(nextSong:)];
692     }
693     
694     if ([defaults objectForKey:@"PrevTrack"] != nil) {
695         [[HotKeyCenter sharedCenter] addHotKey:@"PrevTrack"
696                 combo:[defaults keyComboForKey:@"PrevTrack"]
697                 target:self action:@selector(prevSong:)];
698     }
699     
700     if ([defaults objectForKey:@"TrackInfo"] != nil) {
701         [[HotKeyCenter sharedCenter] addHotKey:@"TrackInfo"
702                 combo:[defaults keyComboForKey:@"TrackInfo"]
703                 target:self action:@selector(showCurrentTrackInfo)];
704     }
705     
706     if ([defaults objectForKey:@"UpcomingSongs"] != nil) {
707         [[HotKeyCenter sharedCenter] addHotKey:@"UpcomingSongs"
708                combo:[defaults keyComboForKey:@"UpcomingSongs"]
709                target:self action:@selector(showUpcomingSongs)];
710     }
711 }
712
713 //
714 //
715 // Show Current Track Info And Show Upcoming Songs Floaters
716 //
717 //
718
719 - (void)showCurrentTrackInfo
720 {
721     NSString *trackName = [currentRemote currentSongTitle];
722     if (!statusWindow && [trackName length]) {
723         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
724         NSString *stringToShow = @"";
725         
726         if ([defaults boolForKey:@"showName"]) {
727             if ([defaults boolForKey:@"showArtist"]) {
728                 NSString *trackArtist = [currentRemote currentSongArtist];
729                 trackName = [NSString stringWithFormat:@"%@ - %@", trackArtist, trackName];
730             }
731             stringToShow = [stringToShow stringByAppendingString:trackName];
732             stringToShow = [stringToShow stringByAppendingString:@"\n"];
733         }
734         
735         if ([defaults boolForKey:@"showAlbum"]) {
736             NSString *trackAlbum = [currentRemote currentSongAlbum];
737             if ([trackAlbum length]) {
738                 stringToShow = [stringToShow stringByAppendingString:trackAlbum];
739                 stringToShow = [stringToShow stringByAppendingString:@"\n"];
740             }
741         }
742         
743         if ([defaults boolForKey:@"showTime"]) {
744             NSString *trackTime = [currentRemote currentSongLength];
745             if ([trackTime length]) {
746                 stringToShow = [NSString stringWithFormat:@"%@Total Time: %@\n", stringToShow, trackTime];
747             }
748         }
749         
750         {
751             int trackTimeLeft = [[currentRemote currentSongRemaining] intValue];
752             int minutes = trackTimeLeft / 60, seconds = trackTimeLeft % 60;
753             if (seconds < 10) {
754                 stringToShow = [stringToShow stringByAppendingString:
755                             [NSString stringWithFormat:@"Time Remaining: %i:0%i", minutes, seconds]];
756             } else {
757                 stringToShow = [stringToShow stringByAppendingString:
758                             [NSString stringWithFormat:@"Time Remaining: %i:%i", minutes, seconds]];
759             }
760         }
761         
762         [statusWindow setText:stringToShow];
763         [NSTimer scheduledTimerWithTimeInterval:3.0
764                     target:self
765                     selector:@selector(fadeAndCloseStatusWindow)
766                     userInfo:nil
767                     repeats:NO];
768     }
769 }
770
771 - (void)showUpcomingSongs
772 {
773     int curPlaylist = [currentRemote currentPlaylistIndex];
774     if (!statusWindow) {
775         int numSongs = [currentRemote numberOfSongsInPlaylistAtIndex:curPlaylist];
776         
777         if (numSongs > 0) {
778             int numSongsInAdvance = [[NSUserDefaults standardUserDefaults] integerForKey:@"SongsInAdvance"];
779             int curTrack = [currentRemote currentSongIndex];
780             int i;
781             NSString *songs = @"";
782             
783             statusWindow = [ITTransientStatusWindow sharedWindow];
784             for (i = curTrack + 1; i <= curTrack + numSongsInAdvance; i++) {
785                 if (i <= numSongs) {
786                     NSString *curSong = [currentRemote songTitleAtIndex:i];
787                     songs = [songs stringByAppendingString:curSong];
788                     songs = [songs stringByAppendingString:@"\n"];
789                 }
790             }
791             [statusWindow setText:songs];
792             [NSTimer scheduledTimerWithTimeInterval:3.0
793                         target:self
794                         selector:@selector(fadeAndCloseStatusWindow)
795                         userInfo:nil
796                         repeats:NO];
797         }
798     }
799 }
800
801 - (void)fadeAndCloseStatusWindow
802 {
803     [statusWindow orderOut:self];
804 }
805
806 - (void)setKeyEquivalentForCode:(short)code andModifiers:(long)modifiers
807         onItem:(NSMenuItem *)item
808 {
809     unichar charcode = 'a';
810     int i;
811     long cocoaModifiers = 0;
812     static long carbonToCocoa[6][2] = 
813     {
814         { cmdKey, NSCommandKeyMask },
815         { optionKey, NSAlternateKeyMask },
816         { controlKey, NSControlKeyMask },
817         { shiftKey, NSShiftKeyMask },
818     };
819     
820     for (i = 0; i < 6; i++) {
821         if (modifiers & carbonToCocoa[i][0]) {
822             cocoaModifiers += carbonToCocoa[i][1];
823         }
824     }
825     [item setKeyEquivalentModifierMask:cocoaModifiers];
826     
827     //Missing key combos for some keys. Must find them later.
828     switch (code)
829     {
830         case 36:
831             charcode = '\r';
832         break;
833         
834         case 48:
835             charcode = '\t';
836         break;
837         
838         //Space -- ARGH!
839         case 49:
840         {
841             /*MenuRef menuRef = _NSGetCarbonMenu([item menu]);
842             NSLog(@"%@", menuRef);
843             SetMenuItemCommandKey(menuRef, 0, NO, 49);
844             SetMenuItemModifiers(menuRef, 0, kMenuNoCommandModifier);
845             SetMenuItemKeyGlyph(menuRef, 0, kMenuBlankGlyph);
846             charcode = 'b';*/
847         }
848         break;
849         
850         case 51:
851             charcode = NSDeleteFunctionKey;
852         break;
853         
854         case 53:
855             charcode = '\e';
856         break;
857         
858         case 71:
859             charcode = '\e';
860         break;
861         
862         case 76:
863             charcode = '\r';
864         break;
865         
866         case 96:
867             charcode = NSF5FunctionKey;
868         break;
869         
870         case 97:
871             charcode = NSF6FunctionKey;
872         break;
873         
874         case 98:
875             charcode = NSF7FunctionKey;
876         break;
877         
878         case 99:
879             charcode = NSF3FunctionKey;
880         break;
881         
882         case 100:
883             charcode = NSF8FunctionKey;
884         break;
885         
886         case 101:
887             charcode = NSF9FunctionKey;
888         break;
889         
890         case 103:
891             charcode = NSF11FunctionKey;
892         break;
893         
894         case 105:
895             charcode = NSF3FunctionKey;
896         break;
897         
898         case 107:
899             charcode = NSF14FunctionKey;
900         break;
901         
902         case 109:
903             charcode = NSF10FunctionKey;
904         break;
905         
906         case 111:
907             charcode = NSF12FunctionKey;
908         break;
909         
910         case 113:
911             charcode = NSF13FunctionKey;
912         break;
913         
914         case 114:
915             charcode = NSInsertFunctionKey;
916         break;
917         
918         case 115:
919             charcode = NSHomeFunctionKey;
920         break;
921         
922         case 116:
923             charcode = NSPageUpFunctionKey;
924         break;
925         
926         case 117:
927             charcode = NSDeleteFunctionKey;
928         break;
929         
930         case 118:
931             charcode = NSF4FunctionKey;
932         break;
933         
934         case 119:
935             charcode = NSEndFunctionKey;
936         break;
937         
938         case 120:
939             charcode = NSF2FunctionKey;
940         break;
941         
942         case 121:
943             charcode = NSPageDownFunctionKey;
944         break;
945         
946         case 122:
947             charcode = NSF1FunctionKey;
948         break;
949         
950         case 123:
951             charcode = NSLeftArrowFunctionKey;
952         break;
953         
954         case 124:
955             charcode = NSRightArrowFunctionKey;
956         break;
957         
958         case 125:
959             charcode = NSDownArrowFunctionKey;
960         break;
961         
962         case 126:
963             charcode = NSUpArrowFunctionKey;
964         break;
965     }
966     
967     if (charcode == 'a') {
968         unsigned long state;
969         long keyTrans;
970         char charCode;
971         Ptr kchr;
972         state = 0;
973         kchr = (Ptr) GetScriptVariable(smCurrentScript, smKCHRCache);
974         keyTrans = KeyTranslate(kchr, code, &state);
975         charCode = keyTrans;
976         [item setKeyEquivalent:[NSString stringWithCString:&charCode length:1]];
977     } else if (charcode != 'b') {
978         [item setKeyEquivalent:[NSString stringWithCharacters:&charcode length:1]];
979     }
980 }
981
982 @end