RAAAAAHHHHHHHHHHH NETWORK MENUTOOOONS!
authorKent Sutherland <ksuther@ithinksw.com>
Sat, 25 Oct 2003 01:35:45 +0000 (01:35 +0000)
committerKent Sutherland <ksuther@ithinksw.com>
Sat, 25 Oct 2003 01:35:45 +0000 (01:35 +0000)
12 files changed:
English.lproj/Preferences.nib/classes.nib
English.lproj/Preferences.nib/info.nib
English.lproj/Preferences.nib/keyedobjects.nib
MainController.h
MainController.m
MenuController.h
MenuController.m
NetworkController.h [new file with mode: 0755]
NetworkController.m [new file with mode: 0755]
PreferencesController.h
PreferencesController.m
libValidate.a

index 8bb69df..ee754cf 100755 (executable)
@@ -6,6 +6,7 @@
         {
             ACTIONS = {
                 changeGeneralSetting = id; 
+                changeSharingSetting = id; 
                 changeStatusWindowSetting = id; 
                 clearHotKey = id; 
                 editHotKey = id; 
                 appearanceEffectPopup = NSPopUpButton; 
                 appearanceSpeedSlider = NSSlider; 
                 artistCheckbox = NSButton; 
+                hostTextField = NSTextField; 
                 hotKeysTableView = NSTableView; 
                 launchAtLoginCheckbox = NSButton; 
                 launchPlayerAtLaunchCheckbox = NSButton; 
+                manualView = NSView; 
                 menuTableView = CustomMenuTableView; 
                 nameCheckbox = NSButton; 
                 ratingCheckbox = NSButton; 
+                selectPlayerBox = NSBox; 
+                selectPlayerSheet = NSPanel; 
+                selectSharedPlayerButton = NSButton; 
+                shareMenuTunesCheckbox = NSButton; 
+                sharePasswordCheckbox = NSButton; 
+                sharePasswordTextField = NSTextField; 
+                sharingTableView = NSTableView; 
                 showOnChangeCheckbox = NSButton; 
                 songsInAdvance = NSTextField; 
                 trackNumberCheckbox = NSButton; 
                 trackTimeCheckbox = NSButton; 
+                useSharedMenuTunesCheckbox = NSButton; 
                 vanishDelaySlider = NSSlider; 
                 vanishEffectPopup = NSPopUpButton; 
                 vanishSpeedSlider = NSSlider; 
                 window = NSWindow; 
+                zeroConfView = NSView; 
             }; 
             SUPERCLASS = NSObject; 
         }
index b826611..e4eec3e 100755 (executable)
@@ -4,12 +4,15 @@
 <dict>
        <key>IBDocumentLocation</key>
        <string>6 66 356 240 0 0 1152 746 </string>
+       <key>IBEditorPositions</key>
+       <dict>
+               <key>634</key>
+               <string>386 421 380 180 0 0 1152 746 </string>
+               <key>639</key>
+               <string>386 450 380 122 0 0 1152 746 </string>
+       </dict>
        <key>IBFramework Version</key>
-       <string>291.0</string>
-       <key>IBGroupedObjects</key>
-       <dict/>
-       <key>IBLastGroupID</key>
-       <string>1</string>
+       <string>349.0</string>
        <key>IBLockedObjects</key>
        <array>
                <integer>281</integer>
        <key>IBOpenObjects</key>
        <array>
                <integer>6</integer>
+               <integer>634</integer>
+               <integer>639</integer>
        </array>
        <key>IBSystem Version</key>
-       <string>6L60</string>
+       <string>7B85</string>
 </dict>
 </plist>
index 1f5ef1b..5e523bd 100755 (executable)
Binary files a/English.lproj/Preferences.nib/keyedobjects.nib and b/English.lproj/Preferences.nib/keyedobjects.nib differ
index c2c73ba..f4f9f7b 100755 (executable)
@@ -19,7 +19,7 @@
 #import <ITMTRemote/ITMTRemote.h>
 #import "MTBlingController.h"
 
-@class StatusWindowController, MenuController;
+@class StatusWindowController, MenuController, NetworkController;
 
 @interface MainController : NSObject
 {
@@ -36,6 +36,7 @@
 
     StatusWindowController *statusWindowController; //Shows status windows
     MenuController *menuController;
+    NetworkController *networkController;
     NSUserDefaults *df;
     
     MTBlingController *bling;
 
 //
 
+- (void)setServerStatus:(BOOL)newStatus;
+- (BOOL)connectToServer;
+- (BOOL)disconnectFromServer;
+- (void)networkError:(NSException *)exception;
+
+//
+
 - (ITMTRemote *)currentRemote;
 - (void)clearHotKeys;
 - (void)setupHotKeys;
index dd8c51d..bbb0cec 100755 (executable)
@@ -1,6 +1,7 @@
 #import "MainController.h"
 #import "MenuController.h"
 #import "PreferencesController.h"
+#import "NetworkController.h"
 #import <ITKit/ITHotKeyCenter.h>
 #import <ITKit/ITHotKey.h>
 #import <ITKit/ITKeyCombo.h>
@@ -54,7 +55,15 @@ static MainController *sharedController;
     }
     
     currentRemote = [self loadRemote];
-    [currentRemote begin];
+    [[self currentRemote] begin];
+    
+    //Turn on network stuff if needed
+    networkController = [[NetworkController alloc] init];
+    if ([df boolForKey:@"enableSharing"]) {
+        [self setServerStatus:YES];
+    } else if ([df boolForKey:@"useSharedPlayer"] && [df boolForKey:@"alwaysUseSharedPlayer"]) {
+        [self connectToServer];
+    }
     
     //Setup for notification of the remote player launching or quitting
     [[[NSWorkspace sharedWorkspace] notificationCenter]
@@ -86,18 +95,23 @@ static MainController *sharedController;
                              userInfo:nil
                              repeats:YES] retain];
     
-    if ([currentRemote playerRunningState] == ITMTRemotePlayerRunning) {
-        [self applicationLaunched:nil];
-    } else {
-        if ([df boolForKey:@"LaunchPlayerWithMT"])
-            [self showPlayer];
-        else
-            [self applicationTerminated:nil];
-    }
+    NS_DURING
+        if ([[self currentRemote] playerRunningState] == ITMTRemotePlayerRunning) {
+            [self applicationLaunched:nil];
+        } else {
+            if ([df boolForKey:@"LaunchPlayerWithMT"])
+                [self showPlayer];
+            else
+                [self applicationTerminated:nil];
+        }
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
     
     [statusItem setImage:[NSImage imageNamed:@"MenuNormal"]];
     [statusItem setAlternateImage:[NSImage imageNamed:@"MenuInverted"]];
 
+    [networkController startRemoteServerSearch];
     [NSApp deactivate];
 }
 
@@ -198,7 +212,7 @@ static MainController *sharedController;
             [self setupHotKeys];
             if (![refreshTimer isValid]) {
                 [refreshTimer release];
-                refreshTimer = refreshTimer = [[NSTimer scheduledTimerWithTimeInterval:0.5
+                refreshTimer = [[NSTimer scheduledTimerWithTimeInterval:0.5
                              target:self
                              selector:@selector(timerUpdate)
                              userInfo:nil
@@ -226,17 +240,35 @@ static MainController *sharedController;
 
 - (BOOL)songIsPlaying
 {
-    return ( ! ([[currentRemote playerStateUniqueIdentifier] isEqualToString:@"0-0"]) );
+    NSString *identifier;
+    NS_DURING
+        identifier = [[self currentRemote] playerStateUniqueIdentifier];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
+    return ( ! ([identifier isEqualToString:@"0-0"]) );
 }
 
 - (BOOL)radioIsPlaying
 {
-    return ( [currentRemote currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist );
+    ITMTRemotePlayerPlaylistClass class;
+    NS_DURING
+        class = [[self currentRemote] currentPlaylistClass];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
+    return (class  == ITMTRemotePlayerRadioPlaylist );
 }
 
 - (BOOL)songChanged
 {
-    return ( ! [[currentRemote playerStateUniqueIdentifier] isEqualToString:_latestSongIdentifier] );
+    NSString *identifier;
+    NS_DURING
+        identifier = [[self currentRemote] playerStateUniqueIdentifier];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
+    return ( ! [identifier isEqualToString:_latestSongIdentifier] );
 }
 
 - (NSString *)latestSongIdentifier
@@ -253,17 +285,26 @@ static MainController *sharedController;
 
 - (void)timerUpdate
 {
+    if ([networkController isConnectedToServer]) {
+        [statusItem setMenu:[menuController menu]];
+    }
+    
     if ( [self songChanged] && (timerUpdating != YES) ) {
         ITDebugLog(@"The song changed.");
         timerUpdating = YES;
-        latestPlaylistClass = [currentRemote currentPlaylistClass];
+        
+        NS_DURING
+        latestPlaylistClass = [[self currentRemote] currentPlaylistClass];
         [menuController rebuildSubmenus];
 
         if ( [df boolForKey:@"showSongInfoOnChange"] ) {
             [self performSelector:@selector(showCurrentTrackInfo) withObject:nil afterDelay:0.0];
         }
         
-        [self setLatestSongIdentifier:[currentRemote playerStateUniqueIdentifier]];
+        [self setLatestSongIdentifier:[[self currentRemote] playerStateUniqueIdentifier]];
+        NS_HANDLER
+            [self networkError:localException];
+        NS_ENDHANDLER
         
         timerUpdating = NO;
     }
@@ -272,11 +313,20 @@ static MainController *sharedController;
 - (void)menuClicked
 {
     ITDebugLog(@"Menu clicked.");
-    if ([currentRemote playerRunningState] == ITMTRemotePlayerRunning) {
-        [statusItem setMenu:[menuController menu]];
-    } else {
-        [statusItem setMenu:[menuController menuForNoPlayer]];
+    if ([networkController isConnectedToServer]) {
+        //Used the cached version
+        return;
     }
+    
+    NS_DURING
+        if ([[self currentRemote] playerRunningState] == ITMTRemotePlayerRunning) {
+            [statusItem setMenu:[menuController menu]];
+        } else {
+            [statusItem setMenu:[menuController menuForNoPlayer]];
+        }
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
 }
 
 //
@@ -287,72 +337,109 @@ static MainController *sharedController;
 
 - (void)playPause
 {
-    ITMTRemotePlayerPlayingState state = [currentRemote playerPlayingState];
-    ITDebugLog(@"Play/Pause toggled");
-    if (state == ITMTRemotePlayerPlaying) {
-        [currentRemote pause];
-    } else if ((state == ITMTRemotePlayerForwarding) || (state == ITMTRemotePlayerRewinding)) {
-        [currentRemote pause];
-        [currentRemote play];
-    } else {
-        [currentRemote play];
-    }
+    NS_DURING
+        ITMTRemotePlayerPlayingState state = [[self currentRemote] playerPlayingState];
+        ITDebugLog(@"Play/Pause toggled");
+        if (state == ITMTRemotePlayerPlaying) {
+            [[self currentRemote] pause];
+        } else if ((state == ITMTRemotePlayerForwarding) || (state == ITMTRemotePlayerRewinding)) {
+            [[self currentRemote] pause];
+            [[self currentRemote] play];
+        } else {
+            [[self currentRemote] play];
+        }
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
+    
     [self timerUpdate];
 }
 
 - (void)nextSong
 {
     ITDebugLog(@"Going to next song.");
-    [currentRemote goToNextSong];
+    NS_DURING
+        [[self currentRemote] goToNextSong];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
     [self timerUpdate];
 }
 
 - (void)prevSong
 {
     ITDebugLog(@"Going to previous song.");
-    [currentRemote goToPreviousSong];
+    NS_DURING
+        [[self currentRemote] goToPreviousSong];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
     [self timerUpdate];
 }
 
 - (void)fastForward
 {
     ITDebugLog(@"Fast forwarding.");
-    [currentRemote forward];
+    NS_DURING
+        [[self currentRemote] forward];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
     [self timerUpdate];
 }
 
 - (void)rewind
 {
     ITDebugLog(@"Rewinding.");
-    [currentRemote rewind];
+    NS_DURING
+        [[self currentRemote] rewind];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
     [self timerUpdate];
 }
 
 - (void)selectPlaylistAtIndex:(int)index
 {
     ITDebugLog(@"Selecting playlist %i", index);
-    [currentRemote switchToPlaylistAtIndex:index];
+    NS_DURING
+        [[self currentRemote] switchToPlaylistAtIndex:index];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
     [self timerUpdate];
 }
 
 - (void)selectSongAtIndex:(int)index
 {
     ITDebugLog(@"Selecting song %i", index);
-    [currentRemote switchToSongAtIndex:index];
+    NS_DURING
+        [[self currentRemote] switchToSongAtIndex:index];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
     [self timerUpdate];
 }
 
 - (void)selectSongRating:(int)rating
 {
     ITDebugLog(@"Selecting song rating %i", rating);
-    [currentRemote setCurrentSongRating:(float)rating / 100.0];
+    NS_DURING
+        [[self currentRemote] setCurrentSongRating:(float)rating / 100.0];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
     [self timerUpdate];
 }
 
 - (void)selectEQPresetAtIndex:(int)index
 {
     ITDebugLog(@"Selecting EQ preset %i", index);
-    [currentRemote switchToEQAtIndex:index];
+    NS_DURING
+        [[self currentRemote] switchToEQAtIndex:index];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
     [self timerUpdate];
 }
 
@@ -361,12 +448,20 @@ static MainController *sharedController;
     ITDebugLog(@"Beginning show player.");
     if ( ( playerRunningState == ITMTRemotePlayerRunning) ) {
         ITDebugLog(@"Showing player interface.");
-        [currentRemote showPrimaryInterface];
+        NS_DURING
+            [[self currentRemote] showPrimaryInterface];
+        NS_HANDLER
+            [self networkError:localException];
+        NS_ENDHANDLER
     } else {
         ITDebugLog(@"Launching player.");
-        if (![[NSWorkspace sharedWorkspace] launchApplication:[currentRemote playerFullName]]) {
-            ITDebugLog(@"Error Launching Player");
-        }
+        NS_DURING
+            if (![[NSWorkspace sharedWorkspace] launchApplication:[[self currentRemote] playerFullName]]) {
+                ITDebugLog(@"Error Launching Player");
+            }
+        NS_HANDLER
+            [self networkError:localException];
+        NS_ENDHANDLER
     }
     ITDebugLog(@"Finished show player.");
 }
@@ -550,36 +645,62 @@ static MainController *sharedController;
 
 - (void)showCurrentTrackInfo
 {
-    ITMTRemotePlayerSource  source      = [currentRemote currentSource];
-    NSString               *title       = [currentRemote currentSongTitle];
+    ITMTRemotePlayerSource  source;
+    NSString               *title;
     NSString               *album       = nil;
     NSString               *artist      = nil;
     NSString               *time        = nil;
     NSString               *track       = nil;
     int                     rating      = -1;
     
+    NS_DURING
+        source      = [[self currentRemote] currentSource];
+        title       = [[self currentRemote] currentSongTitle];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
+    
     ITDebugLog(@"Showing track info status window.");
     
     if ( title ) {
 
         if ( [df boolForKey:@"showAlbum"] ) {
-            album = [currentRemote currentSongAlbum];
+            NS_DURING
+                album = [[self currentRemote] currentSongAlbum];
+            NS_HANDLER
+                [self networkError:localException];
+            NS_ENDHANDLER
         }
 
         if ( [df boolForKey:@"showArtist"] ) {
-            artist = [currentRemote currentSongArtist];
+            NS_DURING
+                artist = [[self currentRemote] currentSongArtist];
+            NS_HANDLER
+                [self networkError:localException];
+            NS_ENDHANDLER
         }
 
         if ( [df boolForKey:@"showTime"] ) {
-            time = [NSString stringWithFormat:@"%@: %@ / %@",
+            NS_DURING
+                time = [NSString stringWithFormat:@"%@: %@ / %@",
                 @"Time",
-                [currentRemote currentSongElapsed],
-                [currentRemote currentSongLength]];
+                [[self currentRemote] currentSongElapsed],
+                [[self currentRemote] currentSongLength]];
+            NS_HANDLER
+                [self networkError:localException];
+            NS_ENDHANDLER
         }
 
         if ( [df boolForKey:@"showTrackNumber"] ) {
-            int trackNo    = [currentRemote currentSongTrack];
-            int trackCount = [currentRemote currentAlbumTrackCount];
+            int trackNo;
+            int trackCount;
+            
+            NS_DURING
+                trackNo    = [[self currentRemote] currentSongTrack];
+                trackCount = [[self currentRemote] currentAlbumTrackCount];
+            NS_HANDLER
+                [self networkError:localException];
+            NS_ENDHANDLER
             
             if ( (trackNo > 0) || (trackCount > 0) ) {
                 track = [NSString stringWithFormat:@"%@: %i %@ %i",
@@ -588,7 +709,14 @@ static MainController *sharedController;
         }
 
         if ( [df boolForKey:@"showTrackRating"] ) {
-            float currentRating = [currentRemote currentSongRating];
+            float currentRating;
+            
+            NS_DURING
+                currentRating = [[self currentRemote] currentSongRating];
+            NS_HANDLER
+                [self networkError:localException];
+            NS_ENDHANDLER
+            
             if (currentRating >= 0.0) {
                 rating = ( currentRating * 5 );
             }
@@ -609,140 +737,173 @@ static MainController *sharedController;
 
 - (void)showUpcomingSongs
 {
-    int curPlaylist = [currentRemote currentPlaylistIndex];
-    int numSongs = [currentRemote numberOfSongsInPlaylistAtIndex:curPlaylist];
+    int numSongs;
+    
+    NS_DURING
+        numSongs = [[self currentRemote] numberOfSongsInPlaylistAtIndex:[[self currentRemote] currentPlaylistIndex]];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
+    
     ITDebugLog(@"Showing upcoming songs status window.");
-    if (numSongs > 0) {
-        NSMutableArray *songList = [NSMutableArray arrayWithCapacity:5];
-        int numSongsInAdvance = [df integerForKey:@"SongsInAdvance"];
-        int curTrack = [currentRemote currentSongIndex];
-        int i;
-
-        for (i = curTrack + 1; i <= curTrack + numSongsInAdvance; i++) {
-            if (i <= numSongs) {
-                [songList addObject:[currentRemote songTitleAtIndex:i]];
+    NS_DURING
+        if (numSongs > 0) {
+            NSMutableArray *songList = [NSMutableArray arrayWithCapacity:5];
+            int numSongsInAdvance = [df integerForKey:@"SongsInAdvance"];
+            int curTrack = [[self currentRemote] currentSongIndex];
+            int i;
+    
+            for (i = curTrack + 1; i <= curTrack + numSongsInAdvance; i++) {
+                if (i <= numSongs) {
+                    [songList addObject:[[self currentRemote] songTitleAtIndex:i]];
+                }
             }
+            
+            [statusWindowController showUpcomingSongsWindowWithTitles:songList];
+        } else {
+            [statusWindowController showUpcomingSongsWindowWithTitles:[NSArray arrayWithObject:NSLocalizedString(@"noUpcomingSongs", @"No upcoming songs.")]];
         }
-        
-        [statusWindowController showUpcomingSongsWindowWithTitles:songList];
-        
-    } else {
-        [statusWindowController showUpcomingSongsWindowWithTitles:[NSArray arrayWithObject:NSLocalizedString(@"noUpcomingSongs", @"No upcoming songs.")]];
-    }
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
 }
 
 - (void)incrementVolume
 {
-    float volume  = [currentRemote volume];
-    float dispVol = volume;
-    ITDebugLog(@"Incrementing volume.");
-    volume  += 0.110;
-    dispVol += 0.100;
+    NS_DURING
+        float volume  = [[self currentRemote] volume];
+        float dispVol = volume;
+        ITDebugLog(@"Incrementing volume.");
+        volume  += 0.110;
+        dispVol += 0.100;
+        
+        if (volume > 1.0) {
+            volume  = 1.0;
+            dispVol = 1.0;
+        }
     
-    if (volume > 1.0) {
-        volume  = 1.0;
-        dispVol = 1.0;
-    }
-
-    ITDebugLog(@"Setting volume to %f", volume);
-    [currentRemote setVolume:volume];
-
-    // Show volume status window
-    [statusWindowController showVolumeWindowWithLevel:dispVol];
+        ITDebugLog(@"Setting volume to %f", volume);
+        [[self currentRemote] setVolume:volume];
+    
+        // Show volume status window
+        [statusWindowController showVolumeWindowWithLevel:dispVol];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
 }
 
 - (void)decrementVolume
 {
-    float volume  = [currentRemote volume];
-    float dispVol = volume;
-    ITDebugLog(@"Decrementing volume.");
-    volume  -= 0.090;
-    dispVol -= 0.100;
-
-    if (volume < 0.0) {
-        volume  = 0.0;
-        dispVol = 0.0;
-    }
+    NS_DURING
+        float volume  = [[self currentRemote] volume];
+        float dispVol = volume;
+        ITDebugLog(@"Decrementing volume.");
+        volume  -= 0.090;
+        dispVol -= 0.100;
     
-    ITDebugLog(@"Setting volume to %f", volume);
-    [currentRemote setVolume:volume];
-    
-    //Show volume status window
-    [statusWindowController showVolumeWindowWithLevel:dispVol];
+        if (volume < 0.0) {
+            volume  = 0.0;
+            dispVol = 0.0;
+        }
+        
+        ITDebugLog(@"Setting volume to %f", volume);
+        [[self currentRemote] setVolume:volume];
+        
+        //Show volume status window
+        [statusWindowController showVolumeWindowWithLevel:dispVol];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
 }
 
 - (void)incrementRating
 {
-    float rating = [currentRemote currentSongRating];
-    ITDebugLog(@"Incrementing rating.");
-    
-    if ([currentRemote currentPlaylistIndex] == 0) {
-        ITDebugLog(@"No song playing, rating change aborted.");
-        return;
-    }
-    
-    rating += 0.2;
-    if (rating > 1.0) {
-        rating = 1.0;
-    }
-    ITDebugLog(@"Setting rating to %f", rating);
-    [currentRemote setCurrentSongRating:rating];
-    
-    //Show rating status window
-    [statusWindowController showRatingWindowWithRating:rating];
+    NS_DURING
+        float rating = [[self currentRemote] currentSongRating];
+        ITDebugLog(@"Incrementing rating.");
+        
+        if ([[self currentRemote] currentPlaylistIndex] == 0) {
+            ITDebugLog(@"No song playing, rating change aborted.");
+            return;
+        }
+        
+        rating += 0.2;
+        if (rating > 1.0) {
+            rating = 1.0;
+        }
+        ITDebugLog(@"Setting rating to %f", rating);
+        [[self currentRemote] setCurrentSongRating:rating];
+        
+        //Show rating status window
+        [statusWindowController showRatingWindowWithRating:rating];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
 }
 
 - (void)decrementRating
 {
-    float rating = [currentRemote currentSongRating];
-    ITDebugLog(@"Decrementing rating.");
-    
-    if ([currentRemote currentPlaylistIndex] == 0) {
-        ITDebugLog(@"No song playing, rating change aborted.");
-        return;
-    }
-    
-    rating -= 0.2;
-    if (rating < 0.0) {
-        rating = 0.0;
-    }
-    ITDebugLog(@"Setting rating to %f", rating);
-    [currentRemote setCurrentSongRating:rating];
-    
-    //Show rating status window
-    [statusWindowController showRatingWindowWithRating:rating];
+    NS_DURING
+        float rating = [[self currentRemote] currentSongRating];
+        ITDebugLog(@"Decrementing rating.");
+        
+        if ([[self currentRemote] currentPlaylistIndex] == 0) {
+            ITDebugLog(@"No song playing, rating change aborted.");
+            return;
+        }
+        
+        rating -= 0.2;
+        if (rating < 0.0) {
+            rating = 0.0;
+        }
+        ITDebugLog(@"Setting rating to %f", rating);
+        [[self currentRemote] setCurrentSongRating:rating];
+        
+        //Show rating status window
+        [statusWindowController showRatingWindowWithRating:rating];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
 }
 
 - (void)toggleLoop
 {
-    ITMTRemotePlayerRepeatMode repeatMode = [currentRemote repeatMode];
-    ITDebugLog(@"Toggling repeat mode.");
-    switch (repeatMode) {
-        case ITMTRemotePlayerRepeatOff:
-            repeatMode = ITMTRemotePlayerRepeatAll;
-        break;
-        case ITMTRemotePlayerRepeatAll:
-            repeatMode = ITMTRemotePlayerRepeatOne;
-        break;
-        case ITMTRemotePlayerRepeatOne:
-            repeatMode = ITMTRemotePlayerRepeatOff;
-        break;
-    }
-    ITDebugLog(@"Setting repeat mode to %i", repeatMode);
-    [currentRemote setRepeatMode:repeatMode];
-    
-    //Show loop status window
-    [statusWindowController showRepeatWindowWithMode:repeatMode];
+    NS_DURING
+        ITMTRemotePlayerRepeatMode repeatMode = [[self currentRemote] repeatMode];
+        ITDebugLog(@"Toggling repeat mode.");
+        switch (repeatMode) {
+            case ITMTRemotePlayerRepeatOff:
+                repeatMode = ITMTRemotePlayerRepeatAll;
+            break;
+            case ITMTRemotePlayerRepeatAll:
+                repeatMode = ITMTRemotePlayerRepeatOne;
+            break;
+            case ITMTRemotePlayerRepeatOne:
+                repeatMode = ITMTRemotePlayerRepeatOff;
+            break;
+        }
+        ITDebugLog(@"Setting repeat mode to %i", repeatMode);
+        [[self currentRemote] setRepeatMode:repeatMode];
+        
+        //Show loop status window
+        [statusWindowController showRepeatWindowWithMode:repeatMode];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
 }
 
 - (void)toggleShuffle
 {
-    BOOL newShuffleEnabled = ( ! [currentRemote shuffleEnabled] );
-    ITDebugLog(@"Toggling shuffle mode.");
-    [currentRemote setShuffleEnabled:newShuffleEnabled];
-    //Show shuffle status window
-    ITDebugLog(@"Setting shuffle mode to %i", newShuffleEnabled);
-    [statusWindowController showShuffleWindow:newShuffleEnabled];
+    NS_DURING
+        BOOL newShuffleEnabled = ( ! [[self currentRemote] shuffleEnabled] );
+        ITDebugLog(@"Toggling shuffle mode.");
+        [[self currentRemote] setShuffleEnabled:newShuffleEnabled];
+        //Show shuffle status window
+        ITDebugLog(@"Setting shuffle mode to %i", newShuffleEnabled);
+        [statusWindowController showShuffleWindow:newShuffleEnabled];
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
 }
 
 - (void)registerNowOK
@@ -763,6 +924,53 @@ static MainController *sharedController;
     [NSApp terminate:self];
 }
 
+/*************************************************************************/
+#pragma mark -
+#pragma mark NETWORK HANDLERS
+/*************************************************************************/
+
+- (void)setServerStatus:(BOOL)newStatus
+{
+    if (newStatus) {
+        //Turn on
+        [networkController setServerStatus:YES];
+    } else {
+        //Tear down
+        [networkController setServerStatus:NO];
+    }
+}
+
+- (BOOL)connectToServer
+{
+    //Connect
+    if ([networkController connectToHost:[df stringForKey:@"sharedPlayerHost"]]) {
+        currentRemote = [networkController sharedRemote];
+        [refreshTimer invalidate];
+        return YES;
+    } else {
+        currentRemote = [remoteArray objectAtIndex:0];
+        return NO;
+    }
+}
+
+- (BOOL)disconnectFromServer
+{
+    //Disconnect
+    currentRemote = [remoteArray objectAtIndex:0];
+    [networkController disconnect];
+    [self timerUpdate];
+    return YES;
+}
+
+- (void)networkError:(NSException *)exception
+{
+    ITDebugLog(@"Remote exception thrown: %@: %@", [exception name], [exception reason]);
+    NSRunAlertPanel(@"Remote MenuTunes Disconnected", @"The MenuTunes server you were connected to stopped responding or quit. MenuTunes will revert back to the local player.", @"OK", nil, nil);
+    if ([networkController isConnectedToServer] && [self disconnectFromServer]) {
+    } else {
+        ITDebugLog(@"CRITICAL ERROR DISCONNECTING!");
+    }
+}
 
 /*************************************************************************/
 #pragma mark -
@@ -771,33 +979,41 @@ static MainController *sharedController;
 
 - (void)applicationLaunched:(NSNotification *)note
 {
-    if (!note || [[[note userInfo] objectForKey:@"NSApplicationName"] isEqualToString:[currentRemote playerFullName]]) {
-        ITDebugLog(@"Remote application launched.");
-        playerRunningState = ITMTRemotePlayerRunning;
-        [currentRemote begin];
-        [self setLatestSongIdentifier:@""];
-        [self timerUpdate];
-        refreshTimer = [[NSTimer scheduledTimerWithTimeInterval:0.5
-                             target:self
-                             selector:@selector(timerUpdate)
-                             userInfo:nil
-                             repeats:YES] retain];
-        //[NSThread detachNewThreadSelector:@selector(startTimerInNewThread) toTarget:self withObject:nil];
-        [self setupHotKeys];
-    }
+    NS_DURING
+        if (!note || [[[note userInfo] objectForKey:@"NSApplicationName"] isEqualToString:[[self currentRemote] playerFullName]]) {
+            ITDebugLog(@"Remote application launched.");
+            playerRunningState = ITMTRemotePlayerRunning;
+            [[self currentRemote] begin];
+            [self setLatestSongIdentifier:@""];
+            [self timerUpdate];
+            refreshTimer = [[NSTimer scheduledTimerWithTimeInterval:([networkController isConnectedToServer] ? 10.0 : 0.5)
+                                target:self
+                                selector:@selector(timerUpdate)
+                                userInfo:nil
+                                repeats:YES] retain];
+            //[NSThread detachNewThreadSelector:@selector(startTimerInNewThread) toTarget:self withObject:nil];
+            [self setupHotKeys];
+        }
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
 }
 
  - (void)applicationTerminated:(NSNotification *)note
  {
-     if (!note || [[[note userInfo] objectForKey:@"NSApplicationName"] isEqualToString:[currentRemote playerFullName]]) {
-        ITDebugLog(@"Remote application terminated.");
-        [currentRemote halt];
-        [refreshTimer invalidate];
-        [refreshTimer release];
-        refreshTimer = nil;
-        [self clearHotKeys];
-        playerRunningState = ITMTRemotePlayerNotRunning;
-     }
+    NS_DURING
+        if (!note || [[[note userInfo] objectForKey:@"NSApplicationName"] isEqualToString:[[self currentRemote] playerFullName]]) {
+            ITDebugLog(@"Remote application terminated.");
+            [[self currentRemote] halt];
+            [refreshTimer invalidate];
+            [refreshTimer release];
+            refreshTimer = nil;
+            [self clearHotKeys];
+            playerRunningState = ITMTRemotePlayerNotRunning;
+        }
+    NS_HANDLER
+        [self networkError:localException];
+    NS_ENDHANDLER
  }
 
 
@@ -809,6 +1025,7 @@ static MainController *sharedController;
 - (void)applicationWillTerminate:(NSNotification *)note
 {
     [self clearHotKeys];
+    [networkController stopRemoteServerSearch];
     [[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
 }
 
@@ -825,6 +1042,7 @@ static MainController *sharedController;
     [statusItem release];
     [statusWindowController release];
     [menuController release];
+    [networkController release];
     [super dealloc];
 }
 
index 55ae240..c9a393b 100755 (executable)
@@ -7,7 +7,6 @@
 //
 
 #import <Cocoa/Cocoa.h>
-#import "ITMTRemote.h"
 
 // Internal: To be used with NSMenuItems as their tag, for use with the NSMenuValidation stuff.
 // Also will be used in supplying the controller with the layout to use for the MenuItems, unless
@@ -45,7 +44,6 @@ typedef enum {
     NSMenu *_currentMenu;
     NSMenu *_ratingMenu, *_upcomingSongsMenu, *_eqMenu, *_playlistsMenu; //Submenus
     
-    ITMTRemote *currentRemote;
     int _currentPlaylist, _currentTrack;
     BOOL _playingRadio;
 }
index b0ee60f..4898c09 100755 (executable)
@@ -8,6 +8,7 @@
 
 #import "MenuController.h"
 #import "MainController.h"
+#import "ITMTRemote.h"
 #import <ITFoundation/ITDebug.h>
 #import <ITKit/ITHotKeyCenter.h>
 #import <ITKit/ITHotKey.h>
     NSEnumerator *itemEnum;
     ITHotKey *hotKey;
     NSArray *hotKeys = [[ITHotKeyCenter sharedCenter] allHotKeys];
+    int currentSongRating;
     
     //Get the information
-    _currentPlaylist = [currentRemote currentPlaylistIndex];
-    _playingRadio = ([currentRemote currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist);
+    NS_DURING
+        _currentPlaylist = [[[MainController sharedController] currentRemote] currentPlaylistIndex];
+        _playingRadio = ([[[MainController sharedController] currentRemote] currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist);
+        currentSongRating = ( [[[MainController sharedController] currentRemote] currentSongRating] != -1 );
+    NS_HANDLER
+        [[MainController sharedController] networkError:localException];
+    NS_ENDHANDLER
     
     ITDebugLog(@"Reset menu if required.");
     
             }
             
             ITDebugLog(@"Set \"Play\"/\"Pause\" menu item's title to correct state.");
-            switch ([currentRemote playerPlayingState]) {
-                case ITMTRemotePlayerPlaying:
-                    [tempItem setTitle:NSLocalizedString(@"pause", @"Pause")];
-                break;
-                case ITMTRemotePlayerRewinding:
-                case ITMTRemotePlayerForwarding:
-                    [tempItem setTitle:NSLocalizedString(@"resume", @"Resume")];
-                break;
-                default:
-                break;
-            }
+            NS_DURING
+                switch ([[[MainController sharedController] currentRemote] playerPlayingState]) {
+                    case ITMTRemotePlayerPlaying:
+                        [tempItem setTitle:NSLocalizedString(@"pause", @"Pause")];
+                    break;
+                    case ITMTRemotePlayerRewinding:
+                    case ITMTRemotePlayerForwarding:
+                        [tempItem setTitle:NSLocalizedString(@"resume", @"Resume")];
+                    break;
+                    default:
+                    break;
+                }
+            NS_HANDLER
+                [[MainController sharedController] networkError:localException];
+            NS_ENDHANDLER
         } else if ([nextObject isEqualToString:@"nextTrack"]) {
             ITDebugLog(@"Add \"Next Track\" menu item.");
             tempItem = [menu addItemWithTitle:NSLocalizedString(@"nextTrack", @"Next Track")
             }
         } else if ([nextObject isEqualToString:@"showPlayer"]) {
             ITDebugLog(@"Add \"Show Player\" menu item.");
-            tempItem = [menu addItemWithTitle:[NSString stringWithFormat:@"%@ %@",
-                            NSLocalizedString(@"show", @"Show"),
-                            [[[MainController sharedController] currentRemote] playerSimpleName]]
-                    action:@selector(performMainMenuAction:)
-                    keyEquivalent:@""];
+            NS_DURING
+                tempItem = [menu addItemWithTitle:[NSString stringWithFormat:@"%@ %@",
+                                NSLocalizedString(@"show", @"Show"),
+                                    [[[MainController sharedController] currentRemote] playerSimpleName]]
+                                action:@selector(performMainMenuAction:)
+                                keyEquivalent:@""];
+            NS_HANDLER
+                [[MainController sharedController] networkError:localException];
+            NS_ENDHANDLER
             
             itemEnum = [hotKeys objectEnumerator];
             while ( (hotKey = [itemEnum nextObject]) ) {
             ITDebugLog(@"Check to see if a Track is playing...");
             //Handle playing radio too
             if (_currentPlaylist) {
-                NSString *title = [currentRemote currentSongTitle];
+                NSString *title;
+                NS_DURING
+                    title = [[[MainController sharedController] currentRemote] currentSongTitle];
+                NS_HANDLER
+                    [[MainController sharedController] networkError:localException];
+                NS_ENDHANDLER
                 ITDebugLog(@"A Track is Playing, Add \"Track Info\" menu items.");
                 ITDebugLog(@"Add \"Now Playing\" menu item.");
                 [menu addItemWithTitle:NSLocalizedString(@"nowPlaying", @"Now Playing") action:NULL keyEquivalent:@""];
                 
                 if (!_playingRadio) {
                     if ([defaults boolForKey:@"showAlbum"]) {
-                        NSString *curAlbum = [currentRemote currentSongAlbum];
+                        NSString *curAlbum;
+                        NS_DURING
+                            curAlbum = [[[MainController sharedController] currentRemote] currentSongAlbum];
+                        NS_HANDLER
+                            [[MainController sharedController] networkError:localException];
+                        NS_ENDHANDLER
                         ITDebugLog(@"Add Track Album (\"%@\") menu item.", curAlbum);
                         if ( curAlbum ) {
                             [menu indentItem:
                     }
                     
                     if ([defaults boolForKey:@"showArtist"]) {
-                        NSString *curArtist = [currentRemote currentSongArtist];
+                        NSString *curArtist;
+                        NS_DURING
+                            curArtist = [[[MainController sharedController] currentRemote] currentSongArtist];
+                        NS_HANDLER
+                            [[MainController sharedController] networkError:localException];
+                        NS_ENDHANDLER
                         ITDebugLog(@"Add Track Artist (\"%@\") menu item.", curArtist);
                         if ( curArtist ) {
                             [menu indentItem:
                     }
                     
                     if ([defaults boolForKey:@"showTrackNumber"]) {
-                        int track = [currentRemote currentSongTrack];
+                        int track;
+                        NS_DURING
+                            track = [[[MainController sharedController] currentRemote] currentSongTrack];
+                        NS_HANDLER
+                            [[MainController sharedController] networkError:localException];
+                        NS_ENDHANDLER
                         ITDebugLog(@"Add Track Number (\"Track %i\") menu item.", track);
                         if ( track > 0 ) {
                             [menu indentItem:
                     }
                 }
                 
-                if ([defaults boolForKey:@"showTime"] && ( ([currentRemote currentSongElapsed] != nil) || ([currentRemote currentSongLength] != nil) )) {
-                    ITDebugLog(@"Add Track Elapsed (\"%@/%@\") menu item.", [currentRemote currentSongElapsed], [currentRemote currentSongLength]);
-                    [menu indentItem:[menu addItemWithTitle:[NSString stringWithFormat:@"%@/%@", [currentRemote currentSongElapsed], [currentRemote currentSongLength]] action:nil keyEquivalent:@""]];
-                }
+                NS_DURING
+                    if ([defaults boolForKey:@"showTime"] && ( ([[[MainController sharedController] currentRemote] currentSongElapsed] != nil) || ([[[MainController sharedController] currentRemote] currentSongLength] != nil) )) {
+                        ITDebugLog(@"Add Track Elapsed (\"%@/%@\") menu item.", [[[MainController sharedController] currentRemote] currentSongElapsed], [[[MainController sharedController] currentRemote] currentSongLength]);
+                        [menu indentItem:[menu addItemWithTitle:[NSString stringWithFormat:@"%@/%@", [[[MainController sharedController] currentRemote] currentSongElapsed], [[[MainController sharedController] currentRemote] currentSongLength]] action:nil keyEquivalent:@""]];
+                    }
+                NS_HANDLER
+                    [[MainController sharedController] networkError:localException];
+                NS_ENDHANDLER
                 
                 if (!_playingRadio) {
-                    if ([defaults boolForKey:@"showTrackRating"] && ( [currentRemote currentSongRating] != -1.0 )) {
-                        NSString *string = nil;
-                        switch ((int)([currentRemote currentSongRating] * 5)) {
-                            case 0:
-                                string = [NSString stringWithUTF8String:"☆☆☆☆☆"];
-                            break;
-                            case 1:
-                                string = [NSString stringWithUTF8String:"★☆☆☆☆"];
-                            break;
-                            case 2:
-                                string = [NSString stringWithUTF8String:"★★☆☆☆"];
-                            break;
-                            case 3:
-                                string = [NSString stringWithUTF8String:"★★★☆☆"];
-                            break;
-                            case 4:
-                                string = [NSString stringWithUTF8String:"★★★★☆"];
-                            break;
-                            case 5:
-                                string = [NSString stringWithUTF8String:"★★★★★"];
-                            break;
+                    NS_DURING
+                        if ([defaults boolForKey:@"showTrackRating"] && ( [[[MainController sharedController] currentRemote] currentSongRating] != -1.0 )) {
+                            NSString *string = nil;
+                            switch ((int)([[[MainController sharedController] currentRemote] currentSongRating] * 5)) {
+                                case 0:
+                                    string = [NSString stringWithUTF8String:"☆☆☆☆☆"];
+                                break;
+                                case 1:
+                                    string = [NSString stringWithUTF8String:"★☆☆☆☆"];
+                                break;
+                                case 2:
+                                    string = [NSString stringWithUTF8String:"★★☆☆☆"];
+                                break;
+                                case 3:
+                                    string = [NSString stringWithUTF8String:"★★★☆☆"];
+                                break;
+                                case 4:
+                                    string = [NSString stringWithUTF8String:"★★★★☆"];
+                                break;
+                                case 5:
+                                    string = [NSString stringWithUTF8String:"★★★★★"];
+                                break;
+                            }
+                            ITDebugLog(@"Add Track Rating (\"%@\") menu item.", string);
+                            [menu indentItem:[menu addItemWithTitle:string action:nil keyEquivalent:@""]];
                         }
-                        ITDebugLog(@"Add Track Rating (\"%@\") menu item.", string);
-                        [menu indentItem:[menu addItemWithTitle:string action:nil keyEquivalent:@""]];
-                    }
+                    NS_HANDLER
+                        [[MainController sharedController] networkError:localException];
+                    NS_ENDHANDLER
                 }
             } else {
                 ITDebugLog(@"No Track is Playing, Add \"No Song\" menu item.");
             while ( (tempItem = [itemEnum nextObject]) ) {
                 [tempItem setState:NSOffState];
             }
-            [[_eqMenu itemAtIndex:([currentRemote currentEQPresetIndex] - 1)] setState:NSOnState];
-        } else if ([nextObject isEqualToString:@"songRating"] && ( [currentRemote currentSongRating] != -1 )) {
+            NS_DURING
+                [[_eqMenu itemAtIndex:([[[MainController sharedController] currentRemote] currentEQPresetIndex] - 1)] setState:NSOnState];
+            NS_HANDLER
+                [[MainController sharedController] networkError:localException];
+            NS_ENDHANDLER
+        } else if ([nextObject isEqualToString:@"songRating"] && currentSongRating) {
                 ITDebugLog(@"Add \"Song Rating\" submenu.");
                 tempItem = [menu addItemWithTitle:NSLocalizedString(@"songRating", @"Song Rating")
                         action:nil
                     [tempItem setState:NSOffState];
                 }
                 
-                [[_ratingMenu itemAtIndex:([currentRemote currentSongRating] * 5)] setState:NSOnState];
+                NS_DURING
+                    [[_ratingMenu itemAtIndex:([[[MainController sharedController] currentRemote] currentSongRating] * 5)] setState:NSOnState];
+                NS_HANDLER
+                    [[MainController sharedController] networkError:localException];
+                NS_ENDHANDLER
             } else if ([nextObject isEqualToString:@"upcomingSongs"]) {
                 ITDebugLog(@"Add \"Upcoming Songs\" submenu.");
                 tempItem = [menu addItemWithTitle:NSLocalizedString(@"upcomingSongs", @"Upcoming Songs")
     NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
     NSMenuItem *tempItem;
     ITDebugLog(@"Creating menu for when player isn't running.");
-    ITDebugLog(@"Add \"Open %@\" menu item.", [[[MainController sharedController] currentRemote] playerSimpleName]);
-    tempItem = [menu addItemWithTitle:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"open", @"Open"), [[[MainController sharedController] currentRemote] playerSimpleName]] action:@selector(performMainMenuAction:) keyEquivalent:@""];
+    NS_DURING
+        ITDebugLog(@"Add \"Open %@\" menu item.", [[[MainController sharedController] currentRemote] playerSimpleName]);
+        tempItem = [menu addItemWithTitle:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"open", @"Open"), [[[MainController sharedController] currentRemote] playerSimpleName]] action:@selector(performMainMenuAction:) keyEquivalent:@""];
+    NS_HANDLER
+        [[MainController sharedController] networkError:localException];
+    NS_ENDHANDLER
     [tempItem setTag:MTMenuShowPlayerItem];
     [tempItem setTarget:self];
     ITDebugLog(@"Add a separator menu item.");
 {
     ITDebugLog(@"Rebuilding all of the submenus.");
     
-    currentRemote = [[MainController sharedController] currentRemote];
-    _currentPlaylist = [currentRemote currentPlaylistIndex];
-    _currentTrack = [currentRemote currentSongIndex];
-    _playingRadio = ([currentRemote currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist);
+    NS_DURING
+        _currentPlaylist = [[[MainController sharedController] currentRemote] currentPlaylistIndex];
+        _currentTrack = [[[MainController sharedController] currentRemote] currentSongIndex];
+        _playingRadio = ([[[MainController sharedController] currentRemote] currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist);
+    NS_HANDLER
+        [[MainController sharedController] networkError:localException];
+    NS_ENDHANDLER
     
     [_ratingMenu release];
     [_upcomingSongsMenu release];
 - (NSMenu *)upcomingSongsMenu
 {
     NSMenu *upcomingSongsMenu = [[NSMenu alloc] initWithTitle:@""];
-    int numSongs = [currentRemote numberOfSongsInPlaylistAtIndex:_currentPlaylist];
-    int numSongsInAdvance = [[NSUserDefaults standardUserDefaults] integerForKey:@"SongsInAdvance"];
+    int numSongs, numSongsInAdvance = [[NSUserDefaults standardUserDefaults] integerForKey:@"SongsInAdvance"];
+    
+    NS_DURING
+        numSongs = [[[MainController sharedController] currentRemote] numberOfSongsInPlaylistAtIndex:_currentPlaylist];
+    NS_HANDLER
+        [[MainController sharedController] networkError:localException];
+    NS_ENDHANDLER
     
     ITDebugLog(@"Building \"Upcoming Songs\" menu.");
     
 
             for (i = _currentTrack + 1; i <= _currentTrack + numSongsInAdvance; i++) {
                 if (i <= numSongs) {
-                    NSString *curSong = [currentRemote songTitleAtIndex:i];
+                    NSString *curSong;
+                    NS_DURING
+                        curSong = [[[MainController sharedController] currentRemote] songTitleAtIndex:i];
+                    NS_HANDLER
+                        [[MainController sharedController] networkError:localException];
+                    NS_ENDHANDLER
                     NSMenuItem *songItem;
                     ITDebugLog(@"Adding song: %@", curSong);
                     songItem = [upcomingSongsMenu addItemWithTitle:curSong action:@selector(performUpcomingSongsMenuAction:) keyEquivalent:@""];
 - (NSMenu *)playlistsMenu
 {
     NSMenu *playlistsMenu = [[NSMenu alloc] initWithTitle:@""];
-    NSArray *playlists = [currentRemote playlists];
+    NSArray *playlists;
     NSMenuItem *tempItem;
     int i;
     
+    NS_DURING
+        playlists = [[[MainController sharedController] currentRemote] playlists];
+    NS_HANDLER
+        [[MainController sharedController] networkError:localException];
+    NS_ENDHANDLER
+    
     ITDebugLog(@"Building \"Playlists\" menu.");
     
     for (i = 0; i < [playlists count]; i++) {
 - (NSMenu *)eqMenu
 {
     NSMenu *eqMenu = [[NSMenu alloc] initWithTitle:@""];
-    NSArray *eqPresets = [currentRemote eqPresets];
+    NSArray *eqPresets;
     NSMenuItem *tempItem;
     int i;
     
+    NS_DURING
+        eqPresets = [[[MainController sharedController] currentRemote] eqPresets];
+    NS_HANDLER
+        [[MainController sharedController] networkError:localException];
+    NS_ENDHANDLER
+    
     ITDebugLog(@"Building \"EQ Presets\" menu.");
     
     for (i = 0; i < [eqPresets count]; i++) {
diff --git a/NetworkController.h b/NetworkController.h
new file mode 100755 (executable)
index 0000000..de3801b
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *     MenuTunes
+ *  NetworkController
+ *    Rendezvous network controller
+ *
+ *  Original Author : Kent Sutherland <ksuther@ithinksw.com>
+ *   Responsibility : Kent Sutherland <ksuther@ithinksw.com>
+ *
+ *  Copyright (c) 2003 iThink Software.
+ *  All Rights Reserved
+ *
+ */
+#import <Foundation/Foundation.h>
+
+#define SERVER_PORT 5712
+
+@class ITMTRemote;
+
+@interface NetworkController : NSObject
+{
+    NSNetService *service;
+    NSNetServiceBrowser *browser;
+    NSMutableArray *remoteServices;
+    
+    NSConnection *serverConnection, *clientConnection;
+    NSSocketPort *serverPort, *clientPort;
+    BOOL serverOn, clientConnected, connectedToServer;
+    ITMTRemote *clientProxy;
+}
++ (NetworkController *)sharedController;
+
+- (void)startRemoteServerSearch;
+- (void)stopRemoteServerSearch;
+
+- (void)setServerStatus:(BOOL)status;
+- (BOOL)connectToHost:(NSString *)host;
+- (BOOL)disconnect;
+- (BOOL)isServerOn;
+- (BOOL)isClientConnected;
+- (BOOL)isConnectedToServer;
+
+- (ITMTRemote *)sharedRemote;
+- (NSArray *)remoteServices;
+@end
diff --git a/NetworkController.m b/NetworkController.m
new file mode 100755 (executable)
index 0000000..3ac6250
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ *     MenuTunes
+ *  NetworkController
+ *    Rendezvous network controller
+ *
+ *  Original Author : Kent Sutherland <ksuther@ithinksw.com>
+ *   Responsibility : Kent Sutherland <ksuther@ithinksw.com>
+ *
+ *  Copyright (c) 2003 iThink Software.
+ *  All Rights Reserved
+ *
+ */
+
+#import "NetworkController.h"
+#import "MainController.h"
+#import "netinet/in.h"
+#import "arpa/inet.h"
+#import <ITFoundation/ITDebug.h>
+#import <ITFoundation/ITFoundation.h>
+#import <ITMTRemote/ITMTRemote.h>
+
+static NetworkController *sharedController;
+
+@implementation NetworkController
+
++ (NetworkController *)sharedController
+{
+    return sharedController;
+}
+
+- (id)init
+{
+    if ( (self = [super init]) ) {
+        sharedController = self;
+        browser = [[NSNetServiceBrowser alloc] init];
+        [browser setDelegate:self];
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [self disconnect];
+    if (serverOn) {
+        [serverConnection invalidate];
+        [serverConnection release];
+    }
+    [clientProxy release];
+    [remoteServices release];
+    [browser release];
+    [service stop];
+    [service release];
+    [super dealloc];
+}
+
+- (void)startRemoteServerSearch
+{
+    [browser searchForServicesOfType:@"_mttp._tcp." inDomain:@""];
+    [remoteServices release];
+    remoteServices = [[NSMutableArray alloc] init];
+}
+
+- (void)stopRemoteServerSearch
+{
+    [browser stop];
+}
+
+- (void)setServerStatus:(BOOL)status
+{
+    if (!serverOn && status) {
+        NSString *name = [[NSUserDefaults standardUserDefaults] stringForKey:@"sharedPlayerName"];
+        //Turn on
+        NS_DURING
+            serverPort = [[NSSocketPort alloc] initWithTCPPort:SERVER_PORT];
+            serverConnection = [[NSConnection alloc] initWithReceivePort:serverPort
+                                                     sendPort:serverPort];
+            [serverConnection setRootObject:[[MainController sharedController] currentRemote]];
+            [serverConnection registerName:@"ITMTPlayerHost"];
+            [serverConnection setDelegate:self];
+        NS_HANDLER
+            ITDebugLog(@"Error starting server!");
+        NS_ENDHANDLER
+        ITDebugLog(@"Started server.");
+        if (!name) {
+            name = @"MenuTunes Shared Player";
+        }
+        service = [[NSNetService alloc] initWithDomain:@""
+                                        type:@"_mttp._tcp."
+                                        name:name
+                                        port:SERVER_PORT];
+        [service publish];
+        serverOn = YES;
+    } else if (serverOn && !status && [serverConnection isValid]) {
+        //Turn off
+        [service stop];
+        [serverConnection registerName:nil];
+        [serverPort invalidate];
+        [serverConnection invalidate];
+        [serverConnection release];
+        ITDebugLog(@"Stopped server.");
+        serverOn = NO;
+    }
+}
+
+- (BOOL)connectToHost:(NSString *)host
+{
+    ITDebugLog(@"Connecting to host: %@", host);
+    NS_DURING
+        clientPort = [[NSSocketPort alloc] initRemoteWithTCPPort:SERVER_PORT
+                                           host:host];
+        clientConnection = [[NSConnection connectionWithReceivePort:nil sendPort:clientPort] retain];
+        clientProxy = [[clientConnection rootProxy] retain];
+    NS_HANDLER
+        ITDebugLog(@"Connection to host failed: %@", host);
+        return NO;
+    NS_ENDHANDLER
+    [clientConnection setReplyTimeout:5];
+    ITDebugLog(@"Connected to host: %@", host);
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(disconnect) name:NSConnectionDidDieNotification object:clientConnection];
+    connectedToServer = YES;
+    return YES;
+}
+
+- (BOOL)disconnect
+{
+    ITDebugLog(@"Disconnecting from host.");
+    connectedToServer = NO;
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+    [clientProxy release];
+    [clientConnection invalidate];
+    [clientConnection release];
+    return YES;
+}
+
+- (BOOL)isServerOn
+{
+    return serverOn;
+}
+
+- (BOOL)isClientConnected
+{
+    return clientConnected;
+}
+
+- (BOOL)isConnectedToServer
+{
+    return connectedToServer;
+}
+
+- (ITMTRemote *)sharedRemote
+{
+    return (ITMTRemote *)clientProxy;
+}
+
+- (NSArray *)remoteServices
+{
+    return remoteServices;
+}
+
+- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing
+{
+    [aNetService setDelegate:self];
+    [aNetService resolve];
+    ITDebugLog(@"Found service named %@.", [aNetService name]);
+    if (!moreComing) {
+        [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTFoundNetService" object:nil];
+    }
+}
+
+- (void)netServiceDidResolveAddress:(NSNetService *)sender
+{
+    [remoteServices addObject:[NSDictionary dictionaryWithObjectsAndKeys:[sender name], @"name",
+                                                                         [NSString stringWithCString:inet_ntoa((*(struct sockaddr_in*)[[[sender addresses] objectAtIndex:0] bytes]).sin_addr)], @"ip",
+                                                                         nil, nil]];
+    ITDebugLog(@"Resolved service named %@.", [sender name]);
+    NSLog(@"found!");
+    [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTFoundNetService" object:nil];
+}
+
+- (void)netServiceWillResolve:(NSNetService *)sender
+{
+    ITDebugLog(@"Resolving service named %@.", [sender name]);
+}
+
+- (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict
+{
+    ITDebugLog(@"Error resolving service %@.", errorDict);
+}
+
+@end
index 109d9e7..b49b1d7 100755 (executable)
     IBOutlet NSPopUpButton *appearanceEffectPopup;
     IBOutlet NSSlider *appearanceSpeedSlider;
     IBOutlet NSButton *artistCheckbox;
+    IBOutlet NSTextField *hostTextField;
     IBOutlet NSTableView *hotKeysTableView;
     IBOutlet NSButton *launchAtLoginCheckbox;
     IBOutlet NSButton *launchPlayerAtLaunchCheckbox;
+    IBOutlet NSView *manualView;
     IBOutlet CustomMenuTableView *menuTableView;
     IBOutlet NSButton *nameCheckbox;
     IBOutlet NSButton *ratingCheckbox;
+    IBOutlet NSBox *selectPlayerBox;
+    IBOutlet NSPanel *selectPlayerSheet;
+    IBOutlet NSButton *selectSharedPlayerButton;
+    IBOutlet NSButton *shareMenuTunesCheckbox;
+    IBOutlet NSButton *sharePasswordCheckbox;
+    IBOutlet NSTextField *sharePasswordTextField;
+    IBOutlet NSTableView *sharingTableView;
     IBOutlet NSButton *showOnChangeCheckbox;
     IBOutlet NSTextField *songsInAdvance;
     IBOutlet NSButton *trackNumberCheckbox;
     IBOutlet NSButton *trackTimeCheckbox;
+    IBOutlet NSButton *useSharedMenuTunesCheckbox;
     IBOutlet NSSlider *vanishDelaySlider;
     IBOutlet NSPopUpButton *vanishEffectPopup;
     IBOutlet NSSlider *vanishSpeedSlider;
     IBOutlet NSWindow *window;
+    IBOutlet NSView *zeroConfView;
 
     MainController *controller;
     NSUserDefaults *df;
@@ -54,6 +65,7 @@
 - (void)setController:(id)object;
 
 - (IBAction)changeGeneralSetting:(id)sender;
+- (IBAction)changeSharingSetting:(id)sender;
 - (IBAction)changeStatusWindowSetting:(id)sender;
 - (IBAction)clearHotKey:(id)sender;
 - (IBAction)editHotKey:(id)sender;
index b66520b..01820ab 100755 (executable)
@@ -1,5 +1,6 @@
 #import "PreferencesController.h"
 #import "MainController.h"
+#import "NetworkController.h"
 #import "StatusWindow.h"
 #import "StatusWindowController.h"
 #import "CustomMenuTableView.h"
@@ -133,7 +134,11 @@ static PreferencesController *prefs = nil;
         [hotKeysTableView setDoubleAction:@selector(hotKeysTableViewDoubleClicked:)];
         
         //Change the launch player checkbox to the proper name
-        [launchPlayerAtLaunchCheckbox setTitle:[NSString stringWithFormat:@"Launch %@ when MenuTunes launches", [[controller currentRemote] playerSimpleName]]]; //This isn't localized...
+        NS_DURING
+            [launchPlayerAtLaunchCheckbox setTitle:[NSString stringWithFormat:@"Launch %@ when MenuTunes launches", [[controller currentRemote] playerSimpleName]]]; //This isn't localized...
+        NS_HANDLER
+            [controller networkError:localException];
+        NS_ENDHANDLER
     }
 
     [window center];
@@ -168,6 +173,84 @@ static PreferencesController *prefs = nil;
     [df synchronize];
 }
 
+- (IBAction)changeSharingSetting:(id)sender
+{
+    ITDebugLog(@"Changing sharing setting of tag %i.", [sender tag]);
+    if ( [sender tag] == 5010 ) {
+        BOOL state = SENDER_STATE;
+        [df setBool:state forKey:@"enableSharing"];
+        //Disable/enable the use of shared player options
+        [useSharedMenuTunesCheckbox setEnabled:!state];
+        [sharePasswordCheckbox setEnabled:!state];
+        [sharePasswordTextField setEnabled:!state];
+        [controller setServerStatus:state]; //Set server status
+    } else if ( [sender tag] == 5020 ) {
+        [df setBool:SENDER_STATE forKey:@"enableSharingPassword"];
+    } else if ( [sender tag] == 5030 ) {
+        [df setObject:[sender stringValue] forKey:@"sharingPassword"];
+    } else if ( [sender tag] == 5040 ) {
+        BOOL state = SENDER_STATE;
+        [df setBool:state forKey:@"useSharedPlayer"];
+        //Disable/enable the use of sharing options
+        [shareMenuTunesCheckbox setEnabled:!state];
+        [sharePasswordCheckbox setEnabled:!state];
+        [sharePasswordTextField setEnabled:!state];
+        
+        if (state) {
+            [controller connectToServer];
+        } else {
+            [controller disconnectFromServer];
+        }
+    } else if ( [sender tag] == 5050 ) {
+        if ([sender clickedRow] > -1) {
+            //Set sharedPlayerHost
+            [df setObject:[[[[NetworkController sharedController] remoteServices] objectAtIndex:[sender clickedRow]] objectForKey:@"ip"] forKey:@"sharedPlayerHost"];
+        }
+    } else if ( [sender tag] == 5060 ) {
+        //Show selection sheet
+        [NSApp beginSheet:selectPlayerSheet modalForWindow:window modalDelegate:self didEndSelector:NULL contextInfo:nil];
+    } else if ( [sender tag] == 5100 ) {
+        //Change view
+        if ( ([sender indexOfItem:[sender selectedItem]] == 0) && ([selectPlayerBox contentView] != zeroConfView) ) {
+            NSRect frame = [selectPlayerSheet frame];
+            frame.origin.y -= 58;
+            frame.size.height = 273;
+            [selectPlayerSheet setFrame:frame display:YES animate:YES];
+            [selectPlayerBox setContentView:zeroConfView];
+        } else if ([selectPlayerBox contentView] != manualView) {
+            NSRect frame = [selectPlayerSheet frame];
+            frame.origin.y += 58;
+            frame.size.height = 215;
+            [selectPlayerSheet setFrame:frame display:YES animate:YES];
+            [selectPlayerBox setContentView:manualView];
+        }
+    } else if ( [sender tag] == 5110 ) {
+        //Cancel
+        [NSApp endSheet:selectPlayerSheet];
+        [selectPlayerSheet orderOut:nil];
+        if ([selectPlayerBox contentView] == manualView) {
+            [hostTextField setStringValue:[df stringForKey:@"sharedPlayerHost"]];
+        } else {
+        }
+    } else if ( [sender tag] == 5120 ) {
+        //OK, try to connect
+        [NSApp endSheet:selectPlayerSheet];
+        [selectPlayerSheet orderOut:nil];
+        
+        if (![controller connectToServer]) {
+            NSRunAlertPanel(@"Connection error.", @"The MenuTunes server you attempted to connect to was not responding. MenuTunes will revert back to the local player.", @"OK", nil, nil);
+        } else {
+            [useSharedMenuTunesCheckbox setState:NSOnState];
+        }
+        
+        if ([selectPlayerBox contentView] == manualView) {
+            [df setObject:[hostTextField stringValue] forKey:@"sharedPlayerHost"];
+        } else {
+        }
+    }
+    [df synchronize];
+}
+
 - (IBAction)changeStatusWindowSetting:(id)sender
 {
     StatusWindow *sw = [StatusWindow sharedWindow];
@@ -520,6 +603,28 @@ static PreferencesController *prefs = nil;
     [vanishSpeedSlider     setFloatValue:-([df floatForKey:@"statusWindowVanishSpeed"])];
     [vanishDelaySlider     setFloatValue:[df floatForKey:@"statusWindowVanishDelay"]];
     [showOnChangeCheckbox  setState:([df boolForKey:@"showSongInfoOnChange"] ? NSOnState : NSOffState)];
+    
+    // Setup the sharing controls
+    if ([df boolForKey:@"enableSharing"]) {
+        [shareMenuTunesCheckbox setState:NSOnState];
+        [useSharedMenuTunesCheckbox setEnabled:NO];
+        [selectSharedPlayerButton setEnabled:NO];
+        [hostTextField setEnabled:NO];
+    } else if ([df boolForKey:@"useSharedPlayer"]) {
+        [useSharedMenuTunesCheckbox setState:NSOnState];
+        [shareMenuTunesCheckbox setEnabled:NO];
+        [sharePasswordCheckbox setEnabled:NO];
+        [sharePasswordTextField setEnabled:NO];
+    }
+    
+    [[NSNotificationCenter defaultCenter] addObserver:sharingTableView selector:@selector(reloadData) name:@"ITMTFoundNetService" object:nil];
+    
+    [selectPlayerBox setContentView:zeroConfView];
+    [sharePasswordCheckbox setState:([df boolForKey:@"enableSharingPassword"] ? NSOnState : NSOffState)];
+    //[sharePasswordTextField setStringValue:@""]; //DO THIS LATER
+    if ([df stringForKey:@"sharedPlayerHost"]) {
+        [hostTextField setStringValue:[df stringForKey:@"sharedPlayerHost"]];
+    }
 }
 
 - (IBAction)changeMenus:(id)sender
@@ -582,8 +687,10 @@ static PreferencesController *prefs = nil;
         return [myItems count];
     } else if (aTableView == allTableView) {
         return [availableItems count];
-    } else {
+    } else if (aTableView == hotKeysTableView) {
         return [hotKeysArray count];
+    } else {
+        return [[[NetworkController sharedController] remoteServices] count];
     }
 }
 
@@ -593,7 +700,13 @@ static PreferencesController *prefs = nil;
         NSString *object = [myItems objectAtIndex:rowIndex];
         if ([[aTableColumn identifier] isEqualToString:@"name"]) {
             if ([object isEqualToString:@"showPlayer"]) {
-                return [NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"show", @"Show"), [[controller currentRemote] playerSimpleName]];
+                NSString *string;
+                NS_DURING
+                    string = [NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"show", @"Show"), [[controller currentRemote] playerSimpleName]];
+                NS_HANDLER
+                    [controller networkError:localException];
+                NS_ENDHANDLER
+                return string;
             }
             return NSLocalizedString(object, @"ERROR");
         } else {
@@ -608,7 +721,13 @@ static PreferencesController *prefs = nil;
         NSString *object = [availableItems objectAtIndex:rowIndex];
         if ([[aTableColumn identifier] isEqualToString:@"name"]) {
             if ([object isEqualToString:@"showPlayer"]) {
-                return [NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"show", @"Show"), [[controller currentRemote] playerSimpleName]];
+                NSString *string;
+                NS_DURING
+                    string = [NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"show", @"Show"), [[controller currentRemote] playerSimpleName]];
+                NS_HANDLER
+                    [controller networkError:localException];
+                NS_ENDHANDLER
+                return string;
             }
             return NSLocalizedString(object, @"ERROR");
         } else {
@@ -618,12 +737,18 @@ static PreferencesController *prefs = nil;
                 return nil;
             }
         }
-    } else {
+    } else if (aTableView == hotKeysTableView) {
         if ([[aTableColumn identifier] isEqualToString:@"name"]) {
             return [hotKeyNamesArray objectAtIndex:rowIndex];
         } else {
             return [[hotKeysDictionary objectForKey:[hotKeysArray objectAtIndex:rowIndex]] description];
         }
+    } else {
+        if ([[aTableColumn identifier] isEqualToString:@"name"]) {
+            return [[[[NetworkController sharedController] remoteServices] objectAtIndex:rowIndex] objectForKey:@"name"];
+        } else {
+            return @"X";
+        }
     }
 }
 
index 929ea9d..b6ec5c1 100755 (executable)
Binary files a/libValidate.a and b/libValidate.a differ