285 lines
11 KiB
Objective-C
285 lines
11 KiB
Objective-C
//
|
|
// MainController.m
|
|
// iLyrics
|
|
//
|
|
// Created by Kim Wittenburg on 10.06.12.
|
|
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
|
//
|
|
|
|
#import "MainController.h"
|
|
|
|
@implementation MainController {
|
|
NSMutableArray *data;
|
|
id<LyricsHoster> currentHoster;
|
|
BOOL lyricsSelected;
|
|
NSInteger selectedSavePanelButton;
|
|
NSURL *saveFile;
|
|
iTunesApplication *iTunes;
|
|
Lyrics *currentLyrics;
|
|
int selectedRow;
|
|
}
|
|
@synthesize iLyricsMenuItem;
|
|
@synthesize window;
|
|
@synthesize searchField;
|
|
@synthesize resultsOutline;
|
|
@synthesize loadMoreResultsButton;
|
|
@synthesize showPreviewCheckBox;
|
|
@synthesize previewPopover;
|
|
@synthesize previewTextArea;
|
|
@synthesize songLabel;
|
|
@synthesize artistLabel;
|
|
@synthesize sendToiTunesButton;
|
|
@synthesize downloadLyricsButton;
|
|
@synthesize lyricsArea;
|
|
|
|
|
|
-(id)init {
|
|
iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];
|
|
data = [[NSMutableArray alloc] init];
|
|
currentHoster = [[Magistrix alloc] init];
|
|
return [super init];
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Outline view Data Source and Delegate
|
|
-(NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
|
|
return item == nil ? [data count] : 0;
|
|
}
|
|
|
|
-(id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
|
|
return [data objectAtIndex:index];
|
|
}
|
|
|
|
-(BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
|
|
return NO;
|
|
}
|
|
|
|
-(id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
|
|
if ([[tableColumn identifier] isEqualToString:@"song"]) {
|
|
return [item name];
|
|
} else {
|
|
return [item artist];
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
|
|
-(NSString *)outlineView:(NSOutlineView *)outlineView toolTipForCell:(NSCell *)cell rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)tableColumn item:(id)item mouseLocation:(NSPoint)mouseLocation {
|
|
//item is an instance of SearchResult
|
|
[self shouldShowPreviewForCellRect:*rect searchResult:item];
|
|
return nil;
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Responding to Lyrics Search
|
|
|
|
- (IBAction)getCurrentiTunesSong:(id)sender {
|
|
iTunesTrack *track = [iTunes currentTrack];
|
|
if (track == nil) {
|
|
NSBeginAlertSheet(NSLocalizedString(@"iTunes.messages.iTunesIdle.title", @""), NSLocalizedString(@"OK", @""), nil, nil, window, nil, nil, nil, nil, NSLocalizedString(@"iTunes.messages.iTunesIdle.detail", @""));
|
|
return;
|
|
}
|
|
NSString *name = [track name];
|
|
NSString *artist = [track artist];
|
|
if (name == nil) {
|
|
NSBeginAlertSheet(NSLocalizedString(@"iTunes.messages.noTrackPlaying.title", @""), NSLocalizedString(@"OK", @""), nil, nil, window, nil, nil, nil, nil, NSLocalizedString(@"iTunes.messages.noTrackPlaying.detail", @""));
|
|
return;
|
|
}
|
|
NSString *searchText = [NSString stringWithFormat:@"%@ - %@", name, artist];
|
|
[searchField setStringValue:searchText];
|
|
[searchField performClick:sender];
|
|
}
|
|
|
|
- (IBAction)startNewSearch:(id)sender {
|
|
[self resetLoadedResults:sender];
|
|
if ([[searchField stringValue] length] > 0) {
|
|
[currentHoster startNewSearchForQuery:[searchField stringValue]];
|
|
[self loadNextResults:sender];
|
|
}
|
|
}
|
|
|
|
- (IBAction)loadNextResults:(id)sender {
|
|
NSArray *nextResults = [currentHoster nextResults];
|
|
if (nextResults == nil) {
|
|
NSRunCriticalAlertPanel(NSLocalizedString(@"Hoster.messages.networkError.title", @""), NSLocalizedString(@"Hoster.messages.networkError.detail", @""), NSLocalizedString(@"OK", @""), nil, nil);
|
|
return;
|
|
}
|
|
if ([nextResults count] == 0) {
|
|
NSRunAlertPanel(NSLocalizedString(@"Hoster.messages.noResults.title", @""), NSLocalizedString(@"Hoster.messages.noResults.detail", @""), NSLocalizedString(@"OK", @""), nil, nil);
|
|
return;
|
|
}
|
|
[data addObjectsFromArray:nextResults];
|
|
[resultsOutline reloadData];
|
|
[loadMoreResultsButton setEnabled:[currentHoster hasMoreResults]];
|
|
}
|
|
|
|
-(IBAction)resetLoadedResults:(id)sender {
|
|
[currentHoster resetLoadedResults];
|
|
[data removeAllObjects];
|
|
[resultsOutline reloadData];
|
|
[loadMoreResultsButton setEnabled:[currentHoster hasMoreResults]];
|
|
[self lyricsSelectionChanged:resultsOutline];
|
|
}
|
|
|
|
- (IBAction)lyricsSelectionChanged:(NSOutlineView *)sender {
|
|
int index = [sender selectedRow];
|
|
if (index < 0) {
|
|
lyricsSelected = NO;
|
|
currentLyrics = nil;
|
|
NSString *noSelectionText = NSLocalizedString(@"iLyrics.text.noSelection", @"");
|
|
[songLabel setStringValue:noSelectionText];
|
|
[artistLabel setStringValue:noSelectionText];
|
|
[lyricsArea setString:noSelectionText];
|
|
[lyricsArea setEditable:NO];
|
|
} else {
|
|
if (selectedRow != index) {
|
|
lyricsSelected = YES;
|
|
SearchResult *result = [data objectAtIndex:index];
|
|
Lyrics *lyrics = [currentHoster lyricsBySearchResult:result];
|
|
currentLyrics = lyrics;
|
|
if (lyrics == nil) {
|
|
NSRunCriticalAlertPanel(NSLocalizedString(@"Hoster.messages.networkError.title", @""), NSLocalizedString(@"Hoster.messages.networkError.detail", @""), NSLocalizedString(@"OK", @""), nil, nil);
|
|
NSString *noNetwork = NSLocalizedString(@"Hoster.text.noNetwork", @"");
|
|
[songLabel setStringValue:noNetwork];
|
|
[artistLabel setStringValue:noNetwork];
|
|
[lyricsArea setString:noNetwork];
|
|
[lyricsArea setEditable:NO];
|
|
}
|
|
[songLabel setStringValue:[lyrics name]];
|
|
[artistLabel setStringValue:[lyrics artist]];
|
|
[lyricsArea setString:[lyrics lyrics]];
|
|
[lyricsArea setEditable:YES];
|
|
}
|
|
}
|
|
selectedRow = index;
|
|
[window update];
|
|
}
|
|
|
|
-(void) shouldShowPreviewForCellRect: (NSRect) rect searchResult: (SearchResult *) result {
|
|
if ([showPreviewCheckBox state] == NSOnState) {
|
|
NSString *lyrics = [result preview];
|
|
if (lyrics) {
|
|
rect.size.width = [resultsOutline frame].size.width;
|
|
[previewTextArea setString:lyrics];
|
|
[previewPopover showRelativeToRect:rect ofView:resultsOutline preferredEdge:NSMaxXEdge];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (IBAction)sendLyricsToiTunes:(id)sender {
|
|
iTunesTrack *track = [iTunes currentTrack];
|
|
NSString *name = [track name];
|
|
if (name == nil) {
|
|
NSBeginAlertSheet(NSLocalizedString(@"iTunes.messages.noTrackPlaying.title", @""), NSLocalizedString(@"OK", @""), nil, nil, window, nil, nil, nil, nil, NSLocalizedString(@"iTunes.messages.noTrackPlaying.detail", @""));
|
|
return;
|
|
}
|
|
NSString *oldLyrics = [track lyrics];
|
|
if (oldLyrics != nil && [oldLyrics length] > 0) {
|
|
NSBeginAlertSheet(NSLocalizedString(@"iTunes.messages.replaceLyrics.title", @""), NSLocalizedString(@"Yes", @""), NSLocalizedString(@"No", @""), nil, window, self, @selector(replaceLyricsSheetDidEnd:returnCode:contextInfo:), nil, nil, NSLocalizedString(@"iTunes.messages.replaceLyrics.detail", @""));
|
|
} else {
|
|
[self replaceLyricsSheetDidEnd:nil returnCode:NSAlertDefaultReturn contextInfo:nil];
|
|
}
|
|
}
|
|
|
|
- (void)replaceLyricsSheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
|
|
if (returnCode == NSAlertDefaultReturn) {
|
|
iTunesTrack *track = [iTunes currentTrack];
|
|
[track setLyrics:[lyricsArea string]];
|
|
[GrowlApplicationBridge notifyWithTitle:NSLocalizedString(@"Growl.messages.lyricsSent.title", @"") description:[NSString stringWithFormat:NSLocalizedString(@"Growl.messages.lyricsSent.detail", @""), [track name]] notificationName:@"Lyrics sent to iTunes" iconData:nil priority:0 isSticky:NO clickContext:nil];
|
|
}
|
|
}
|
|
|
|
- (IBAction)downloadLyrics:(id)sender {
|
|
NSSavePanel *savePanel = [NSSavePanel savePanel];
|
|
[savePanel setAllowedFileTypes:[NSArray arrayWithObject:@"txt"]];
|
|
[savePanel setAllowsOtherFileTypes:YES];
|
|
[savePanel setCanSelectHiddenExtension:YES];
|
|
[savePanel setExtensionHidden:YES];
|
|
[savePanel setNameFieldStringValue:[currentLyrics name]];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(savePanelDidClose:) name:NSWindowDidEndSheetNotification object:window];
|
|
void (^handler) (NSInteger) = ^(NSInteger result) {
|
|
selectedSavePanelButton = result;
|
|
saveFile = [savePanel URL];
|
|
};
|
|
[savePanel beginSheetModalForWindow:window completionHandler:handler];
|
|
}
|
|
|
|
-(void) savePanelDidClose: (NSNotification *) notification{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidEndSheetNotification object:window];
|
|
if (selectedSavePanelButton == NSOKButton) {
|
|
BOOL success = [[[lyricsArea string] dataUsingEncoding:NSUTF8StringEncoding] writeToURL:saveFile atomically:NO];
|
|
if (!success) {
|
|
NSBeginAlertSheet(NSLocalizedString(@"messages.error.saveLyrics.title", @""), NSLocalizedString(@"OK", @""), nil, nil, window, nil, nil, nil, nil, NSLocalizedString(@"messages.error.saveLyrics.detail", @""));
|
|
} else {
|
|
[GrowlApplicationBridge notifyWithTitle:NSLocalizedString(@"Growl.messages.lyricsSaved.title", @"") description:[NSString stringWithFormat:NSLocalizedString(@"Growl.messages.lyricsSaved.detail", @""), [saveFile path]] notificationName:@"Lyrics saved to File" iconData:nil priority:0 isSticky:NO clickContext:nil];
|
|
}
|
|
}
|
|
}
|
|
|
|
-(Lyrics *)currentLyrics {
|
|
return currentLyrics;
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Show the window
|
|
|
|
- (IBAction)showiLyricsWindow:(id)sender {
|
|
[window makeKeyAndOrderFront:sender];
|
|
}
|
|
|
|
#pragma mark window delegate
|
|
|
|
-(BOOL)validateMenuItem:(NSMenuItem *)menuItem {
|
|
return [self validateUserInterfaceItem:menuItem];
|
|
}
|
|
|
|
-(BOOL)validateToolbarItem:(NSToolbarItem *)theItem {
|
|
return [self validateUserInterfaceItem:theItem];
|
|
}
|
|
|
|
-(BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
|
|
SEL action = [item action];
|
|
if (action == @selector(downloadLyrics:)) {
|
|
[downloadLyricsButton setEnabled:lyricsSelected];
|
|
return lyricsSelected;
|
|
}
|
|
if (action == @selector(sendLyricsToiTunes:)) {
|
|
BOOL enabled = lyricsSelected && [iTunes isRunning];
|
|
[sendToiTunesButton setEnabled:enabled];
|
|
return enabled;
|
|
}
|
|
if (action == @selector(getCurrentiTunesSong:)) {
|
|
return [iTunes isRunning];
|
|
}
|
|
if (action == @selector(showPreview:)) {
|
|
return [resultsOutline clickedRow] >= 0;
|
|
}
|
|
return [self respondsToSelector:[item action]];
|
|
}
|
|
|
|
-(void)windowDidBecomeMain:(NSNotification *)notification {
|
|
[iLyricsMenuItem setOffStateImage:nil];
|
|
[iLyricsMenuItem setState:NSOnState];
|
|
}
|
|
|
|
-(void)windowDidResignMain:(NSNotification *)notification {
|
|
[iLyricsMenuItem setOffStateImage:nil];
|
|
[iLyricsMenuItem setState:NSOffState];
|
|
}
|
|
|
|
-(void)windowDidMiniaturize:(NSNotification *)notification {
|
|
NSString *imgPath = [[NSBundle mainBundle] pathForImageResource:@"Diamond"];
|
|
NSImage *miniaturizedImage = [[NSImage alloc] initWithContentsOfFile:imgPath];
|
|
[iLyricsMenuItem setOffStateImage:miniaturizedImage];
|
|
[iLyricsMenuItem setState:NSOffState];
|
|
}
|
|
|
|
-(void)saveToDefalts:(NSUserDefaults *)defaults {
|
|
[defaults setBool:[showPreviewCheckBox state] == NSOnState forKey:@"Show preview"];
|
|
}
|
|
|
|
-(void)loadFromDefaults:(NSUserDefaults *)defaults {
|
|
[showPreviewCheckBox setState:[defaults boolForKey:@"Show preview"]?NSOnState:NSOffState];
|
|
}
|
|
@end
|