From e350cc5032334a724daffdf6d2016e3653efc825 Mon Sep 17 00:00:00 2001 From: Matthew Judy Date: Fri, 25 Apr 2003 02:51:59 +0000 Subject: [PATCH] Adding new controller into CVS under the name NewMainController. However, building it will fail, since it thinks it is named MainCintroller. Also adding the StatusWindowController, and updating the nib. --- English.lproj/Preferences.nib/info.nib | 10 +- .../Preferences.nib/keyedobjects.nib | Bin 39485 -> 42439 bytes MainController.h | 48 + MainController.m | 1088 +++++++++++++++++ OldMainController.m | 4 +- PreferencesController.m | 1 + StatusWindowController.h | 51 + StatusWindowController.m | 48 + 8 files changed, 1241 insertions(+), 9 deletions(-) create mode 100755 MainController.h create mode 100755 MainController.m create mode 100755 StatusWindowController.h create mode 100755 StatusWindowController.m diff --git a/English.lproj/Preferences.nib/info.nib b/English.lproj/Preferences.nib/info.nib index 783d23f..467b1a7 100755 --- a/English.lproj/Preferences.nib/info.nib +++ b/English.lproj/Preferences.nib/info.nib @@ -3,9 +3,9 @@ IBDocumentLocation - 5 3 356 240 0 0 1152 746 + 4 3 356 240 0 0 1056 770 IBFramework Version - 291.0 + 286.0 IBGroupedObjects 0 @@ -20,11 +20,7 @@ 281 - IBOpenObjects - - 6 - IBSystem Version - 6L29 + 6L28 diff --git a/English.lproj/Preferences.nib/keyedobjects.nib b/English.lproj/Preferences.nib/keyedobjects.nib index b9904a887b4d15d76c2d6178b5a8da73c2c474c4..d12002a462b0cfb7839dd0a2ed9d9dda241b4ae4 100755 GIT binary patch delta 24012 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 DYz%cL delta 21510 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

B@8?vwk`T2Qc_voY6;aG`}UEFkToO6wmbeLG_7< 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 + * Responsibility : Matthew Judy + * + * Copyright (c) 2002-2003 iThink Software. + * All Rights Reserved + * + */ + + +#import +#import +#import +#import +#import + + +@class StatusWindowController; + + +@interface MainController : NSObject +{ + ITStatusItem *statusItem; + NSMutableArray *remoteArray; + ITMTRemote *currentRemote; + + ITMTRemotePlayerRunningState playerRunningState; + ITMTRemotePlayerPlaylistClass latestPlaylistClass; + + //Used in updating the menu automatically + NSTimer *refreshTimer; + + NSString *_latestSongIdentifier; + + StatusWindowController *statusWindowController; //Shows track info and upcoming songs. + NSUserDefaults *df; +} + + +- (ITMTRemote *)currentRemote; +- (void)clearHotKeys; +- (void)closePreferences; + +@end diff --git a/MainController.m b/MainController.m new file mode 100755 index 0000000..1b670eb --- /dev/null +++ b/MainController.m @@ -0,0 +1,1088 @@ +#import "MainController.h" +#import "PreferencesController.h" +#import "HotKeyCenter.h" +#import "StatusWindowController.h" + +@interface MainController(Private) +- (ITMTRemote *)loadRemote; +- (void)setupHotKeys; +- (void)timerUpdate; +- (void)setKeyEquivalentForCode:(short)code andModifiers:(long)modifiers + onItem:(NSMenuItem *)item; +@end + +@implementation MainController + +/*************************************************************************/ +#pragma mark - +#pragma mark INITIALIZATION/DEALLOCATION METHODS +/*************************************************************************/ + +- (id)init +{ + if ( ( self = [super init] ) ) { + remoteArray = [[NSMutableArray alloc] initWithCapacity:1]; + statusWindowController = [[StatusWindowController alloc] init]; + df = [[NSUserDefaults standardUserDefaults] retain]; + [self setLatestSongIdentifier:@"0-0"]; + } + return self; +} + +- (void)applicationDidFinishLaunching:(NSNotification *)note +{ + currentRemote = [self loadRemote]; + [currentRemote begin]; + + //Setup for notification of the remote player launching or quitting + [[[NSWorkspace sharedWorkspace] notificationCenter] + addObserver:self + selector:@selector(applicationTerminated:) + name:NSWorkspaceDidTerminateApplicationNotification + object:nil]; + + [[[NSWorkspace sharedWorkspace] notificationCenter] + addObserver:self + selector:@selector(applicationLaunched:) + name:NSWorkspaceDidLaunchApplicationNotification + object:nil]; + + if ( ! [df objectForKey:@"menu"] ) { // If this is nil, defaults have never been registered. + [[PreferencesController sharedPrefs] registerDefaults]; + } + + statusItem = [[ITStatusItem alloc] + initWithStatusBar:[NSStatusBar systemStatusBar] + withLength:NSSquareStatusItemLength]; + + [statusItem setImage:[NSImage imageNamed:@"menu"]]; + [statusItem setAlternateImage:[NSImage imageNamed:@"selected_image"]]; +} + +- (ITMTRemote *)loadRemote +{ + NSString *folderPath = [[NSBundle mainBundle] builtInPlugInsPath]; + + if (folderPath) { + NSArray *bundlePathList = [NSBundle pathsForResourcesOfType:@"remote" inDirectory:folderPath]; + NSEnumerator *enumerator = [bundlePathList objectEnumerator]; + NSString *bundlePath; + + while ( (bundlePath = [enumerator nextObject]) ) { + NSBundle* remoteBundle = [NSBundle bundleWithPath:bundlePath]; + + if (remoteBundle) { + Class remoteClass = [remoteBundle principalClass]; + + if ([remoteClass conformsToProtocol:@protocol(ITMTRemote)] && + [remoteClass isKindOfClass:[NSObject class]]) { + + id remote = [remoteClass remote]; + [remoteArray addObject:remote]; + } + } + } + +// if ( [remoteArray count] > 0 ) { // UNCOMMENT WHEN WE HAVE > 1 PLUGIN +// if ( [remoteArray count] > 1 ) { +// [remoteArray sortUsingSelector:@selector(sortAlpha:)]; +// } +// [self loadModuleAccessUI]; //Comment out this line to disable remote visibility +// } + } +// NSLog(@"%@", [remoteArray objectAtIndex:0]); //DEBUG + return [remoteArray objectAtIndex:0]; +} + +/*************************************************************************/ +#pragma mark - +#pragma mark INSTANCE METHODS +/*************************************************************************/ + +- (void)startTimerInNewThread +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; + refreshTimer = [[NSTimer scheduledTimerWithTimeInterval:0.5 + target:self + selector:@selector(timerUpdate) + userInfo:nil + repeats:YES] retain]; + [runLoop run]; + [pool release]; +} + + +/*************************************************************************/ +#pragma mark - +#pragma mark MENU BUILDING METHODS +/*************************************************************************/ + +- (NSMenu *)menu +{ + NSMenu *theMenu = [[[NSMenu alloc] initWithTitle:@""] autorelease]; + + [theMenu addItem:[self playlistMenuItem]]; + [theMenu addItem:[self upcomingSongsMenuItem]]; + [theMenu addItem:[self ratingMenuItem]]; + + return theMenu; +} + +- (NSMenu *)menuForNoPlayer +{ + return nil; +} + +- (NSMenuItem *)playlistMenuItem +{ + NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:@"Playlists" + action:nil + keyEquivalent:@""] autorelease]; + NSMenu *submenu = [[[NSMenu alloc] initWithTitle:@""] autorelease]; + + int currentPlaylist = [currentRemote currentPlaylistIndex]; + NSArray *playlists = [currentRemote playlists]; + NSEnumerator *playlistEnum = [playlists objectEnumerator]; + int playlistTag = 1; + id aPlaylist; + + [item setSubmenu:submenu]; + [submenu setAutoenablesItems:NO]; + + while ( (aPlaylist = [playlistEnum nextObject]) ) { + NSMenuItem *playlistItem = [[[NSMenuItem alloc] initWithTitle:aPlaylist + action:@selector(selectPlaylist:) + keyEquivalent:@""] autorelease]; + [playlistItem setTag:playlistTag]; + [playlistItem setTarget:self]; + playlistTag++; + [submenu addItem:playlistItem]; + } + + if ( (! [self radioIsPlaying]) && currentPlaylist) { + [[submenu itemAtIndex:(currentPlaylist - 1)] setState:NSOnState]; + } + + return item; +} + +- (NSMenuItem *)upcomingSongsMenuItem +{ + NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:@"Upcoming Songs" + action:nil + keyEquivalent:@""] autorelease]; + NSMenu *submenu = [[[NSMenu alloc] initWithTitle:@""] autorelease]; + + int curIndex = [currentRemote currentPlaylistIndex]; + int numSongs = [currentRemote numberOfSongsInPlaylistAtIndex:curIndex]; + int numSongsInAdvance = [df integerForKey:@"SongsInAdvance"]; + + [item setSubmenu:submenu]; + + if ( [self radioIsPlaying] ) { + [submenu addItemWithTitle:@"No Upcoming Songs..." action:nil keyEquivalent:@""]; + [submenu addItemWithTitle:@"Playing Radio Stream" action:nil keyEquivalent:@""]; + } else { + if ( ! (numSongs > 0) ) { + [submenu addItemWithTitle:@"No Songs in Playlist" action:nil keyEquivalent:@""]; + } else { + int curTrack = [currentRemote currentSongIndex]; + int i; + + for (i = curTrack + 1; ( (i <= curTrack + numSongsInAdvance) && (i <= numSongs) ); i++) { + + NSString *curSong = [currentRemote songTitleAtIndex:i]; + NSMenuItem *songItem = [[[NSMenuItem alloc] initWithTitle:curSong + action:@selector(selectSong:) + keyEquivalent:@""] autorelease]; + [songItem setRepresentedObject:[NSNumber numberWithInt:i]]; + [submenu addItem:songItem]; + } + } + } + + return item; +} + +- (NSMenuItem *)ratingMenuItem +{ + NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:@"Rating" + action:nil + keyEquivalent:@""] autorelease]; + NSMenu *submenu = [[[NSMenu alloc] initWithTitle:@""] autorelease]; + + [item setSubmenu:submenu]; + + [submenu addItemWithTitle:[NSString stringWithUTF8String:"☆☆☆☆☆"] action:nil keyEquivalent:@""]; + [submenu addItemWithTitle:[NSString stringWithUTF8String:"★☆☆☆☆"] action:nil keyEquivalent:@""]; + [submenu addItemWithTitle:[NSString stringWithUTF8String:"★★☆☆☆"] action:nil keyEquivalent:@""]; + [submenu addItemWithTitle:[NSString stringWithUTF8String:"★★★☆☆"] action:nil keyEquivalent:@""]; + [submenu addItemWithTitle:[NSString stringWithUTF8String:"★★★★☆"] action:nil keyEquivalent:@""]; + [submenu addItemWithTitle:[NSString stringWithUTF8String:"★★★★★"] action:nil keyEquivalent:@""]; + + if ( ! ( [self radioIsPlaying] || [self songIsPlaying] ) ) { + + NSEnumerator *itemEnum; + id anItem; + int itemTag = 0; + SEL itemSelector = @selector(selectSongRating:); + + itemEnum = [[submenu itemArray] objectEnumerator]; + while ( (anItem = [itemEnum nextObject]) ) { + [anItem setAction:itemSelector]; + [anItem setTag:itemTag]; + itemTag += 20; + } + } + + return item; +} + +- (NSMenuItem *)eqMenuItem +{ + NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:@"Equalizer" + action:nil + keyEquivalent:@""] autorelease]; + NSMenu *submenu = [[[NSMenu alloc] initWithTitle:@""] autorelease]; + + NSArray *eqPresets = [currentRemote eqPresets]; + NSEnumerator *eqEnum = [eqPresets objectEnumerator]; + int eqTag = 0; + id anEq; + + [item setSubmenu:submenu]; + + while ( ( anEq = [eqEnum nextObject]) ) { + NSMenuItem *eqItem = [[[NSMenuItem alloc] initWithTitle:anEq + action:@selector(selectEQPreset:) + keyEquivalent:@""] autorelease]; + [eqItem setTag:eqTag]; + eqTag++; + [submenu addItem:eqItem]; + } + + [[submenu itemAtIndex:([currentRemote currentEQPresetIndex] - 1)] setState:NSOnState]; +} + +- (BOOL)songIsPlaying +{ + return ( ! ([[currentRemote currentSongUniqueIdentifier] isEqualToString:@"0-0"]) ); +} + +- (BOOL)radioIsPlaying +{ + return ( [currentRemote currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist ); +} + +- (BOOL)songChanged +{ + return ( ! [[currentRemote currentSongUniqueIdentifier] isEqualToString:_latestSongIdentifier] ); +} + +- (NSString *)latestSongIdentifier +{ + return _latestSongIdentifier; +} + +- (void)setLatestSongIdentifier:(NSString *)newIdentifier +{ + [_latestSongIdentifier autorelease]; + _latestSongIdentifier = [newIdentifier copy]; +} + +/* +//Recreate the status item menu +- (void)rebuildMenu +{ + NSArray *myMenu = [df arrayForKey:@"menu"]; + int playlist = [currentRemote currentPlaylistIndex]; + int i; + + if ([currentRemote playerRunningState] == ITMTRemotePlayerNotRunning) { + return; + } + + trackInfoIndex = -1; + lastPlaylistIndex = -1; + + [menu release]; + menu = [[NSMenu alloc] initWithTitle:@""]; + + playPauseItem = nil; + + upcomingSongsItem = nil; + [upcomingSongsMenu release]; + upcomingSongsMenu = nil; + + if (ratingItem) { + [ratingItem setSubmenu:nil]; + } + + playlistItem = nil; + [playlistMenu release]; + playlistMenu = nil; + + eqItem = nil; + [eqMenu release]; + eqMenu = nil; + + //Build the custom menu + for (i = 0; i < [myMenu count]; i++) { + NSString *item = [myMenu objectAtIndex:i]; + if ([item isEqualToString:@"Play/Pause"]) { + KeyCombo *tempCombo = [df keyComboForKey:@"PlayPause"]; + playPauseItem = [menu addItemWithTitle:@"Play" + action:@selector(playPause:) + keyEquivalent:@""]; + + if (tempCombo) { + [self setKeyEquivalentForCode:[tempCombo keyCode] + andModifiers:[tempCombo modifiers] onItem:playPauseItem]; + [tempCombo release]; + } + } else if ([item isEqualToString:@"Next Track"]) { + KeyCombo *tempCombo = [df keyComboForKey:@"NextTrack"]; + NSMenuItem *nextTrack = [menu addItemWithTitle:@"Next Track" + action:@selector(nextSong:) + keyEquivalent:@""]; + + if (tempCombo) { + [self setKeyEquivalentForCode:[tempCombo keyCode] + andModifiers:[tempCombo modifiers] onItem:nextTrack]; + [tempCombo release]; + } + } else if ([item isEqualToString:@"Previous Track"]) { + KeyCombo *tempCombo = [df keyComboForKey:@"PrevTrack"]; + NSMenuItem *prevTrack = [menu addItemWithTitle:@"Previous Track" + action:@selector(prevSong:) + keyEquivalent:@""]; + + if (tempCombo) { + [self setKeyEquivalentForCode:[tempCombo keyCode] + andModifiers:[tempCombo modifiers] onItem:prevTrack]; + [tempCombo release]; + } + } else if ([item isEqualToString:@"Fast Forward"]) { + [menu addItemWithTitle:@"Fast Forward" + action:@selector(fastForward:) + keyEquivalent:@""]; + } else if ([item isEqualToString:@"Rewind"]) { + [menu addItemWithTitle:@"Rewind" + action:@selector(rewind:) + keyEquivalent:@""]; + } else if ([item isEqualToString:@"Show Player"]) { + [menu addItemWithTitle:[NSString stringWithFormat:@"Show %@", [currentRemote playerSimpleName]] + action:@selector(showPlayer:) + keyEquivalent:@""]; + } else if ([item isEqualToString:@"Upcoming Songs"]) { + upcomingSongsItem = [menu addItemWithTitle:@"Upcoming Songs" + action:nil + keyEquivalent:@""]; + upcomingSongsMenu = [[NSMenu alloc] initWithTitle:@""]; + [upcomingSongsItem setSubmenu:upcomingSongsMenu]; + [upcomingSongsItem setEnabled:NO]; + } else if ([item isEqualToString:@"Playlists"]) { + playlistItem = [menu addItemWithTitle:@"Playlists" + action:nil + keyEquivalent:@""]; + } else if ([item isEqualToString:@"EQ Presets"]) { + eqItem = [menu addItemWithTitle:@"EQ Presets" + action:nil + keyEquivalent:@""]; + } else if ([item isEqualToString:@"Preferences…"]) { + [menu addItemWithTitle:@"Preferences…" + action:@selector(showPreferences:) + keyEquivalent:@""]; + } else if ([item isEqualToString:@"Quit"]) { + [menu addItemWithTitle:@"Quit" + action:@selector(quitMenuTunes:) + keyEquivalent:@""]; + } else if ([item isEqualToString:@"Current Track Info"]) { + trackInfoIndex = [menu numberOfItems]; + [menu addItemWithTitle:@"No Song" + action:nil + keyEquivalent:@""]; + } else if ([item isEqualToString:@"Song Rating"]) { + ratingItem = [menu addItemWithTitle:@"Song Rating" + action:nil + keyEquivalent:@""]; + [ratingItem setSubmenu:ratingMenu]; + } else if ([item isEqualToString:@""]) { + [menu addItem:[NSMenuItem separatorItem]]; + } + } + + if (playlistItem) { + [self rebuildPlaylistMenu]; + } + + if (eqItem) { + [self rebuildEQPresetsMenu]; + } + + isPlayingRadio = ([currentRemote classOfPlaylistAtIndex:playlist] == ITMTRemotePlayerRadioPlaylist); + + if (upcomingSongsItem) { + [self rebuildUpcomingSongsMenu]; + } + + if (ratingItem) { + if (isPlayingRadio || !playlist) { + [ratingItem setEnabled:NO]; + } else { + int currentSongRating = ([currentRemote currentSongRating] * 5); + [[ratingMenu itemAtIndex:lastSongRating] setState:NSOffState]; + lastSongRating = currentSongRating; + [[ratingMenu itemAtIndex:lastSongRating] setState:NSOnState]; + [ratingItem setEnabled:YES]; + } + } + + //Set the new unique song identifier + lastSongIdentifier = [[currentRemote currentSongUniqueIdentifier] retain]; + + //If we're in a playlist or radio mode + if ( ![lastSongIdentifier isEqualToString:@"0-0"] && (trackInfoIndex > -1) ) { + NSString *title; + + if ( (i = [menu indexOfItemWithTitle:@"No Song"]) ) { + if ( (i > -1) ) { + [menu removeItemAtIndex:i]; + [menu insertItemWithTitle:@"Now Playing" action:NULL keyEquivalent:@"" atIndex:i]; + } + } + + title = [currentRemote currentSongTitle]; + + if (!isPlayingRadio) { + if ([df boolForKey:@"showTime"]) { + NSString *length = [currentRemote currentSongLength]; + char character = [length characterAtIndex:0]; + if ( (character > '0') && (character < '9') ) { + [menu insertItemWithTitle:[NSString stringWithFormat:@" %@", [currentRemote currentSongLength]] action:nil keyEquivalent:@"" atIndex:trackInfoIndex + 1]; + } + } + + if ([df boolForKey:@"showRating"]) { + if (title) { //Check to see if there's a song playing + [menu insertItemWithTitle:[NSString stringWithFormat:@" %@", [[ratingMenu itemAtIndex:[currentRemote currentSongRating] * 5] title]] action:nil keyEquivalent:@"" atIndex:trackInfoIndex + 1]; + } + } + + if ([df boolForKey:@"showArtist"]) { + NSString *artist = [currentRemote currentSongArtist]; + if ([artist length] > 0) { + [menu insertItemWithTitle:[NSString stringWithFormat:@" %@", artist] action:nil keyEquivalent:@"" atIndex:trackInfoIndex + 1]; + } + } + + if ([df boolForKey:@"showNumber"]) { + int track = [currentRemote currentSongTrack]; + int total = [currentRemote currentAlbumTrackCount]; + if (total > 0) { + [menu insertItemWithTitle:[NSString stringWithFormat:@" Track %i of %i", track, total] action:nil keyEquivalent:@"" atIndex:trackInfoIndex + 1]; + } + } + + if ([df boolForKey:@"showAlbum"]) { + NSString *album = [currentRemote currentSongAlbum]; + if ([album length] > 0) { + [menu insertItemWithTitle:[NSString stringWithFormat:@" %@", album] action:nil keyEquivalent:@"" atIndex:trackInfoIndex + 1]; + } + } + } + + if ([title length] > 0) { + [menu insertItemWithTitle:[NSString stringWithFormat:@" %@", title] action:nil keyEquivalent:@"" atIndex:trackInfoIndex + 1]; + } + } + + [statusItem setMenu:menu]; + + [self clearHotKeys]; + [self setupHotKeys]; +} + + +//Build a menu with the list of all available EQ presets +- (void)rebuildEQPresetsMenu +{ + NSArray *eqPresets = [currentRemote eqPresets]; + int i; + + [eqMenu autorelease]; + eqMenu = [[NSMenu alloc] initWithTitle:@""]; + + for (i = 0; i < [eqPresets count]; i++) { + NSString *name; + NSMenuItem *tempItem; + if ( ( name = [eqPresets objectAtIndex:i] ) ) { + tempItem = [[NSMenuItem alloc] initWithTitle:name action:@selector(selectEQPreset:) keyEquivalent:@""]; + [tempItem setTag:i]; + [eqMenu addItem:tempItem]; + [tempItem autorelease]; + } + } + + [eqItem setSubmenu:eqMenu]; + [eqItem setEnabled:YES]; + [[eqMenu itemAtIndex:([currentRemote currentEQPresetIndex] - 1)] setState:NSOnState]; +} + +*/ + +- (void)timerUpdate +{ + if ( ( [self songChanged] ) || + ( ([self radioIsPlaying]) && (latestPlaylistClass != ITMTRemotePlayerRadioPlaylist) ) || + ( (! [self radioIsPlaying]) && (latestPlaylistClass == ITMTRemotePlayerRadioPlaylist) ) ) { + [statusItem setMenu:[self menu]]; + [self setLatestSongIdentifier:[currentRemote currentSongUniqueIdentifier]]; + latestPlaylistClass = [currentRemote currentPlaylistClass]; + + if ( [df boolForKey:@"showSongInfoOnChange"] ) { + [self showCurrentTrackInfo]; + } + } +/* + //Update Play/Pause menu item + if (playPauseItem){ + if ([currentRemote playerPlayingState] == ITMTRemotePlayerPlaying) { + [playPauseItem setTitle:@"Pause"]; + } else { + [playPauseItem setTitle:@"Play"]; + } + } +*/ +} + +/* +// +// +// Menu Selectors +// +// + +- (void)selectSong:(id)sender +{ + [currentRemote switchToSongAtIndex:[[sender representedObject] intValue]]; +} +*/ +- (void)selectPlaylist:(id)sender +{ + int playlist = [sender tag]; + [currentRemote switchToPlaylistAtIndex:playlist]; +} +/* +- (void)selectEQPreset:(id)sender +{ + int curSet = [currentRemote currentEQPresetIndex]; + int item = [sender tag]; + + [currentRemote switchToEQAtIndex:item]; + [[eqMenu itemAtIndex:curSet - 1] setState:NSOffState]; + [[eqMenu itemAtIndex:item] setState:NSOnState]; +} +*/ +/* +- (void)selectSongRating:(id)sender +{ + int newRating = [sender tag]; +// [[ratingMenu itemAtIndex:lastSongRating] setState:NSOffState]; + [sender setState:NSOnState]; + [currentRemote setCurrentSongRating:(float)newRating / 100.0]; + lastSongRating = newRating / 20; +} +*/ +/* +- (void)playPause:(id)sender +{ + ITMTRemotePlayerPlayingState state = [currentRemote playerPlayingState]; + + if (state == ITMTRemotePlayerPlaying) { + [currentRemote pause]; + [playPauseItem setTitle:@"Play"]; + } else if ((state == ITMTRemotePlayerForwarding) || (state == ITMTRemotePlayerRewinding)) { + [currentRemote pause]; + [currentRemote play]; + } else { + [currentRemote play]; + [playPauseItem setTitle:@"Pause"]; + } +} + +- (void)nextSong:(id)sender +{ + [currentRemote goToNextSong]; +} + +- (void)prevSong:(id)sender +{ + [currentRemote goToPreviousSong]; +} + +- (void)fastForward:(id)sender +{ + [currentRemote forward]; + [playPauseItem setTitle:@"Play"]; +} + +- (void)rewind:(id)sender +{ + [currentRemote rewind]; + [playPauseItem setTitle:@"Play"]; +} +*/ + +// +// +- (void)quitMenuTunes:(id)sender +{ + [NSApp terminate:self]; +} + +- (void)showPlayer:(id)sender +{ + if ( ( playerRunningState == ITMTRemotePlayerRunning) ) { + [currentRemote showPrimaryInterface]; + } else { + if (![[NSWorkspace sharedWorkspace] launchApplication:[currentRemote playerFullName]]) { + NSLog(@"Error Launching Player"); + } + } +} + +- (void)showPreferences:(id)sender +{ + [[PreferencesController sharedPrefs] setController:self]; + [[PreferencesController sharedPrefs] showPrefsWindow:self]; +} + +- (void)closePreferences +{ + if ( ( playerRunningState == ITMTRemotePlayerRunning) ) { + [self setupHotKeys]; + } +} + +- (ITMTRemote *)currentRemote +{ + return currentRemote; +} + +// +// +// Hot key setup +// +// + +- (void)clearHotKeys +{ + [[HotKeyCenter sharedCenter] removeHotKey:@"PlayPause"]; + [[HotKeyCenter sharedCenter] removeHotKey:@"NextTrack"]; + [[HotKeyCenter sharedCenter] removeHotKey:@"PrevTrack"]; + [[HotKeyCenter sharedCenter] removeHotKey:@"TrackInfo"]; + [[HotKeyCenter sharedCenter] removeHotKey:@"UpcomingSongs"]; + [[HotKeyCenter sharedCenter] removeHotKey:@"ToggleLoop"]; + [[HotKeyCenter sharedCenter] removeHotKey:@"ToggleShuffle"]; + [[HotKeyCenter sharedCenter] removeHotKey:@"IncrementVolume"]; + [[HotKeyCenter sharedCenter] removeHotKey:@"DecrementVolume"]; + [[HotKeyCenter sharedCenter] removeHotKey:@"IncrementRating"]; + [[HotKeyCenter sharedCenter] removeHotKey:@"DecrementRating"]; +} + +- (void)setupHotKeys +{ + if ([df objectForKey:@"PlayPause"] != nil) { + [[HotKeyCenter sharedCenter] addHotKey:@"PlayPause" + combo:[df keyComboForKey:@"PlayPause"] + target:self action:@selector(playPause:)]; + } + + if ([df objectForKey:@"NextTrack"] != nil) { + [[HotKeyCenter sharedCenter] addHotKey:@"NextTrack" + combo:[df keyComboForKey:@"NextTrack"] + target:self action:@selector(nextSong:)]; + } + + if ([df objectForKey:@"PrevTrack"] != nil) { + [[HotKeyCenter sharedCenter] addHotKey:@"PrevTrack" + combo:[df keyComboForKey:@"PrevTrack"] + target:self action:@selector(prevSong:)]; + } + + if ([df objectForKey:@"TrackInfo"] != nil) { + [[HotKeyCenter sharedCenter] addHotKey:@"TrackInfo" + combo:[df keyComboForKey:@"TrackInfo"] + target:self action:@selector(showCurrentTrackInfo)]; + } + + if ([df objectForKey:@"UpcomingSongs"] != nil) { + [[HotKeyCenter sharedCenter] addHotKey:@"UpcomingSongs" + combo:[df keyComboForKey:@"UpcomingSongs"] + target:self action:@selector(showUpcomingSongs)]; + } + + if ([df objectForKey:@"ToggleLoop"] != nil) { + [[HotKeyCenter sharedCenter] addHotKey:@"ToggleLoop" + combo:[df keyComboForKey:@"ToggleLoop"] + target:self action:NULL/*Set this to something*/]; + } + + if ([df objectForKey:@"ToggleShuffle"] != nil) { + [[HotKeyCenter sharedCenter] addHotKey:@"ToggleShuffle" + combo:[df keyComboForKey:@"ToggleShuffle"] + target:self action:NULL/*Set this to something*/]; + } + + if ([df objectForKey:@"IncrementVolume"] != nil) { + [[HotKeyCenter sharedCenter] addHotKey:@"IncrementVolume" + combo:[df keyComboForKey:@"IncrementVolume"] + target:self action:NULL/*Set this to something*/]; + } + + if ([df objectForKey:@"DecrementVolume"] != nil) { + [[HotKeyCenter sharedCenter] addHotKey:@"DecrementVolume" + combo:[df keyComboForKey:@"DecrementVolume"] + target:self action:NULL/*Set this to something*/]; + } + + if ([df objectForKey:@"IncrementRating"] != nil) { + [[HotKeyCenter sharedCenter] addHotKey:@"IncrementRating" + combo:[df keyComboForKey:@"IncrementRating"] + target:self action:NULL/*Set this to something*/]; + } + + if ([df objectForKey:@"DecrementRating"] != nil) { + [[HotKeyCenter sharedCenter] addHotKey:@"DecrementRating" + combo:[df keyComboForKey:@"DecrementRating"] + target:self action:NULL/*Set this to something*/]; + } +} + +- (void)showCurrentTrackInfo +{ + NSString *title = [currentRemote currentSongTitle]; + + if ( title ) { + NSString *album = nil; + NSString *artist = nil; + NSString *time = nil; + int trackNumber = 0; + int trackTotal = 0; + int rating = 0; + + if ( [df boolForKey:@"showAlbum"] ) { + album = [currentRemote currentSongAlbum]; + } + + if ( [df boolForKey:@"showArtist"] ) { + artist = [currentRemote currentSongArtist]; + } + + if ( [df boolForKey:@"showTime"] ) { + time = [currentRemote currentSongLength]; + } + + if ( [df boolForKey:@"showNumber"] ) { + trackNumber = [currentRemote currentSongTrack]; + trackTotal = [currentRemote currentAlbumTrackCount]; + } + + if ( [df boolForKey:@"showRating"] ) { + rating = ( [currentRemote currentSongRating] * 5 ); + } + + [statusWindowController showSongWindowWithTitle:title + album:album + artist:artist + time:time + trackNumber:trackNumber + trackTotal:trackTotal + rating:rating]; + } else { + title = @"No song is playing."; + [statusWindowController showSongWindowWithTitle:title + album:nil + artist:nil + time:nil + trackNumber:0 + trackTotal:0 + rating:0]; + } +} + +- (void)showUpcomingSongs +{ + int curPlaylist = [currentRemote currentPlaylistIndex]; + int numSongs = [currentRemote numberOfSongsInPlaylistAtIndex:curPlaylist]; + + 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]]; + } + } + + [statusWindowController showUpcomingSongsWithTitles:songList]; + + } else { + [statusWindowController showUpcomingSongsWithTitles:[NSArray arrayWithObject:@"No upcoming songs."]]; + } +} + +- (void)setKeyEquivalentForCode:(short)code andModifiers:(long)modifiers + onItem:(NSMenuItem *)item +{ + unichar charcode = 'a'; + int i; + long cocoaModifiers = 0; + static long carbonToCocoa[6][2] = + { + { cmdKey, NSCommandKeyMask }, + { optionKey, NSAlternateKeyMask }, + { controlKey, NSControlKeyMask }, + { shiftKey, NSShiftKeyMask }, + }; + + for (i = 0; i < 6; i++) { + if (modifiers & carbonToCocoa[i][0]) { + cocoaModifiers += carbonToCocoa[i][1]; + } + } + [item setKeyEquivalentModifierMask:cocoaModifiers]; + + //Missing key combos for some keys. Must find them later. + switch (code) + { + case 36: + charcode = '\r'; + break; + + case 48: + charcode = '\t'; + break; + + //Space -- ARGH! + case 49: + { + // Haven't tested this, though it should work. + unichar buffer; + [[NSString stringWithString:@"Space"] getCharacters:&buffer]; + charcode = buffer; + /*MenuRef menuRef = _NSGetCarbonMenu([item menu]); + NSLog(@"%@", menuRef); + SetMenuItemCommandKey(menuRef, 0, NO, 49); + SetMenuItemModifiers(menuRef, 0, kMenuNoCommandModifier); + SetMenuItemKeyGlyph(menuRef, 0, kMenuBlankGlyph); + charcode = 'b';*/ + + } + break; + + case 51: + charcode = NSDeleteFunctionKey; + break; + + case 53: + charcode = '\e'; + break; + + case 71: + charcode = '\e'; + break; + + case 76: + charcode = '\r'; + break; + + case 96: + charcode = NSF5FunctionKey; + break; + + case 97: + charcode = NSF6FunctionKey; + break; + + case 98: + charcode = NSF7FunctionKey; + break; + + case 99: + charcode = NSF3FunctionKey; + break; + + case 100: + charcode = NSF8FunctionKey; + break; + + case 101: + charcode = NSF9FunctionKey; + break; + + case 103: + charcode = NSF11FunctionKey; + break; + + case 105: + charcode = NSF3FunctionKey; + break; + + case 107: + charcode = NSF14FunctionKey; + break; + + case 109: + charcode = NSF10FunctionKey; + break; + + case 111: + charcode = NSF12FunctionKey; + break; + + case 113: + charcode = NSF13FunctionKey; + break; + + case 114: + charcode = NSInsertFunctionKey; + break; + + case 115: + charcode = NSHomeFunctionKey; + break; + + case 116: + charcode = NSPageUpFunctionKey; + break; + + case 117: + charcode = NSDeleteFunctionKey; + break; + + case 118: + charcode = NSF4FunctionKey; + break; + + case 119: + charcode = NSEndFunctionKey; + break; + + case 120: + charcode = NSF2FunctionKey; + break; + + case 121: + charcode = NSPageDownFunctionKey; + break; + + case 122: + charcode = NSF1FunctionKey; + break; + + case 123: + charcode = NSLeftArrowFunctionKey; + break; + + case 124: + charcode = NSRightArrowFunctionKey; + break; + + case 125: + charcode = NSDownArrowFunctionKey; + break; + + case 126: + charcode = NSUpArrowFunctionKey; + break; + } + + if (charcode == 'a') { + unsigned long state; + long keyTrans; + char charCode; + Ptr kchr; + state = 0; + kchr = (Ptr) GetScriptVariable(smCurrentScript, smKCHRCache); + keyTrans = KeyTranslate(kchr, code, &state); + charCode = keyTrans; + [item setKeyEquivalent:[NSString stringWithCString:&charCode length:1]]; + } else if (charcode != 'b') { + [item setKeyEquivalent:[NSString stringWithCharacters:&charcode length:1]]; + } +} + +/*************************************************************************/ +#pragma mark - +#pragma mark WORKSPACE NOTIFICATION HANDLERS +/*************************************************************************/ + +- (void)applicationLaunched:(NSNotification *)note +{ + if (!note || [[[note userInfo] objectForKey:@"NSApplicationName"] isEqualToString:[currentRemote playerFullName]]) { + [NSThread detachNewThreadSelector:@selector(startTimerInNewThread) toTarget:self withObject:nil]; + [self setupHotKeys]; + playerRunningState = ITMTRemotePlayerRunning; + } +} + + - (void)applicationTerminated:(NSNotification *)note + { + if (!note || [[[note userInfo] objectForKey:@"NSApplicationName"] isEqualToString:[currentRemote playerFullName]]) { +/* + NSMenu *notRunningMenu = [[NSMenu alloc] initWithTitle:@""]; + [notRunningMenu addItemWithTitle:[NSString stringWithFormat:@"Open %@", [currentRemote playerSimpleName]] action:@selector(showPlayer:) keyEquivalent:@""]; + [notRunningMenu addItem:[NSMenuItem separatorItem]]; + [notRunningMenu addItemWithTitle:@"Preferences" action:@selector(showPreferences:) keyEquivalent:@""]; + [notRunningMenu addItemWithTitle:@"Quit" action:@selector(quitMenuTunes:) keyEquivalent:@""]; +*/ + [refreshTimer invalidate]; + [refreshTimer release]; + refreshTimer = nil; + [self clearHotKeys]; + playerRunningState = ITMTRemotePlayerNotRunning; + + [statusItem setMenu:[self menuForNoPlayer]]; + } + } + + +/*************************************************************************/ +#pragma mark - +#pragma mark NSApplication DELEGATE METHODS +/*************************************************************************/ + +- (void)applicationWillTerminate:(NSNotification *)note +{ + [self clearHotKeys]; + [[NSStatusBar systemStatusBar] removeStatusItem:statusItem]; +} + + +/*************************************************************************/ +#pragma mark - +#pragma mark DEALLOCATION METHOD +/*************************************************************************/ + +- (void)dealloc +{ + if (refreshTimer) { + [refreshTimer invalidate]; + [refreshTimer release]; + refreshTimer = nil; + } + + [currentRemote halt]; + [statusItem release]; + [statusWindowController release]; + [super dealloc]; +} + + +@end diff --git a/OldMainController.m b/OldMainController.m index 8c6d514..dab1899 100755 --- a/OldMainController.m +++ b/OldMainController.m @@ -294,8 +294,8 @@ eqItem = [menu addItemWithTitle:@"EQ Presets" action:nil keyEquivalent:@""]; - } else if ([item isEqualToString:@"PreferencesÉ"]) { - [menu addItemWithTitle:@"PreferencesÉ" + } else if ([item isEqualToString:@"Preferences…"]) { + [menu addItemWithTitle:@"Preferences…" action:@selector(showPreferences:) keyEquivalent:@""]; } else if ([item isEqualToString:@"Quit"]) { diff --git a/PreferencesController.m b/PreferencesController.m index 5c9f059..9d8e2f0 100755 --- a/PreferencesController.m +++ b/PreferencesController.m @@ -152,6 +152,7 @@ static PreferencesController *prefs = nil; // Update vanish delay } else if ( [sender tag] == 2080) { // Update "Song Info window when song changes" setting. + [df setBool:SENDER_STATE forKey:@"showSongInfoOnChange"]; } } diff --git a/StatusWindowController.h b/StatusWindowController.h new file mode 100755 index 0000000..63364a6 --- /dev/null +++ b/StatusWindowController.h @@ -0,0 +1,51 @@ +/* + * MenuTunes + * StatusWindowController + * Abstraction layer between MainController and StatusWindow + * + * Original Author : Matthew Judy + * Responsibility : Matthew Judy + * + * Copyright (c) 2003 iThink Software. + * All Rights Reserved + * + */ + + +#import + + +@class StatusWindow; + + +typedef enum { + MTStatusWindowLoopModeLoopNone, + MTStatusWindowLoopModeLoopOne, + MTStatusWindowLoopModeLoopAll +} MTStatusWindowLoopMode; + +typedef enum { + MTStatusWindowShuffleModeOn, + MTStatusWindowShuffleModeOff +} MTStatusWindowShuffleMode; + + +@interface StatusWindowController : NSObject { + StatusWindow *_window; +} + +- (void)showSongWindowWithTitle:(NSString *)title + album:(NSString *)album + artist:(NSString *)artist + time:(NSString *)time // FLOW: Should probably be NSDate or something. + trackNumber: (int)trackNumber + trackTotal: (int)trackTotal + rating: (int)rating; + +- (void)showUpcomingSongsWithTitles:(NSArray *)titleStrings; + +- (void)showVolumeWindowWithLevel:(int)level; +- (void)showShuffleWindowWithMode:(MTStatusWindowShuffleMode)mode; +- (void)showLoopWindowWithMode:(MTStatusWindowLoopMode)mode; + +@end diff --git a/StatusWindowController.m b/StatusWindowController.m new file mode 100755 index 0000000..649ca9c --- /dev/null +++ b/StatusWindowController.m @@ -0,0 +1,48 @@ +// +// StatusWindowController.m +// MenuTunes +// +// Created by Matthew L. Judy on Thu Apr 17 2003. +// Copyright (c) 2003 NibFile.com. All rights reserved. +// + +#import "StatusWindowController.h" + + +@implementation StatusWindowController + + +- (void)showSongWindowWithTitle:(NSString *)title + album:(NSString *)album + artist:(NSString *)artist + time:(NSString *)time // FLOW: Should probably be NSDate or something. + trackNumber: (int)trackNumber + trackTotal: (int)trackTotal + rating: (int)rating +{ + +} + +- (void)showUpcomingSongsWithTitles:(NSArray *)titleStrings +{ + +} + +- (void)showVolumeWindowWithLevel:(int)level +{ + +} + +- (void)showShuffleWindowWithMode:(MTStatusWindowShuffleMode)mode +{ + +} + +- (void)showLoopWindowWithMode:(MTStatusWindowLoopMode)mode +{ + +} + + + +@end -- 2.20.1