cog/Playlist/PlaylistController.m

553 lines
12 KiB
Matlab
Raw Normal View History

2005-06-02 18:16:43 +00:00
//
// PlaylistController.m
// Cog
2005-06-02 18:16:43 +00:00
//
// Created by Vincent Spader on 3/18/05.
// Copyright 2005 Vincent Spader All rights reserved.
2005-06-02 18:16:43 +00:00
//
#import "PlaylistLoader.h"
2005-06-02 18:16:43 +00:00
#import "PlaylistController.h"
#import "PlaylistEntry.h"
2006-01-20 15:22:03 +00:00
#import "Shuffle.h"
2005-06-02 18:16:43 +00:00
#import "CogAudio/AudioPlayer.h"
2006-05-07 13:19:23 +00:00
2005-06-02 18:16:43 +00:00
@implementation PlaylistController
2006-01-20 15:22:03 +00:00
#define SHUFFLE_HISTORY_SIZE 100
#define UNDO_STACK_LIMIT 100
2005-06-02 18:16:43 +00:00
- (id)initWithCoder:(NSCoder *)decoder
{
self = [super initWithCoder:decoder];
if (self)
{
shuffleList = [[NSMutableArray alloc] init];
undoManager = [[NSUndoManager alloc] init];
[undoManager setLevelsOfUndo:UNDO_STACK_LIMIT];
2005-06-02 18:16:43 +00:00
}
return self;
}
2006-04-29 00:03:28 +00:00
- (void)tableView:(NSTableView *)tableView
didClickTableColumn:(NSTableColumn *)tableColumn
{
2006-04-30 13:01:33 +00:00
if (shuffle == YES)
[self resetShuffleList];
2006-04-29 00:03:28 +00:00
[self updateIndexesFromRow:0];
}
-(void)moveObjectsFromArrangedObjectIndexes:(NSArray *) sources toIndexes:(NSArray *)destinations
{
NSLog(@"MOVING!: %@ %@", sources, destinations);
NSMutableArray *undoSources = [NSMutableArray array];
NSMutableArray *undoDests = [NSMutableArray array];
for (id s in sources)
{
[undoDests insertObject:s atIndex:0];
}
for (id d in destinations)
{
[undoSources insertObject:d atIndex:0];
}
[[[self undoManager] prepareWithInvocationTarget:self] moveObjectsFromArrangedObjectIndexes:undoSources toIndexes:undoDests];
[super moveObjectsFromArrangedObjectIndexes:sources toIndexes:destinations];
NSUInteger firstIndex = (NSUInteger)-1;
NSUInteger i = 0;
for (i = 0; i < [sources count]; i++) {
NSUInteger source = [[sources objectAtIndex:i] unsignedIntegerValue];
NSUInteger dest = [[destinations objectAtIndex:i] unsignedIntegerValue];
if (source < firstIndex)
firstIndex = source;
if (dest < firstIndex)
firstIndex = dest;
}
[self updateIndexesFromRow:firstIndex];
}
2005-06-02 18:16:43 +00:00
- (BOOL)tableView:(NSTableView*)tv
acceptDrop:(id <NSDraggingInfo>)info
row:(int)row
dropOperation:(NSTableViewDropOperation)op
{
[super tableView:tv acceptDrop:info row:row dropOperation:op];
2005-06-02 18:16:43 +00:00
if ([info draggingSource] == tableView)
{
//DNDArrayController handles moving...
2005-06-02 18:16:43 +00:00
return YES;
}
if (row < 0)
row = 0;
// Determine the type of object that was dropped
NSArray *supportedtypes = [NSArray arrayWithObjects:CogUrlsPbboardType, NSFilenamesPboardType, iTunesDropType, nil];
NSPasteboard *pboard = [info draggingPasteboard];
NSString *bestType = [pboard availableTypeFromArray:supportedtypes];
// Get files from an file drawer drop
if ([bestType isEqualToString:CogUrlsPbboardType]) {
NSArray *urls = [NSUnarchiver unarchiveObjectWithData:[[info draggingPasteboard] dataForType:CogUrlsPbboardType]];
NSLog(@"URLS: %@", urls);
[playlistLoader insertURLs: urls atIndex:row sort:YES];
}
// Get files from a normal file drop (such as from Finder)
if ([bestType isEqualToString:NSFilenamesPboardType]) {
NSMutableArray *urls = [[NSMutableArray alloc] init];
NSEnumerator *e = [[[info draggingPasteboard] propertyListForType:NSFilenamesPboardType] objectEnumerator];
NSString *file;
while (file = [e nextObject])
{
[urls addObject:[NSURL fileURLWithPath:file]];
}
[playlistLoader insertURLs:urls atIndex:row sort:YES];
[urls release];
}
// Get files from an iTunes drop
if ([bestType isEqualToString:iTunesDropType]) {
NSDictionary *iTunesDict = [pboard propertyListForType:iTunesDropType];
NSDictionary *tracks = [iTunesDict valueForKey:@"Tracks"];
2005-06-02 18:16:43 +00:00
// Convert the iTunes URLs to URLs....MWAHAHAH!
NSMutableArray *urls = [[NSMutableArray alloc] init];
NSEnumerator *e = [[tracks allValues] objectEnumerator];
NSDictionary *trackInfo;
while (trackInfo = [e nextObject]) {
[urls addObject:[NSURL URLWithString:[trackInfo valueForKey:@"Location"]]];
}
[playlistLoader insertURLs:urls atIndex:row sort:YES];
[urls release];
}
2005-06-29 22:41:49 +00:00
[self updateIndexesFromRow:row];
2006-04-13 18:40:23 +00:00
[self updateTotalTime];
2005-06-02 18:16:43 +00:00
if (shuffle == YES)
2006-01-20 15:22:03 +00:00
[self resetShuffleList];
2005-06-02 18:16:43 +00:00
return YES;
}
2006-04-13 18:40:23 +00:00
- (void)updateTotalTime
{
double tt=0;
2006-04-29 00:03:28 +00:00
NSEnumerator *enumerator = [[self arrangedObjects] objectEnumerator];
2006-04-13 18:40:23 +00:00
PlaylistEntry* pe;
while (pe = [enumerator nextObject]) {
tt += [[pe length] doubleValue];
2006-04-13 18:40:23 +00:00
}
int sec = (int)(tt);
2006-04-13 18:40:23 +00:00
[self setTotalTimeDisplay:[NSString stringWithFormat:@"%i:%02i",sec/60, sec%60]];
}
- (void)setTotalTimeDisplay:(NSString *)ttd
{
[ttd retain];
[totalTimeDisplay release];
totalTimeDisplay = ttd;
}
- (NSString *)totalTimeDisplay;
{
return totalTimeDisplay;
}
2005-06-02 18:16:43 +00:00
- (void)updateIndexesFromRow:(int) row
{
int j;
2006-04-29 00:03:28 +00:00
for (j = row; j < [[self arrangedObjects] count]; j++)
2005-06-02 18:16:43 +00:00
{
PlaylistEntry *p;
2006-04-29 00:03:28 +00:00
p = [[self arrangedObjects] objectAtIndex:j];
2005-06-02 18:16:43 +00:00
[p setIndex:[NSNumber numberWithInt:j]];
2005-06-02 18:16:43 +00:00
}
}
- (NSUndoManager *)undoManager
{
return undoManager;
}
- (void)insertObjects:(NSArray *)objects atArrangedObjectIndexes:(NSIndexSet *)indexes
{
[[[self undoManager] prepareWithInvocationTarget:self] removeObjectsAtArrangedObjectIndexes:indexes];
[super insertObjects:objects atArrangedObjectIndexes:indexes];
[self updateIndexesFromRow:[indexes firstIndex]];
[self updateTotalTime];
if (shuffle == YES)
[self resetShuffleList];
}
2005-06-02 18:16:43 +00:00
- (void)removeObjectsAtArrangedObjectIndexes:(NSIndexSet *)indexes
{
NSLog(@"Removing indexes: %@", indexes);
NSLog(@"Current index: %i", [[currentEntry index] intValue]);
if ([[currentEntry index] intValue] >= 0 && [indexes containsIndex:[[currentEntry index] intValue]])
2005-06-02 18:16:43 +00:00
{
[currentEntry setIndex:[NSNumber numberWithInt:-[[currentEntry index] intValue] - 1]];
NSLog(@"Current removed: %i", [[currentEntry index] intValue]);
}
if ([[currentEntry index] intValue] < 0) //Need to update the negative index
{
int i = -[[currentEntry index] intValue] - 1;
NSLog(@"I is %i", i);
int j;
for (j = i - 1; j >= 0; j--)
{
if ([indexes containsIndex:j]) {
NSLog(@"Removing 1");
i--;
}
}
[currentEntry setIndex: [NSNumber numberWithInt:-i - 1]];
NSLog(@"UPDATING INDEX: %@", [currentEntry index]);
2005-06-02 18:16:43 +00:00
}
[[[self undoManager] prepareWithInvocationTarget:self] insertObjects:[[self arrangedObjects] objectsAtIndexes:indexes] atArrangedObjectIndexes:indexes];
2005-06-02 18:16:43 +00:00
[super removeObjectsAtArrangedObjectIndexes:indexes];
2005-06-02 18:16:43 +00:00
[self updateIndexesFromRow:[indexes firstIndex]];
2006-04-13 18:40:23 +00:00
[self updateTotalTime];
2005-06-02 18:16:43 +00:00
if (shuffle == YES)
2006-01-20 15:22:03 +00:00
[self resetShuffleList];
2005-06-02 18:16:43 +00:00
}
2006-05-12 19:23:17 +00:00
- (void)setSortDescriptors:(NSArray *)sortDescriptors
{
//Cheap hack so the index column isn't sorted
2007-03-14 03:16:37 +00:00
if (([sortDescriptors count] != 0) && [[[sortDescriptors objectAtIndex:0] key] caseInsensitiveCompare:@"index"] == NSOrderedSame)
2006-05-12 19:23:17 +00:00
{
//Remove the sort descriptors
[super setSortDescriptors:nil];
[self rearrangeObjects];
2006-05-29 23:03:58 +00:00
return;
2006-05-12 19:23:17 +00:00
}
2006-05-29 23:03:58 +00:00
[super setSortDescriptors:sortDescriptors];
2006-05-12 19:23:17 +00:00
}
- (IBAction)sortByPath
2006-04-30 13:01:33 +00:00
{
NSSortDescriptor *s = [[NSSortDescriptor alloc] initWithKey:@"url" ascending:YES selector:@selector(compare:)];
[self setSortDescriptors:[NSArray arrayWithObject:s]];
[self rearrangeObjects];
2006-04-30 13:01:33 +00:00
[s release];
if (shuffle == YES)
[self resetShuffleList];
[self updateIndexesFromRow:0];
}
- (IBAction)randomizeList
2006-04-30 13:01:33 +00:00
{
[self setSortDescriptors:nil];
2006-05-12 19:32:01 +00:00
2006-04-30 13:01:33 +00:00
[self setContent:[Shuffle shuffleList:[self content]]];
if (shuffle == YES)
[self resetShuffleList];
[self updateIndexesFromRow:0];
}
2005-06-02 18:16:43 +00:00
- (IBAction)takeShuffleFromObject:(id)sender
{
if( [sender respondsToSelector: @selector(boolValue)] )
[self setShuffle: [sender boolValue]];
else
[self setShuffle: [sender state]];
}
- (IBAction)takeRepeatFromObject:(id)sender
{
if( [sender respondsToSelector: @selector(boolValue)] )
[self setRepeat: [sender boolValue]];
else
[self setRepeat: [sender state]];
}
2006-04-13 02:51:22 +00:00
- (PlaylistEntry *)entryAtIndex:(int)i
{
2006-04-15 13:51:40 +00:00
if (i < 0)
2006-04-13 02:51:22 +00:00
{
2006-04-15 13:51:40 +00:00
if (repeat == YES)
i += [[self arrangedObjects] count];
else
return nil;
}
else if (i >= [[self arrangedObjects] count])
{
if (repeat == YES)
i -= [[self arrangedObjects] count];
else
return nil;
}
return [[self arrangedObjects] objectAtIndex:i];
}
2006-04-15 13:51:40 +00:00
- (PlaylistEntry *)shuffledEntryAtIndex:(int)i
{
while (i < 0)
{
if (repeat == YES)
{
2006-04-15 13:51:40 +00:00
[self addShuffledListToFront];
//change i appropriately
i += [[self arrangedObjects] count];
}
2006-04-15 13:51:40 +00:00
else
{
2006-04-15 13:51:40 +00:00
return nil;
}
2006-04-13 02:51:22 +00:00
}
2006-04-15 13:51:40 +00:00
while (i >= [shuffleList count])
2006-04-13 02:51:22 +00:00
{
2006-04-15 13:51:40 +00:00
if (repeat == YES)
{
2006-04-15 13:51:40 +00:00
[self addShuffledListToBack];
}
2006-04-15 13:51:40 +00:00
else
{
2006-04-15 13:51:40 +00:00
return nil;
}
2006-04-15 13:51:40 +00:00
}
return [shuffleList objectAtIndex:i];
2006-04-13 02:51:22 +00:00
}
2006-04-15 13:51:40 +00:00
- (PlaylistEntry *)getNextEntry:(PlaylistEntry *)pe
{
if (shuffle == YES)
{
return [self shuffledEntryAtIndex:([[pe shuffleIndex] intValue] + 1)];
2006-04-15 13:51:40 +00:00
}
else
{
int i;
if ([[pe index] intValue] < 0) //Was a current entry, now removed.
{
i = -[[pe index] intValue] - 1;
}
else
{
i = [[pe index] intValue] + 1;
}
return [self entryAtIndex:i];
2006-04-15 13:51:40 +00:00
}
}
- (PlaylistEntry *)getPrevEntry:(PlaylistEntry *)pe
{
if (shuffle == YES)
{
return [self shuffledEntryAtIndex:([[pe shuffleIndex] intValue] - 1)];
2006-04-15 13:51:40 +00:00
}
else
{
int i;
if ([[pe index] intValue] < 0) //Was a current entry, now removed.
2006-04-15 14:17:46 +00:00
{
i = -[[pe index] intValue] - 2;
2006-04-15 14:17:46 +00:00
}
else
{
i = [[pe index] intValue] - 1;
2006-04-15 14:17:46 +00:00
}
return [self entryAtIndex:i];
2006-04-15 13:51:40 +00:00
}
}
2006-01-29 14:57:48 +00:00
- (BOOL)next
2005-06-02 18:16:43 +00:00
{
PlaylistEntry *pe;
2006-04-15 13:51:40 +00:00
pe = [self getNextEntry:[self currentEntry]];
2005-06-02 18:16:43 +00:00
if (pe == nil)
2006-01-29 14:57:48 +00:00
return NO;
2005-06-02 18:16:43 +00:00
2006-01-20 15:22:03 +00:00
[self setCurrentEntry:pe];
2006-01-29 14:57:48 +00:00
return YES;
2005-06-02 18:16:43 +00:00
}
2006-01-29 14:57:48 +00:00
- (BOOL)prev
2005-06-02 18:16:43 +00:00
{
PlaylistEntry *pe;
2006-04-15 13:51:40 +00:00
pe = [self getPrevEntry:[self currentEntry]];
2005-06-02 18:16:43 +00:00
if (pe == nil)
2006-01-29 14:57:48 +00:00
return NO;
2005-06-02 18:16:43 +00:00
2006-01-20 15:22:03 +00:00
[self setCurrentEntry:pe];
2006-01-29 14:57:48 +00:00
return YES;
2005-06-02 18:16:43 +00:00
}
2006-04-14 20:34:14 +00:00
2006-04-15 13:51:40 +00:00
//Need to do...when first generated, need to have current entry at the beginning of the list.
- (void)addShuffledListToFront
2005-06-02 18:16:43 +00:00
{
2006-01-20 15:22:03 +00:00
NSArray *newList = [Shuffle shuffleList:[self arrangedObjects]];
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [newList count])];
2005-06-02 18:16:43 +00:00
2006-04-05 17:25:51 +00:00
[shuffleList insertObjects:newList atIndexes:indexSet];
2006-04-15 13:51:40 +00:00
int i;
for (i = 0; i < [shuffleList count]; i++)
{
[[shuffleList objectAtIndex:i] setShuffleIndex:[NSNumber numberWithInt:i]];
2006-04-15 13:51:40 +00:00
}
2005-06-02 18:16:43 +00:00
}
2006-04-15 13:51:40 +00:00
- (void)addShuffledListToBack
2005-06-02 18:16:43 +00:00
{
2006-01-20 15:22:03 +00:00
NSArray *newList = [Shuffle shuffleList:[self arrangedObjects]];
2006-04-05 17:25:51 +00:00
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange([shuffleList count], [newList count])];
2006-04-15 13:51:40 +00:00
2006-04-05 17:25:51 +00:00
[shuffleList insertObjects:newList atIndexes:indexSet];
2006-04-15 13:51:40 +00:00
int i;
for (i = ([shuffleList count] - [newList count]); i < [shuffleList count]; i++)
{
[[shuffleList objectAtIndex:i] setShuffleIndex:[NSNumber numberWithInt:i]];
2006-04-15 13:51:40 +00:00
}
2005-06-02 18:16:43 +00:00
}
2006-01-20 15:22:03 +00:00
- (void)resetShuffleList
2005-06-02 18:16:43 +00:00
{
2006-01-20 15:22:03 +00:00
[shuffleList removeAllObjects];
2006-04-15 13:51:40 +00:00
2006-04-05 17:25:51 +00:00
[self addShuffledListToFront];
2006-04-15 13:51:40 +00:00
if (currentEntry && [[currentEntry index] intValue] != -1)
2006-04-15 13:51:40 +00:00
{
2006-04-15 14:17:46 +00:00
[shuffleList insertObject:currentEntry atIndex:0];
[currentEntry setShuffleIndex:0];
//Need to rejigger so the current entry is at the start now...
int i;
BOOL found = NO;
for (i = 1; i < [shuffleList count]; i++)
2006-04-15 13:51:40 +00:00
{
if (found == NO && [[shuffleList objectAtIndex:i] url] == [currentEntry url])
2006-04-15 14:17:46 +00:00
{
found = YES;
[shuffleList removeObjectAtIndex:i];
}
[[shuffleList objectAtIndex:i] setShuffleIndex:[NSNumber numberWithInt:i]];
2006-04-15 14:17:46 +00:00
}
2006-04-15 13:51:40 +00:00
}
2005-06-02 18:16:43 +00:00
}
- (id)currentEntry
{
return currentEntry;
}
- (void)setCurrentEntry:(PlaylistEntry *)pe
2005-06-02 18:16:43 +00:00
{
[currentEntry setCurrent:[NSNumber numberWithBool:NO]];
2005-06-02 18:16:43 +00:00
[pe setCurrent:[NSNumber numberWithBool:YES]];
[tableView scrollRowToVisible:[[pe index] intValue]];
2005-06-02 18:16:43 +00:00
[pe retain];
[currentEntry release];
currentEntry = pe;
}
- (void)setShuffle:(BOOL)s
{
shuffle = s;
if (shuffle == YES)
2006-01-20 15:22:03 +00:00
[self resetShuffleList];
2005-06-02 18:16:43 +00:00
}
- (BOOL)shuffle
{
return shuffle;
}
- (void)setRepeat:(BOOL)r
{
repeat = r;
}
- (BOOL)repeat
{
return repeat;
}
- (IBAction)clear:(id)sender
{
2007-06-05 00:33:30 +00:00
[currentEntry setIndex:[NSNumber numberWithInt:-1]];
[self removeObjects:[self content]];
2007-06-05 00:33:30 +00:00
[self updateTotalTime];
if (shuffle == YES)
[self resetShuffleList];
}
- (IBAction)clearFilterPredicate:(id)sender
{
[self setFilterPredicate:nil];
}
2006-04-30 15:31:57 +00:00
- (void)setFilterPredicate:(NSPredicate *)filterPredicate
{
[super setFilterPredicate:filterPredicate];
2006-04-30 16:05:39 +00:00
[self updateIndexesFromRow:0];
2006-04-30 15:31:57 +00:00
}
- (IBAction)showEntryInFinder:(id)sender
{
NSWorkspace* ws = [NSWorkspace sharedWorkspace];
if ([self selectionIndex] < 0)
return;
NSURL *url = [[self entryAtIndex:[self selectionIndex]] url];
if ([url isFileURL])
[ws selectFile:[url path] inFileViewerRootedAtPath:[url path]];
}
2005-06-02 18:16:43 +00:00
@end