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