Added an about box menu item. Bumped versions to MT 1.5.2.
[MenuTunes.git] / MenuController.m
1 //
2 //  MenuController.m
3 //  MenuTunes
4 //
5 //  Created by Joseph Spiros on Wed Apr 30 2003.
6 //  Copyright (c) 2003 iThink Software. All rights reserved.
7 //
8
9 #import "MenuController.h"
10 #import "MainController.h"
11 #import "NetworkController.h"
12 #import "ITMTRemote.h"
13 #import <ITFoundation/ITDebug.h>
14 #import <ITKit/ITHotKeyCenter.h>
15 #import <ITKit/ITHotKey.h>
16 #import <ITKit/ITKeyCombo.h>
17 #import <ITKit/ITCategory-NSMenu.h>
18 #import <ITKit/ITAboutBox.h>
19
20 @interface MenuController (SubmenuMethods)
21 - (NSMenu *)ratingMenu;
22 - (NSMenu *)upcomingSongsMenu;
23 - (NSMenu *)playlistsMenu;
24 - (NSMenu *)eqMenu;
25 - (NSMenu *)artistsMenu;
26 - (NSMenu *)albumsMenu;
27 - (void)setKeyEquivalentForCode:(short)code andModifiers:(long)modifiers
28         onItem:(id <NSMenuItem>)item;
29 - (BOOL)iPodWithNameAutomaticallyUpdates:(NSString *)name;
30 @end
31
32 @implementation MenuController
33
34 - (id)init
35 {
36     if ( (self = [super init]) ) {
37         _menuLayout = [[NSMutableArray alloc] initWithCapacity:0];
38     }
39     return self;
40 }
41
42 - (NSMenu *)menu
43 {
44     NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
45     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
46     NSArray *menuArray = [defaults arrayForKey:@"menu"];
47     NSEnumerator *enumerator = [menuArray objectEnumerator];
48     NSString *nextObject;
49     id <NSMenuItem> tempItem;
50     NSEnumerator *itemEnum;
51     ITHotKey *hotKey;
52     NSArray *hotKeys = [[ITHotKeyCenter sharedCenter] allHotKeys];
53     ITMTRemote *mtr = [[MainController sharedController] currentRemote];
54     int currentSongRating = 0;
55     
56     //Get the information
57     NS_DURING
58         _currentPlaylist = [mtr currentPlaylistIndex];
59         _playingRadio = ([mtr currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist);
60         currentSongRating = ( [mtr currentSongRating] != -1 );
61     NS_HANDLER
62         [[MainController sharedController] networkError:localException];
63     NS_ENDHANDLER
64     
65     ITDebugLog(@"Reset menu if required.");
66     
67     //Kill the old submenu items
68     if ( (tempItem = [_currentMenu itemWithTag:1]) ) {
69         ITDebugLog(@"Removing \"Song Rating\" submenu.");
70         [tempItem setSubmenu:nil];
71     }
72     
73     if ( (tempItem = [_currentMenu itemWithTag:2]) ) {
74         ITDebugLog(@"Removing \"Upcoming Songs\" submenu.");
75         [tempItem setSubmenu:nil];
76     }
77     
78     if ( (tempItem = [_currentMenu itemWithTag:3]) ) {
79         ITDebugLog(@"Removing \"Playlists\" submenu.");
80         [tempItem setSubmenu:nil];
81     }
82     
83     if ( (tempItem = [_currentMenu itemWithTag:4]) ) {
84         ITDebugLog(@"Removing \"EQ Presets\" submenu.");
85         [tempItem setSubmenu:nil];
86     }
87     
88     if ( (tempItem = [_currentMenu itemWithTag:5]) ) {
89         ITDebugLog(@"Removing \"Artists\" submenu.");
90         [tempItem setSubmenu:nil];
91     }
92     
93     if ( (tempItem = [_currentMenu itemWithTag:6]) ) {
94         ITDebugLog(@"Removing \"Albums\" submenu.");
95         [tempItem setSubmenu:nil];
96     }
97     
98     ITDebugLog(@"Begin building menu.");
99     
100     //create our menu
101     while ( (nextObject = [enumerator nextObject]) ) {
102         //Main menu items
103         if ([nextObject isEqualToString:@"playPause"]) {
104             ITDebugLog(@"Add \"Play\"/\"Pause\" menu item.");
105             tempItem = [menu addItemWithTitle:NSLocalizedString(@"play", @"Play")
106                     action:@selector(performMainMenuAction:)
107                     keyEquivalent:@""];
108             [tempItem setTag:MTMenuPlayPauseItem];
109             [tempItem setTarget:self];
110             
111             itemEnum = [hotKeys objectEnumerator];
112             while ( (hotKey = [itemEnum nextObject]) ) {
113                 if ([[hotKey name] isEqualToString:@"PlayPause"]) {
114                     ITKeyCombo *combo = [hotKey keyCombo];
115                     [self setKeyEquivalentForCode:[combo keyCode]
116                           andModifiers:[combo modifiers]
117                           onItem:tempItem];
118                 }
119             }
120             
121             ITDebugLog(@"Set \"Play\"/\"Pause\" menu item's title to correct state.");
122             NS_DURING
123                 switch ([mtr playerPlayingState]) {
124                     case ITMTRemotePlayerPlaying:
125                         [tempItem setTitle:NSLocalizedString(@"pause", @"Pause")];
126                     break;
127                     case ITMTRemotePlayerRewinding:
128                     case ITMTRemotePlayerForwarding:
129                         [tempItem setTitle:NSLocalizedString(@"resume", @"Resume")];
130                     break;
131                     default:
132                     break;
133                 }
134             NS_HANDLER
135                 [[MainController sharedController] networkError:localException];
136             NS_ENDHANDLER
137         } else if ([nextObject isEqualToString:@"nextTrack"]) {
138             ITDebugLog(@"Add \"Next Track\" menu item.");
139             tempItem = [menu addItemWithTitle:NSLocalizedString(@"nextTrack", @"Next Track")
140                     action:@selector(performMainMenuAction:)
141                     keyEquivalent:@""];
142             
143             itemEnum = [hotKeys objectEnumerator];
144             while ( (hotKey = [itemEnum nextObject]) ) {
145                 if ([[hotKey name] isEqualToString:@"NextTrack"]) {
146                     ITKeyCombo *combo = [hotKey keyCombo];
147                     [self setKeyEquivalentForCode:[combo keyCode]
148                           andModifiers:[combo modifiers]
149                           onItem:tempItem];
150                 }
151             }
152             
153             if (_currentPlaylist) {
154                 [tempItem setTag:MTMenuNextTrackItem];
155                 [tempItem setTarget:self];
156             }
157         } else if ([nextObject isEqualToString:@"prevTrack"]) {
158             ITDebugLog(@"Add \"Previous Track\" menu item.");
159             tempItem = [menu addItemWithTitle:NSLocalizedString(@"prevTrack", @"Previous Track")
160                     action:@selector(performMainMenuAction:)
161                     keyEquivalent:@""];
162             
163             itemEnum = [hotKeys objectEnumerator];
164             while ( (hotKey = [itemEnum nextObject]) ) {
165                 if ([[hotKey name] isEqualToString:@"PrevTrack"]) {
166                     ITKeyCombo *combo = [hotKey keyCombo];
167                     [self setKeyEquivalentForCode:[combo keyCode]
168                           andModifiers:[combo modifiers]
169                           onItem:tempItem];
170                 }
171             }
172             
173             if (_currentPlaylist) {
174                 [tempItem setTag:MTMenuPreviousTrackItem];
175                 [tempItem setTarget:self];
176             }
177         } else if ([nextObject isEqualToString:@"fastForward"]) {
178             ITDebugLog(@"Add \"Fast Forward\" menu item.");
179             tempItem = [menu addItemWithTitle:NSLocalizedString(@"fastForward", @"Fast Forward")
180                     action:@selector(performMainMenuAction:)
181                     keyEquivalent:@""];
182             if (_currentPlaylist) {
183                 [tempItem setTag:MTMenuFastForwardItem];
184                 [tempItem setTarget:self];
185             }
186         } else if ([nextObject isEqualToString:@"rewind"]) {
187             ITDebugLog(@"Add \"Rewind\" menu item.");
188             tempItem = [menu addItemWithTitle:NSLocalizedString(@"rewind", @"Rewind")
189                     action:@selector(performMainMenuAction:)
190                     keyEquivalent:@""];
191             if (_currentPlaylist) {
192                 [tempItem setTag:MTMenuRewindItem];
193                 [tempItem setTarget:self];
194             }
195         } else if ([nextObject isEqualToString:@"showPlayer"]) {
196             ITDebugLog(@"Add \"Show Player\" menu item.");
197             NS_DURING
198                 tempItem = [menu addItemWithTitle:[NSString stringWithFormat:@"%@ %@",
199                                 NSLocalizedString(@"show", @"Show"),
200                                     [mtr playerSimpleName]]
201                                 action:@selector(performMainMenuAction:)
202                                 keyEquivalent:@""];
203             NS_HANDLER
204                 [[MainController sharedController] networkError:localException];
205             NS_ENDHANDLER
206             
207             itemEnum = [hotKeys objectEnumerator];
208             while ( (hotKey = [itemEnum nextObject]) ) {
209                 if ([[hotKey name] isEqualToString:@"ShowPlayer"]) {
210                     ITKeyCombo *combo = [hotKey keyCombo];
211                     [self setKeyEquivalentForCode:[combo keyCode]
212                           andModifiers:[combo modifiers]
213                           onItem:tempItem];
214                 }
215             }
216             
217             [tempItem setTarget:self];
218             [tempItem setTag:MTMenuShowPlayerItem];
219         } else if ([nextObject isEqualToString:@"preferences"]) {
220             ITDebugLog(@"Add \"Preferences...\" menu item.");
221             tempItem = [menu addItemWithTitle:NSLocalizedString(@"preferences", @"Preferences...")
222                     action:@selector(performMainMenuAction:)
223                     keyEquivalent:@""];
224             [tempItem setTag:MTMenuPreferencesItem];
225             [tempItem setTarget:self];
226         } else if ([nextObject isEqualToString:@"about"]) {
227                         ITDebugLog(@"Add \"About MenuTunes...\" menu item.");
228             tempItem = [menu addItemWithTitle:NSLocalizedString(@"about", @"About MenuTunes...")
229                     action:@selector(performMainMenuAction:)
230                     keyEquivalent:@""];
231             [tempItem setTag:MTMenuAboutItem];
232             [tempItem setTarget:self];
233                 } else if ([nextObject isEqualToString:@"quit"]) {
234             if ([[MainController sharedController] blingBling] == NO) {
235                 ITDebugLog(@"Add \"Register MenuTunes...\" menu item.");
236                 tempItem = [menu addItemWithTitle:NSLocalizedString(@"register", @"Register MenuTunes...") action:@selector(performMainMenuAction:) keyEquivalent:@""];
237                 [tempItem setTag:MTMenuRegisterItem];
238                 [tempItem setTarget:self];
239             }
240             ITDebugLog(@"Add \"Quit\" menu item.");
241             tempItem = [menu addItemWithTitle:NSLocalizedString(@"quit", @"Quit")
242                     action:@selector(performMainMenuAction:)
243                     keyEquivalent:@""];
244             [tempItem setTag:MTMenuQuitItem];
245             [tempItem setTarget:self];
246         } else if ([nextObject isEqualToString:@"trackInfo"]) {
247             ITDebugLog(@"Check to see if a Track is playing...");
248             //Handle playing radio too
249             if (_currentTrack != -1 && _currentPlaylist > 0) {
250                 NSString *title = nil;
251                 NS_DURING
252                     title = [mtr currentSongTitle];
253                 NS_HANDLER
254                     [[MainController sharedController] networkError:localException];
255                 NS_ENDHANDLER
256                 ITDebugLog(@"A Track is Playing, Add \"Track Info\" menu items.");
257                 ITDebugLog(@"Add \"Now Playing\" menu item.");
258                 [menu addItemWithTitle:NSLocalizedString(@"nowPlaying", @"Now Playing") action:NULL keyEquivalent:@""];
259                 
260                 if ([title length] > 0) {
261                     ITDebugLog(@"Add Track Title (\"%@\") menu item.", title);
262                     [menu indentItem:
263                         [menu addItemWithTitle:title action:nil keyEquivalent:@""]];
264                 }
265                 
266                 if (!_playingRadio) {
267                     if ([defaults boolForKey:@"showAlbum"]) {
268                         NSString *curAlbum = nil;
269                         NS_DURING
270                             curAlbum = [mtr currentSongAlbum];
271                         NS_HANDLER
272                             [[MainController sharedController] networkError:localException];
273                         NS_ENDHANDLER
274                         ITDebugLog(@"Add Track Album (\"%@\") menu item.", curAlbum);
275                         if ( curAlbum ) {
276                             [menu indentItem:
277                                 [menu addItemWithTitle:curAlbum action:nil keyEquivalent:@""]];
278                         }
279                     }
280                     
281                     if ([defaults boolForKey:@"showArtist"]) {
282                         NSString *curArtist = nil;
283                         NS_DURING
284                             curArtist = [mtr currentSongArtist];
285                         NS_HANDLER
286                             [[MainController sharedController] networkError:localException];
287                         NS_ENDHANDLER
288                         ITDebugLog(@"Add Track Artist (\"%@\") menu item.", curArtist);
289                         if ( curArtist ) {
290                             [menu indentItem:
291                                 [menu addItemWithTitle:curArtist action:nil keyEquivalent:@""]];
292                         }
293                     }
294                     
295                     if ([defaults boolForKey:@"showComposer"]) {
296                         NSString *curComposer = nil;
297                         NS_DURING
298                             curComposer = [mtr currentSongComposer];
299                         NS_HANDLER
300                             [[MainController sharedController] networkError:localException];
301                         NS_ENDHANDLER
302                         ITDebugLog(@"Add Track Composer (\"%@\") menu item.", curComposer);
303                         if ( curComposer ) {
304                             [menu indentItem:
305                                 [menu addItemWithTitle:curComposer action:nil keyEquivalent:@""]];
306                         }
307                     }
308                     
309                     if ([defaults boolForKey:@"showTrackNumber"]) {
310                         int track = 0;
311                         NS_DURING
312                             track = [mtr currentSongTrack];
313                         NS_HANDLER
314                             [[MainController sharedController] networkError:localException];
315                         NS_ENDHANDLER
316                         ITDebugLog(@"Add Track Number (\"Track %i\") menu item.", track);
317                         if ( track > 0 ) {
318                             [menu indentItem:
319                                 [menu addItemWithTitle:[NSString stringWithFormat:@"%@ %i", NSLocalizedString(@"track", @"Track"), track] action:nil keyEquivalent:@""]];
320                         }
321                     }
322                 }
323                 
324                 NS_DURING
325                     if ([defaults boolForKey:@"showTime"] && ( ([mtr currentSongElapsed] != nil) || ([mtr currentSongLength] != nil) )) {
326                         ITDebugLog(@"Add Track Elapsed (\"%@/%@\") menu item.", [mtr currentSongElapsed], [mtr currentSongLength]);
327                         [menu indentItem:[menu addItemWithTitle:[NSString stringWithFormat:@"%@/%@", [mtr currentSongElapsed], [mtr currentSongLength]] action:nil keyEquivalent:@""]];
328                     }
329                 NS_HANDLER
330                     [[MainController sharedController] networkError:localException];
331                 NS_ENDHANDLER
332                 
333                 if (!_playingRadio) {
334                     NS_DURING
335                         if ([defaults boolForKey:@"showPlayCount"] && [mtr currentSource] == ITMTRemoteLibrarySource) {
336                             [menu indentItem:[menu addItemWithTitle:[NSString stringWithFormat:@"Play Count: %i", [mtr currentSongPlayCount]] action:nil keyEquivalent:@""]];
337                         }
338                         if ([defaults boolForKey:@"showTrackRating"] && ( [mtr currentSongRating] != -1.0 )) {
339                             NSString *string = nil;
340                             switch ((int)([mtr currentSongRating] * 5)) {
341                                 case 0:
342                                     string = [NSString stringWithUTF8String:"☆☆☆☆☆"];
343                                 break;
344                                 case 1:
345                                     string = [NSString stringWithUTF8String:"★☆☆☆☆"];
346                                 break;
347                                 case 2:
348                                     string = [NSString stringWithUTF8String:"★★☆☆☆"];
349                                 break;
350                                 case 3:
351                                     string = [NSString stringWithUTF8String:"★★★☆☆"];
352                                 break;
353                                 case 4:
354                                     string = [NSString stringWithUTF8String:"★★★★☆"];
355                                 break;
356                                 case 5:
357                                     string = [NSString stringWithUTF8String:"★★★★★"];
358                                 break;
359                             }
360                             ITDebugLog(@"Add Track Rating (\"%@\") menu item.", string);
361                             [menu indentItem:[menu addItemWithTitle:string action:nil keyEquivalent:@""]];
362                         }
363                     NS_HANDLER
364                         [[MainController sharedController] networkError:localException];
365                     NS_ENDHANDLER
366                     
367                     /*if ([tempItem respondsToSelector:@selector(setAttributedTitle:)] && [defaults boolForKey:@"showAlbumArtwork"] && ![[NetworkController sharedController] isConnectedToServer]) {
368                         NSImage *image = [mtr currentSongAlbumArt];
369                         if (image) {
370                             NSSize oldSize, newSize;
371                             oldSize = [image size];
372                             if (oldSize.width > oldSize.height) newSize = NSMakeSize(110,oldSize.height * (110.0f / oldSize.width));
373                             else newSize = NSMakeSize(oldSize.width * (110.0f / oldSize.height),110);
374                             image = [[[[NSImage alloc] initWithData:[image TIFFRepresentation]] autorelease] imageScaledSmoothlyToSize:newSize];
375                             
376                             tempItem = [menu addItemWithTitle:@"" action:nil keyEquivalent:@""];
377                             NSTextAttachment *attachment = [[[NSTextAttachment alloc] init] autorelease];
378                             [[attachment attachmentCell] setImage:image];
379                             NSAttributedString *attrString = [NSAttributedString attributedStringWithAttachment:attachment];
380                             [tempItem setAttributedTitle:attrString];
381                         }
382                     }*/
383                 }
384             } else {
385                 ITDebugLog(@"No Track is Playing, Add \"No Song\" menu item.");
386                 [menu addItemWithTitle:NSLocalizedString(@"noSong", @"No Song") action:NULL keyEquivalent:@""];
387             }
388         } else if ([nextObject isEqualToString:@"separator"]) {
389             ITDebugLog(@"Add a separator menu item.");
390             [menu addItem:[NSMenuItem separatorItem]];
391         //Submenu items
392         } else if ([nextObject isEqualToString:@"playlists"]) {
393             ITDebugLog(@"Add \"Playlists\" submenu.");
394             tempItem = [menu addItemWithTitle:NSLocalizedString(@"playlists", @"Playlists")
395                     action:nil
396                     keyEquivalent:@""];
397             [tempItem setSubmenu:_playlistsMenu];
398             [tempItem setTag:3];
399         } else if ([nextObject isEqualToString:@"eqPresets"]) {
400             ITDebugLog(@"Add \"EQ Presets\" submenu.");
401             tempItem = [menu addItemWithTitle:NSLocalizedString(@"eqPresets", @"EQ Presets")
402                     action:nil
403                     keyEquivalent:@""];
404             [tempItem setSubmenu:_eqMenu];
405             [tempItem setTag:4];
406             
407             itemEnum = [[_eqMenu itemArray] objectEnumerator];
408             while ( (tempItem = [itemEnum nextObject]) ) {
409                 [tempItem setState:NSOffState];
410             }
411             NS_DURING
412                 [[_eqMenu itemAtIndex:0] setState:[mtr equalizerEnabled] ? NSOnState : NSOffState];
413                 [[_eqMenu itemAtIndex:([mtr currentEQPresetIndex] + 1)] setState:NSOnState];
414             NS_HANDLER
415                 [[MainController sharedController] networkError:localException];
416             NS_ENDHANDLER
417         } else if ([nextObject isEqualToString:@"songRating"] && currentSongRating) {
418             ITDebugLog(@"Add \"Song Rating\" submenu.");
419             tempItem = [menu addItemWithTitle:NSLocalizedString(@"songRating", @"Song Rating")
420                     action:nil
421                     keyEquivalent:@""];
422             [tempItem setSubmenu:_ratingMenu];
423             [tempItem setTag:1];
424             if (_playingRadio || !_currentPlaylist) {
425                 [tempItem setEnabled:NO];
426             }
427             
428             itemEnum = [[_ratingMenu itemArray] objectEnumerator];
429             while ( (tempItem = [itemEnum nextObject]) ) {
430                 [tempItem setState:NSOffState];
431             }
432             
433             NS_DURING
434                 [[_ratingMenu itemAtIndex:([mtr currentSongRating] * 5)] setState:NSOnState];
435             NS_HANDLER
436                 [[MainController sharedController] networkError:localException];
437             NS_ENDHANDLER
438         } else if ([nextObject isEqualToString:@"upcomingSongs"]) {
439             ITDebugLog(@"Add \"Upcoming Songs\" submenu.");
440             tempItem = [menu addItemWithTitle:NSLocalizedString(@"upcomingSongs", @"Upcoming Songs")
441                     action:nil
442                     keyEquivalent:@""];
443             [tempItem setSubmenu:_upcomingSongsMenu];
444             [tempItem setTag:2];
445             if (_playingRadio || !_currentPlaylist) {
446                 [tempItem setEnabled:NO];
447             }
448         } else if ([nextObject isEqualToString:@"artists"]) {
449             ITDebugLog(@"Add \"Artists\" submenu.");
450             tempItem = [menu addItemWithTitle:NSLocalizedString(@"artists", @"Artists")
451                     action:nil
452                     keyEquivalent:@""];
453             [tempItem setSubmenu:_artistsMenu];
454             [tempItem setTag:5];
455         } else if ([nextObject isEqualToString:@"albums"]) {
456             ITDebugLog(@"Add \"Albums\" submenu.");
457             tempItem = [menu addItemWithTitle:NSLocalizedString(@"albums", @"Albums")
458                     action:nil
459                     keyEquivalent:@""];
460             [tempItem setSubmenu:_albumsMenu];
461             [tempItem setTag:6];
462         }
463     }
464     ITDebugLog(@"Finished building menu.");
465     [_currentMenu release];
466     _currentMenu = menu;
467     return _currentMenu;
468 }
469
470 - (NSMenu *)menuForNoPlayer
471 {
472     NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
473     id <NSMenuItem> tempItem = nil;
474     ITDebugLog(@"Creating menu for when player isn't running.");
475     NS_DURING
476         ITDebugLog(@"Add \"Open %@\" menu item.", [[[MainController sharedController] currentRemote] playerSimpleName]);
477         tempItem = [menu addItemWithTitle:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"open", @"Open"), [[[MainController sharedController] currentRemote] playerSimpleName]] action:@selector(performMainMenuAction:) keyEquivalent:@""];
478     NS_HANDLER
479         [[MainController sharedController] networkError:localException];
480     NS_ENDHANDLER
481     [tempItem setTag:MTMenuShowPlayerItem];
482     [tempItem setTarget:self];
483     ITDebugLog(@"Add a separator menu item.");
484     [menu addItem:[NSMenuItem separatorItem]];
485     ITDebugLog(@"Add \"Preferences...\" menu item.");
486     tempItem = [menu addItemWithTitle:NSLocalizedString(@"preferences", @"Preferences...") action:@selector(performMainMenuAction:) keyEquivalent:@""];
487     [tempItem setTag:MTMenuPreferencesItem];
488     [tempItem setTarget:self];
489     if ([[MainController sharedController] blingBling] == NO) {
490         ITDebugLog(@"Add \"Register MenuTunes...\" menu item.");
491         tempItem = [menu addItemWithTitle:NSLocalizedString(@"register", @"Register MenuTunes...") action:@selector(performMainMenuAction:) keyEquivalent:@""];
492         [tempItem setTag:MTMenuRegisterItem];
493         [tempItem setTarget:self];
494     }
495     ITDebugLog(@"Add \"Quit\" menu item.");
496     tempItem = [menu addItemWithTitle:NSLocalizedString(@"quit", @"Quit") action:@selector(performMainMenuAction:) keyEquivalent:@""];
497     [tempItem setTag:MTMenuQuitItem];
498     [tempItem setTarget:self];
499     return [menu autorelease];
500 }
501
502 - (BOOL)rebuildSubmenus
503 {
504     NSArray *menu = [[NSUserDefaults standardUserDefaults] arrayForKey:@"menu"];
505     ITDebugLog(@"Rebuilding all of the submenus.");
506     NS_DURING
507                 _currentTrack = [[[MainController sharedController] currentRemote] currentSongIndex];
508                 if (_currentTrack > -1) {
509                         _currentPlaylist = [[[MainController sharedController] currentRemote] currentPlaylistIndex];
510                 }
511         _playingRadio = ([[[MainController sharedController] currentRemote] currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist);
512     NS_HANDLER
513         [[MainController sharedController] networkError:localException];
514     NS_ENDHANDLER
515     ITDebugLog(@"Releasing old submenus.");
516         _continue = YES;
517     ITDebugLog(@" - Rating menu");
518     [_ratingMenu release];
519         _ratingMenu = nil;
520     ITDebugLog(@" - Upcoming songs menu");
521     [_upcomingSongsMenu release];
522         _upcomingSongsMenu = nil;
523     ITDebugLog(@" - Playlists menu");
524     [_playlistsMenu release];
525         _playlistsMenu = nil;
526     ITDebugLog(@" - EQ menu");
527     [_eqMenu release];
528         _eqMenu = nil;
529     
530     ITDebugLog(@"Beginning Rebuild of \"Song Rating\" submenu.");
531     _ratingMenu = [self ratingMenu];
532     ITDebugLog(@"Beginning Rebuild of \"Upcoming Songs\" submenu.");
533     _upcomingSongsMenu = [self upcomingSongsMenu];
534         if (_continue) {
535                 ITDebugLog(@"Beginning Rebuild of \"Playlists\" submenu.");
536                 _playlistsMenu = [self playlistsMenu];
537         }
538         if (_continue) {
539                 ITDebugLog(@"Beginning Rebuild of \"EQ Presets\" submenu.");
540                 _eqMenu = [self eqMenu];
541         }
542     if (_continue && [menu containsObject:@"artists"]) {
543         ITDebugLog(@"Releasing artists menu");
544         [_artistsMenu release];
545         ITDebugLog(@"Beginning Rebuild of \"Artists\" submenu.");
546         _artistsMenu = [self artistsMenu];
547     }
548     
549     if (_continue && [menu containsObject:@"albums"]) {
550         ITDebugLog(@"Releasing albums menu");
551         [_albumsMenu release];
552         ITDebugLog(@"Beginning Rebuild of \"Albums\" submenu.");
553         _albumsMenu = [self albumsMenu];
554     }
555     ITDebugLog(@"Done rebuilding all of the submenus.");
556         return _continue;
557 }
558
559 - (NSMenu *)ratingMenu
560 {
561     NSMenu *ratingMenu = [[NSMenu alloc] initWithTitle:@""];
562     NSEnumerator *itemEnum;
563     id  anItem;
564     int itemTag = 0;
565     SEL itemSelector = @selector(performRatingMenuAction:);
566     
567     ITDebugLog(@"Building \"Song Rating\" menu.");
568     
569     [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"☆☆☆☆☆"] action:nil keyEquivalent:@""];
570     [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"★☆☆☆☆"] action:nil keyEquivalent:@""];
571     [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"★★☆☆☆"] action:nil keyEquivalent:@""];
572     [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"★★★☆☆"] action:nil keyEquivalent:@""];
573     [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"★★★★☆"] action:nil keyEquivalent:@""];
574     [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"★★★★★"] action:nil keyEquivalent:@""];
575     
576     itemEnum = [[ratingMenu itemArray] objectEnumerator];
577     while ( (anItem = [itemEnum nextObject]) ) {
578         ITDebugLog(@"Setting up \"%@\" menu item.", [anItem title]);
579         [anItem setAction:itemSelector];
580         [anItem setTarget:self];
581         [anItem setTag:itemTag];
582         itemTag += 20;
583     }
584     ITDebugLog(@"Done Building \"Song Rating\" menu.");
585     return ratingMenu;
586 }
587
588 - (NSMenu *)upcomingSongsMenu
589 {
590     NSMenu *upcomingSongsMenu;
591     int numSongs = 0, numSongsInAdvance = [[NSUserDefaults standardUserDefaults] integerForKey:@"SongsInAdvance"];
592         if (_currentTrack == -1) {
593                 return nil;
594         }
595     NS_DURING
596         numSongs = [[[MainController sharedController] currentRemote] numberOfSongsInPlaylistAtIndex:_currentPlaylist];
597     NS_HANDLER
598         [[MainController sharedController] networkError:localException];
599     NS_ENDHANDLER
600     
601         if (numSongs == -1) {
602                 return nil;
603         }
604         upcomingSongsMenu = [[NSMenu alloc] initWithTitle:@""];
605         NS_DURING
606     ITDebugLog(@"Building \"Upcoming Songs\" menu.");
607     if (_currentPlaylist && !_playingRadio) {
608         if (numSongs > 0) {
609             int i;
610             for (i = _currentTrack + 1; i <= _currentTrack + numSongsInAdvance; i++) {
611                 if (i <= numSongs) {
612                     NSString *curSong = nil;
613                     NS_DURING
614                         curSong = [[[MainController sharedController] currentRemote] songTitleAtIndex:i];
615                     NS_HANDLER
616                         [[MainController sharedController] networkError:localException];
617                     NS_ENDHANDLER
618                     id <NSMenuItem> songItem;
619                     ITDebugLog(@"Adding song: %@", curSong);
620                     songItem = [upcomingSongsMenu addItemWithTitle:curSong action:@selector(performUpcomingSongsMenuAction:) keyEquivalent:@""];
621                     [songItem setTag:i];
622                     [songItem setTarget:self];
623                 } else {
624                     break;
625                 }
626             }
627         }
628         
629         if ([upcomingSongsMenu numberOfItems] == 0) {
630             [upcomingSongsMenu addItemWithTitle:NSLocalizedString(@"noUpcomingSongs", @"No upcoming songs.") action:NULL keyEquivalent:@""];
631         }
632     }
633     ITDebugLog(@"Done Building \"Upcoming Songs\" menu.");
634         NS_VALUERETURN(upcomingSongsMenu, NSMenu *);
635         NS_HANDLER
636                 [upcomingSongsMenu release];
637                 _continue = NO;
638                 NS_VALUERETURN(nil, NSMenu *);
639         NS_ENDHANDLER
640 }
641
642 /*- (NSMenu *)playlistsMenu
643 {
644     NSMenu *playlistsMenu = [[NSMenu alloc] initWithTitle:@""];
645     NSArray *playlists;
646     id <NSMenuItem> tempItem;
647     ITMTRemotePlayerSource source = [[[MainController sharedController] currentRemote] currentSource];
648     int i;
649     NS_DURING
650         playlists = [[[MainController sharedController] currentRemote] playlists];
651     NS_HANDLER
652         [[MainController sharedController] networkError:localException];
653     NS_ENDHANDLER
654     
655     ITDebugLog(@"Building \"Playlists\" menu.");
656     
657     for (i = 0; i < [playlists count]; i++) {
658         NSString *curPlaylist = [playlists objectAtIndex:i];
659         ITDebugLog(@"Adding playlist: %@", curPlaylist);
660         tempItem = [playlistsMenu addItemWithTitle:curPlaylist action:@selector(performPlaylistMenuAction:) keyEquivalent:@""];
661         [tempItem setTag:i + 1];
662         [tempItem setTarget:self];
663     }
664     
665     if (source == ITMTRemoteRadioSource) {
666         [[playlistsMenu addItemWithTitle:NSLocalizedString(@"radio", @"Radio") action:NULL keyEquivalent:@""] setState:NSOnState];
667     } else if (source == ITMTRemoteGenericDeviceSource) {
668         [[playlistsMenu addItemWithTitle:NSLocalizedString(@"genericDevice", @"Generic Device") action:NULL keyEquivalent:@""] setState:NSOnState];
669     } else if (source == ITMTRemoteiPodSource) {
670         [[playlistsMenu addItemWithTitle:NSLocalizedString(@"iPod", @"iPod") action:NULL keyEquivalent:@""] setState:NSOnState];
671     } else if (source == ITMTRemoteCDSource) {
672         [[playlistsMenu addItemWithTitle:NSLocalizedString(@"cd", @"CD") action:NULL keyEquivalent:@""] setState:NSOnState];
673     } else if (source == ITMTRemoteSharedLibrarySource) {
674         [[playlistsMenu addItemWithTitle:NSLocalizedString(@"sharedLibrary", @"Shared Library") action:NULL keyEquivalent:@""] setState:NSOnState];
675     } else if (source == ITMTRemoteLibrarySource && _currentPlaylist) {
676         [[playlistsMenu itemAtIndex:_currentPlaylist - 1] setState:NSOnState];
677     }
678     ITDebugLog(@"Done Building \"Playlists\" menu");
679     return playlistsMenu;
680 }*/
681
682
683 - (NSMenu *)playlistsMenu
684 {
685     NSMenu *playlistsMenu = [[NSMenu alloc] initWithTitle:@""];
686     NSArray *playlists = nil;
687     id <NSMenuItem> tempItem;
688     ITMTRemotePlayerSource source = [[[MainController sharedController] currentRemote] currentSource];
689     int i, j;
690     NSMutableArray *indices = [[NSMutableArray alloc] init];
691     NS_DURING
692         playlists = [[[MainController sharedController] currentRemote] playlists];
693     NS_HANDLER
694         [[MainController sharedController] networkError:localException];
695     NS_ENDHANDLER
696         
697         if (!playlists) {
698                 [playlistsMenu release];
699                 return nil;
700         }
701         NS_DURING
702     ITDebugLog(@"Building \"Playlists\" menu.");
703     {
704         NSArray *curPlaylist = [playlists objectAtIndex:0];
705         NSString *name = [curPlaylist objectAtIndex:0];
706         ITDebugLog(@"Adding main source: %@", name);
707         for (i = 3; i < [curPlaylist count]; i++) {
708             ITDebugLog(@"Adding playlist: %@", [curPlaylist objectAtIndex:i]);
709             tempItem = [playlistsMenu addItemWithTitle:[curPlaylist objectAtIndex:i] action:@selector(performPlaylistMenuAction:) keyEquivalent:@""];
710             [tempItem setTag:i - 1];
711             [tempItem setTarget:self];
712         }
713         ITDebugLog(@"Adding index to the index array.");
714         [indices addObject:[curPlaylist objectAtIndex:2]];
715     }
716         
717     if ([playlists count] > 1) {
718         if ([[[playlists objectAtIndex:1] objectAtIndex:1] intValue] == ITMTRemoteRadioSource) {
719             [indices addObject:[[playlists objectAtIndex:1] objectAtIndex:2]];
720             if (source == ITMTRemoteRadioSource) {
721                 [playlistsMenu addItem:[NSMenuItem separatorItem]];
722                 [[playlistsMenu addItemWithTitle:NSLocalizedString(@"radio", @"Radio") action:@selector(performPlaylistMenuAction:) keyEquivalent:@""] setState:NSOnState];
723             }
724         } else {
725             [playlistsMenu addItem:[NSMenuItem separatorItem]];
726         }
727     }
728         
729     if ([playlists count] > 1) {
730         for (i = 1; i < [playlists count]; i++) {
731             NSArray *curPlaylist = [playlists objectAtIndex:i];
732             if ([[curPlaylist objectAtIndex:1] intValue] != ITMTRemoteRadioSource) {
733                 NSString *name = [curPlaylist objectAtIndex:0];
734                 NSMenu *submenu = [[NSMenu alloc] init];
735                 ITDebugLog(@"Adding source: %@", name);
736                 
737                 if ( ([[curPlaylist objectAtIndex:1] intValue] == ITMTRemoteiPodSource) && [self iPodWithNameAutomaticallyUpdates:name] ) {
738                     ITDebugLog(@"Invalid iPod source.");
739                     [playlistsMenu addItemWithTitle:name action:NULL keyEquivalent:@""];
740                 } else {
741                     for (j = 3; j < [curPlaylist count]; j++) {
742                         ITDebugLog(@"Adding playlist: %@", [curPlaylist objectAtIndex:j]);
743                         tempItem = [submenu addItemWithTitle:[curPlaylist objectAtIndex:j] action:@selector(performPlaylistMenuAction:) keyEquivalent:@""];
744                         [tempItem setTag:(i * 1000) + j - 1];
745                         [tempItem setTarget:self];
746                     }
747                     [[playlistsMenu addItemWithTitle:name action:NULL keyEquivalent:@""] setSubmenu:[submenu autorelease]];
748                 }
749                 ITDebugLog(@"Adding index to the index array.");
750                 [indices addObject:[curPlaylist objectAtIndex:2]];
751             }
752         }
753     }
754     ITDebugLog(@"Checking the current source.");
755         NS_DURING
756         if (_currentPlaylist != -1) {
757                 if ( (source == ITMTRemoteSharedLibrarySource) || (source == ITMTRemoteiPodSource) || (source == ITMTRemoteGenericDeviceSource) || (source == ITMTRemoteCDSource) ) {
758                         tempItem = [playlistsMenu itemAtIndex:[playlistsMenu numberOfItems] + [indices indexOfObject:[NSNumber numberWithInt:[[[MainController sharedController] currentRemote] currentSourceIndex]]] - [indices count]];
759                         [tempItem setState:NSOnState];
760                         [[[tempItem submenu] itemAtIndex:_currentPlaylist - 1] setState:NSOnState];
761                 } else if (source == ITMTRemoteLibrarySource && _currentPlaylist) {
762                         [[playlistsMenu itemAtIndex:_currentPlaylist - 1] setState:NSOnState];
763                 }
764         }
765         NS_HANDLER
766         NS_ENDHANDLER
767     [indices release];
768     tempItem = [playlistsMenu addItemWithTitle:NSLocalizedString(@"refresh", @"Refresh") action:@selector(rebuildSubmenus) keyEquivalent:@""];
769     [tempItem setTarget:self];
770     [tempItem setImage:[NSImage imageNamed:@"ChasingArrow"]];
771     ITDebugLog(@"Done Building \"Playlists\" menu");
772     NS_VALUERETURN(playlistsMenu, NSMenu *);
773         NS_HANDLER
774                 [playlistsMenu release];
775                 _continue = NO;
776                 NS_VALUERETURN(nil, NSMenu *);
777         NS_ENDHANDLER
778 }
779
780 - (NSMenu *)eqMenu
781 {
782     NSMenu *eqMenu = [[NSMenu alloc] initWithTitle:@""];
783     NSArray *eqPresets = nil;
784     id <NSMenuItem> tempItem;
785     int i;
786     
787     NS_DURING
788         eqPresets = [[[MainController sharedController] currentRemote] eqPresets];
789     NS_HANDLER
790         [[MainController sharedController] networkError:localException];
791     NS_ENDHANDLER
792     
793     ITDebugLog(@"Building \"EQ Presets\" menu.");
794     
795     tempItem = [eqMenu addItemWithTitle:@"Enabled" action:@selector(performEqualizerMenuAction:) keyEquivalent:@""];
796     [tempItem setTag:-1];
797     [tempItem setTarget:self];
798     [eqMenu addItem:[NSMenuItem separatorItem]];
799     
800     for (i = 0; i < [eqPresets count]; i++) {
801         NSString *name;
802            if ( ( name = [eqPresets objectAtIndex:i] ) ) {
803             ITDebugLog(@"Adding EQ Preset: %@", name);
804             tempItem = [eqMenu addItemWithTitle:name
805                     action:@selector(performEqualizerMenuAction:)
806                     keyEquivalent:@""];
807             [tempItem setTag:i];
808             [tempItem setTarget:self];
809            }
810     }
811     ITDebugLog(@"Done Building \"EQ Presets\" menu");
812     return eqMenu;
813 }
814
815 - (NSMenu *)artistsMenu
816 {
817     NSMenu *artistsMenu = [[NSMenu alloc] initWithTitle:@"Artists"];
818     NSEnumerator *artistsEnumerator;
819     NSString *nextArtist;
820     id <NSMenuItem> tempItem;
821     ITDebugLog(@"Building \"Artists\" menu.");
822     NS_DURING
823         artistsEnumerator = [[[[MainController sharedController] currentRemote] artists] objectEnumerator];
824         while ( (nextArtist = [artistsEnumerator nextObject]) ) {
825             tempItem = [artistsMenu addItemWithTitle:nextArtist action:@selector(performBrowseMenuAction:) keyEquivalent:@""];
826             [tempItem setTarget:self];
827         }
828     NS_HANDLER
829         [[MainController sharedController] networkError:localException];
830     NS_ENDHANDLER
831     ITDebugLog(@"Done Building \"Artists\" menu");
832     return artistsMenu;
833 }
834
835 - (NSMenu *)albumsMenu
836 {
837     NSMenu *albumsMenu = [[NSMenu alloc] initWithTitle:@"Albums"];
838     NSEnumerator *albumsEnumerator;
839     NSString *nextAlbum;
840     id <NSMenuItem> tempItem;
841     ITDebugLog(@"Building \"Albums\" menu.");
842     NS_DURING
843         albumsEnumerator = [[[[MainController sharedController] currentRemote] albums] objectEnumerator];
844         while ( (nextAlbum = [albumsEnumerator nextObject]) ) {
845             tempItem = [albumsMenu addItemWithTitle:nextAlbum action:@selector(performBrowseMenuAction:) keyEquivalent:@""];
846             [tempItem setTarget:self];
847         }
848     NS_HANDLER
849         [[MainController sharedController] networkError:localException];
850     NS_ENDHANDLER
851     ITDebugLog(@"Done Building \"Albums\" menu");
852     return albumsMenu;
853 }
854
855 - (void)performMainMenuAction:(id)sender
856 {
857     switch ( [sender tag] )
858     {
859         case MTMenuPlayPauseItem:
860             ITDebugLog(@"Performing Menu Action: Play/Pause");
861             [[MainController sharedController] playPause];
862             break;
863         case MTMenuFastForwardItem:
864             ITDebugLog(@"Performing Menu Action: Fast Forward");
865             [[MainController sharedController] fastForward];
866             break;
867         case MTMenuRewindItem:
868             ITDebugLog(@"Performing Menu Action: Rewind");
869             [[MainController sharedController] rewind];
870             break;
871         case MTMenuPreviousTrackItem:
872             ITDebugLog(@"Performing Menu Action: Previous Track");
873             [[MainController sharedController] prevSong];
874             break;
875         case MTMenuNextTrackItem:
876             ITDebugLog(@"Performing Menu Action: Next Track");
877             [[MainController sharedController] nextSong];
878             break;
879         case MTMenuShowPlayerItem:
880             ITDebugLog(@"Performing Menu Action: Show Main Interface");
881             [[MainController sharedController] showPlayer];
882             break;
883         case MTMenuPreferencesItem:
884             ITDebugLog(@"Performing Menu Action: Preferences...");
885             [[MainController sharedController] showPreferences];
886             break;
887                 case MTMenuAboutItem:
888                         ITDebugLog(@"Performing Menu Action: About MenuTunes...");
889                         [[ITAboutBox sharedController] showAboutBox];
890                         break;
891         case MTMenuQuitItem:
892             ITDebugLog(@"Performing Menu Action: Quit");
893             [[MainController sharedController] quitMenuTunes];
894             break;
895         case MTMenuRegisterItem:
896             ITDebugLog(@"Performing Menu Action: Register");
897             [[MainController sharedController] blingNow];
898             break;
899         default:
900             ITDebugLog(@"Performing Menu Action: Unimplemented Menu Item OR Child-bearing Menu Item");
901             break;
902     }
903 }
904
905 - (void)performRatingMenuAction:(id)sender
906 {
907     ITDebugLog(@"Rating action selected on item with tag %i", [sender tag]);
908     [[MainController sharedController] selectSongRating:[sender tag]];
909 }
910
911 - (void)performPlaylistMenuAction:(id)sender
912 {
913     ITDebugLog(@"Playlist action selected on item with tag %i", [sender tag]);
914     [[MainController sharedController] selectPlaylistAtIndex:[sender tag]];
915 }
916
917 - (void)performEqualizerMenuAction:(id)sender
918 {
919     ITDebugLog(@"EQ action selected on item with tag %i", [sender tag]);
920     [[MainController sharedController] selectEQPresetAtIndex:[sender tag]];
921 }
922
923 - (void)performUpcomingSongsMenuAction:(id)sender
924 {
925     ITDebugLog(@"Song action selected on item with tag %i", [sender tag]);
926     [[MainController sharedController] selectSongAtIndex:[sender tag]];
927 }
928
929 - (void)performBrowseMenuAction:(id)sender
930 {
931     ITDebugLog(@"Browse action selected on item named %@", [sender title]);
932     /*
933     ** 1 - Artist
934     ** 2 - Album
935     ** 3 - Genre?
936     */
937     [[MainController sharedController] makePlaylistWithTerm:[sender title] ofType:(([[[sender menu] title] isEqualToString:@"Artists"]) ? 1 : 2)];
938 }
939
940 - (void)updateMenu
941 {
942     ITDebugLog(@"Update Menu");
943     [_currentMenu update];
944 }
945
946 - (BOOL)validateMenuItem:(id <NSMenuItem>)menuItem
947 {
948     return YES;
949 }
950
951 //This is never used I know, keep it though
952 - (NSString *)systemUIColor
953 {
954     NSDictionary *tmpDict;
955     NSNumber *tmpNumber;
956     if ( (tmpDict = [NSDictionary dictionaryWithContentsOfFile:[@"~/Library/Preferences/.GlobalPreferences.plist" stringByExpandingTildeInPath]]) ) {
957         if ( (tmpNumber = [tmpDict objectForKey:@"AppleAquaColorVariant"]) ) {
958             if ( ([tmpNumber intValue] == 1) ) {
959                 return @"Aqua";
960             } else {
961                 return @"Graphite";
962             }
963         } else {
964             return @"Aqua";
965         }
966     } else {
967         return @"Aqua";
968     }
969 }
970
971 - (void)setKeyEquivalentForCode:(short)code andModifiers:(long)modifiers
972         onItem:(id <NSMenuItem>)item
973 {
974     unichar charcode = 'a';
975     int i;
976     long cocoaModifiers = 0;
977     static long carbonToCocoa[6][2] = 
978     {
979         { cmdKey, NSCommandKeyMask },
980         { optionKey, NSAlternateKeyMask },
981         { controlKey, NSControlKeyMask },
982         { shiftKey, NSShiftKeyMask },
983     };
984     
985     ITDebugLog(@"Setting Key Equivelent on menu item \"%@\".", [item title]);
986     
987     for (i = 0; i < 6; i++) {
988         if (modifiers & carbonToCocoa[i][0]) {
989             cocoaModifiers += carbonToCocoa[i][1];
990         }
991     }
992     [item setKeyEquivalentModifierMask:cocoaModifiers];
993     
994     //Missing key combos for some keys. Must find them later.
995     switch (code)
996     {
997         case 36:
998             ITDebugLog(@"Keycode for menu item \"%@\": 36 (Return)", [item title]);
999             charcode = '\r';
1000         break;
1001         
1002         case 48:
1003             ITDebugLog(@"Keycode for menu item \"%@\": 48 (Tab)", [item title]);
1004             charcode = '\t';
1005         break;
1006         
1007         //Space -- ARGH!
1008         case 49:
1009         {
1010             ITDebugLog(@"Keycode for menu item \"%@\": 49 (Space)", [item title]);
1011             // Haven't tested this, though it should work.
1012             // This doesn't work. :'(
1013             //unichar buffer;
1014             //[[NSString stringWithString:@"Space"] getCharacters:&buffer];
1015             //charcode = buffer;
1016             /*MenuRef menuRef = _NSGetCarbonMenu([item menu]);
1017             ITDebugLog(@"%@", menuRef);
1018             SetMenuItemCommandKey(menuRef, 0, NO, 49);
1019             SetMenuItemModifiers(menuRef, 0, kMenuNoCommandModifier);
1020             SetMenuItemKeyGlyph(menuRef, 0, kMenuBlankGlyph);
1021             charcode = 'b';*/
1022             unichar buffer;
1023             [[NSString stringWithString:@" "] getCharacters:&buffer]; // this will have to do for now :(
1024             charcode = buffer;
1025         }
1026         break;
1027         
1028         case 51:
1029             ITDebugLog(@"Keycode for menu item \"%@\": 51 (Delete)", [item title]);
1030             charcode = NSDeleteFunctionKey;
1031         break;
1032         
1033         case 53:
1034             ITDebugLog(@"Keycode for menu item \"%@\": 53 (Escape)", [item title]);
1035             charcode = '\e';
1036         break;
1037         
1038         case 71:
1039             ITDebugLog(@"Keycode for menu item \"%@\": 71 (Escape)", [item title]);
1040             charcode = '\e';
1041         break;
1042         
1043         case 76:
1044             ITDebugLog(@"Keycode for menu item \"%@\": 76 (Return)", [item title]);
1045             charcode = '\r';
1046         break;
1047         
1048         case 96:
1049             ITDebugLog(@"Keycode for menu item \"%@\": 96 (F5)", [item title]);
1050             charcode = NSF5FunctionKey;
1051         break;
1052         
1053         case 97:
1054             ITDebugLog(@"Keycode for menu item \"%@\": 97 (F6)", [item title]);
1055             charcode = NSF6FunctionKey;
1056         break;
1057         
1058         case 98:
1059             ITDebugLog(@"Keycode for menu item \"%@\": 98 (F7)", [item title]);
1060             charcode = NSF7FunctionKey;
1061         break;
1062         
1063         case 99:
1064             ITDebugLog(@"Keycode for menu item \"%@\": 99 (F3)", [item title]);
1065             charcode = NSF3FunctionKey;
1066         break;
1067         
1068         case 100:
1069             ITDebugLog(@"Keycode for menu item \"%@\": 100 (F8)", [item title]);
1070             charcode = NSF8FunctionKey;
1071         break;
1072         
1073         case 101:
1074             ITDebugLog(@"Keycode for menu item \"%@\": 101 (F9)", [item title]);
1075             charcode = NSF9FunctionKey;
1076         break;
1077         
1078         case 103:
1079             ITDebugLog(@"Keycode for menu item \"%@\": 103 (F11)", [item title]);
1080             charcode = NSF11FunctionKey;
1081         break;
1082         
1083         case 105:
1084             ITDebugLog(@"Keycode for menu item \"%@\": 105 (F13)", [item title]);
1085             charcode = NSF13FunctionKey;
1086         break;
1087         
1088         case 107:
1089             ITDebugLog(@"Keycode for menu item \"%@\": 107 (F14)", [item title]);
1090             charcode = NSF14FunctionKey;
1091         break;
1092         
1093         case 109:
1094             ITDebugLog(@"Keycode for menu item \"%@\": 109 (F10)", [item title]);
1095             charcode = NSF10FunctionKey;
1096         break;
1097         
1098         case 111:
1099             ITDebugLog(@"Keycode for menu item \"%@\": 111 (F12)", [item title]);
1100             charcode = NSF12FunctionKey;
1101         break;
1102         
1103         case 113:
1104             ITDebugLog(@"Keycode for menu item \"%@\": 113 (F13)", [item title]);
1105             charcode = NSF13FunctionKey;
1106         break;
1107         
1108         case 114:
1109             ITDebugLog(@"Keycode for menu item \"%@\": 114 (Insert)", [item title]);
1110             charcode = NSInsertFunctionKey;
1111         break;
1112         
1113         case 115:
1114             ITDebugLog(@"Keycode for menu item \"%@\": 115 (Home)", [item title]);
1115             charcode = NSHomeFunctionKey;
1116         break;
1117         
1118         case 116:
1119             ITDebugLog(@"Keycode for menu item \"%@\": 116 (PgUp)", [item title]);
1120             charcode = NSPageUpFunctionKey;
1121         break;
1122         
1123         case 117:
1124             ITDebugLog(@"Keycode for menu item \"%@\": 117 (Delete)", [item title]);
1125             charcode = NSDeleteFunctionKey;
1126         break;
1127         
1128         case 118:
1129             ITDebugLog(@"Keycode for menu item \"%@\": 118 (F4)", [item title]);
1130             charcode = NSF4FunctionKey;
1131         break;
1132         
1133         case 119:
1134             ITDebugLog(@"Keycode for menu item \"%@\": 119 (End)", [item title]);
1135             charcode = NSEndFunctionKey;
1136         break;
1137         
1138         case 120:
1139             ITDebugLog(@"Keycode for menu item \"%@\": 120 (F2)", [item title]);
1140             charcode = NSF2FunctionKey;
1141         break;
1142         
1143         case 121:
1144             ITDebugLog(@"Keycode for menu item \"%@\": 121 (PgDown)", [item title]);
1145             charcode = NSPageDownFunctionKey;
1146         break;
1147         
1148         case 122:
1149             ITDebugLog(@"Keycode for menu item \"%@\": 122 (F1)", [item title]);
1150             charcode = NSF1FunctionKey;
1151         break;
1152         
1153         case 123:
1154             ITDebugLog(@"Keycode for menu item \"%@\": 123 (Left Arrow)", [item title]);
1155             charcode = NSLeftArrowFunctionKey;
1156         break;
1157         
1158         case 124:
1159             ITDebugLog(@"Keycode for menu item \"%@\": 124 (Right Arrow)", [item title]);
1160             charcode = NSRightArrowFunctionKey;
1161         break;
1162         
1163         case 125:
1164             ITDebugLog(@"Keycode for menu item \"%@\": 125 (Down Arrow)", [item title]);
1165             charcode = NSDownArrowFunctionKey;
1166         break;
1167         
1168         case 126:
1169             ITDebugLog(@"Keycode for menu item \"%@\": 126 (Up Arrow)", [item title]);
1170             charcode = NSUpArrowFunctionKey;
1171         break;
1172     }
1173     
1174     if (charcode == 'a') {
1175         unsigned long state;
1176         long keyTrans;
1177         char charCode;
1178         Ptr kchr;
1179         state = 0;
1180         kchr = (Ptr) GetScriptVariable(smCurrentScript, smKCHRCache);
1181         keyTrans = KeyTranslate(kchr, code, &state);
1182         charCode = keyTrans;
1183         ITDebugLog(@"Keycode for menu item \"%@\": %i (%c)", [item title], code, charCode);
1184         [item setKeyEquivalent:[NSString stringWithCString:&charCode length:1]];
1185     } else if (charcode != 'b') {
1186         [item setKeyEquivalent:[NSString stringWithCharacters:&charcode length:1]];
1187     }
1188     ITDebugLog(@"Done setting key equivalent on menu item: %@", [item title]);
1189 }
1190
1191 - (BOOL)iPodWithNameAutomaticallyUpdates:(NSString *)name
1192 {
1193     NSArray *volumes = [[NSWorkspace sharedWorkspace] mountedLocalVolumePaths];
1194     NSEnumerator *volEnum = [volumes objectEnumerator];
1195     NSString *nextVolume;
1196     ITDebugLog(@"Looking for an iPod named %@", name);
1197     while ( (nextVolume = [volEnum nextObject]) ) {
1198         ITDebugLog(@"- %@", nextVolume);
1199         if ([nextVolume rangeOfString:name options:nil /*range:NSMakeRange(0, [name length] - 1)*/].location != NSNotFound) {
1200             NSFileHandle *handle;
1201             NSData *data;
1202             NSString *path = [nextVolume stringByAppendingPathComponent:@"/iPod_Control/iTunes/iTunesPrefs"];
1203             if ( ![[NSFileManager defaultManager] fileExistsAtPath:path] ) {
1204                 ITDebugLog(@"Error, path isn't an iPod! %@", path);
1205                 return NO;
1206             }
1207             handle = [NSFileHandle fileHandleForReadingAtPath:path];
1208             ITDebugLog(@"File handle: %@", handle);
1209             [handle seekToFileOffset:10];
1210             data = [handle readDataOfLength:1];
1211             ITDebugLog(@"Data: %@", data);
1212             if ( (*((unsigned char*)[data bytes]) == 0x00) ) {
1213                 ITDebugLog(@"iPod is manually updated. %@", path);
1214                 return NO;
1215             } else if ( ( *((unsigned char*)[data bytes]) == 0x01 ) ) {
1216                 ITDebugLog(@"iPod is automatically updated. %@", path);
1217                 return YES;
1218             } else {
1219                 ITDebugLog(@"Error! Value: %h  Desc: %@ Path: %@", *((unsigned char*)[data bytes]), [data description], path);
1220                 return NO;
1221             }
1222         }
1223     }
1224     return YES;
1225 }
1226
1227 @end