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