2005-06-02 18:16:43 +00:00
|
|
|
//
|
2008-02-10 16:16:45 +00:00
|
|
|
// PlaylistController.m
|
|
|
|
// Cog
|
2005-06-02 18:16:43 +00:00
|
|
|
//
|
2008-02-10 16:16:45 +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
|
|
|
//
|
|
|
|
|
2007-03-09 01:16:06 +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"
|
2008-02-10 16:16:45 +00:00
|
|
|
#import "UndoObject.h"
|
2005-06-02 18:16:43 +00:00
|
|
|
|
2007-02-24 20:36:27 +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
|
2008-02-10 16:16:45 +00:00
|
|
|
#define UNDO_STACK_LIMIT 25
|
2005-06-02 18:16:43 +00:00
|
|
|
|
|
|
|
- (id)initWithCoder:(NSCoder *)decoder
|
|
|
|
{
|
|
|
|
self = [super initWithCoder:decoder];
|
|
|
|
|
|
|
|
if (self)
|
|
|
|
{
|
|
|
|
shuffleList = [[NSMutableArray alloc] init];
|
2008-02-10 16:16:45 +00:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
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];
|
2008-02-10 16:16:45 +00:00
|
|
|
|
|
|
|
UndoObject *undoEntry;
|
|
|
|
NSMutableArray *undoEntries = [[NSMutableArray alloc] init];
|
|
|
|
|
2005-06-02 18:16:43 +00:00
|
|
|
if ([info draggingSource] == tableView)
|
|
|
|
{
|
2007-03-09 01:16:06 +00:00
|
|
|
//DNDArrayController handles moving...still need to update the indexes
|
|
|
|
|
2008-02-10 16:16:45 +00:00
|
|
|
NSArray *rows = [NSKeyedUnarchiver unarchiveObjectWithData:[[info draggingPasteboard] dataForType: MovedRowsType]];
|
|
|
|
NSIndexSet *indexes = [self indexSetFromRows:rows];
|
|
|
|
int firstIndex = [indexes firstIndex];
|
|
|
|
int indexesSize = [indexes count];
|
|
|
|
NSUInteger indexBuffer[indexesSize];
|
2007-03-09 01:16:06 +00:00
|
|
|
|
2008-02-10 16:16:45 +00:00
|
|
|
int i;
|
|
|
|
int adjustment;
|
|
|
|
int counter;
|
|
|
|
|
2005-06-02 18:16:43 +00:00
|
|
|
if (firstIndex > row)
|
|
|
|
i = row;
|
|
|
|
else
|
|
|
|
i = firstIndex;
|
2008-02-10 16:16:45 +00:00
|
|
|
|
|
|
|
[indexes getIndexes:indexBuffer maxCount:indexesSize inIndexRange:nil];
|
|
|
|
|
|
|
|
if (row > firstIndex)
|
|
|
|
adjustment = 1;
|
|
|
|
else
|
|
|
|
adjustment = 0;
|
|
|
|
|
|
|
|
// create an UndoObject for each entry being moved, and store it away
|
|
|
|
// in the undoEntries array
|
|
|
|
for (counter = 0; counter < indexesSize; counter++)
|
|
|
|
{
|
|
|
|
undoEntry = [[UndoObject alloc] init];
|
|
|
|
|
|
|
|
[undoEntry setOrigin: row - adjustment];
|
|
|
|
[undoEntry setMovedTo: indexBuffer[counter]];
|
|
|
|
[undoEntries addObject: undoEntry];
|
|
|
|
}
|
|
|
|
|
|
|
|
[undoManager registerUndoWithTarget:self
|
|
|
|
selector:@selector(undoMove:)
|
|
|
|
object:undoEntries];
|
|
|
|
|
|
|
|
|
2005-06-02 18:16:43 +00:00
|
|
|
|
|
|
|
[self updateIndexesFromRow:i];
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (row < 0)
|
|
|
|
row = 0;
|
2007-02-17 15:58:39 +00:00
|
|
|
|
|
|
|
// Determine the type of object that was dropped
|
2007-10-16 01:22:57 +00:00
|
|
|
NSArray *supportedtypes = [NSArray arrayWithObjects:CogUrlsPbboardType, NSFilenamesPboardType, iTunesDropType, nil];
|
2007-02-17 15:58:39 +00:00
|
|
|
NSPasteboard *pboard = [info draggingPasteboard];
|
|
|
|
NSString *bestType = [pboard availableTypeFromArray:supportedtypes];
|
|
|
|
|
2007-10-16 01:22:57 +00:00
|
|
|
// 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];
|
|
|
|
}
|
|
|
|
|
2007-02-17 15:58:39 +00:00
|
|
|
// Get files from a normal file drop (such as from Finder)
|
|
|
|
if ([bestType isEqualToString:NSFilenamesPboardType]) {
|
2007-03-09 01:16:06 +00:00
|
|
|
NSMutableArray *urls = [[NSMutableArray alloc] init];
|
|
|
|
|
|
|
|
NSEnumerator *e = [[[info draggingPasteboard] propertyListForType:NSFilenamesPboardType] objectEnumerator];
|
|
|
|
NSString *file;
|
|
|
|
while (file = [e nextObject])
|
|
|
|
{
|
|
|
|
[urls addObject:[NSURL fileURLWithPath:file]];
|
|
|
|
}
|
2007-02-17 15:58:39 +00:00
|
|
|
|
2007-03-09 01:16:06 +00:00
|
|
|
[playlistLoader insertURLs:urls atIndex:row sort:YES];
|
|
|
|
|
|
|
|
[urls release];
|
2007-02-17 15:58:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
2007-03-09 01:16:06 +00:00
|
|
|
// Convert the iTunes URLs to URLs....MWAHAHAH!
|
|
|
|
NSMutableArray *urls = [[NSMutableArray alloc] init];
|
|
|
|
|
2007-02-17 15:58:39 +00:00
|
|
|
NSEnumerator *e = [[tracks allValues] objectEnumerator];
|
|
|
|
NSDictionary *trackInfo;
|
|
|
|
while (trackInfo = [e nextObject]) {
|
2007-03-09 01:16:06 +00:00
|
|
|
[urls addObject:[NSURL URLWithString:[trackInfo valueForKey:@"Location"]]];
|
2007-02-17 15:58:39 +00:00
|
|
|
}
|
|
|
|
|
2007-03-09 01:16:06 +00:00
|
|
|
[playlistLoader insertURLs:urls atIndex:row sort:YES];
|
|
|
|
[urls release];
|
2007-02-17 15:58:39 +00:00
|
|
|
}
|
|
|
|
|
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]) {
|
2007-03-14 02:28:30 +00:00
|
|
|
tt += [[pe length] doubleValue];
|
2006-04-13 18:40:23 +00:00
|
|
|
}
|
|
|
|
|
2007-11-24 20:16:27 +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
|
|
|
|
2007-03-14 02:28:30 +00:00
|
|
|
[p setIndex:[NSNumber numberWithInt:j]];
|
2005-06-02 18:16:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-10 16:16:45 +00:00
|
|
|
-(void)undoDelete:(NSMutableArray *)undoEntries
|
|
|
|
{
|
|
|
|
NSEnumerator *enumerator = [undoEntries objectEnumerator];
|
|
|
|
UndoObject *current;
|
|
|
|
|
|
|
|
while (current = [enumerator nextObject])
|
|
|
|
{
|
|
|
|
[playlistLoader
|
|
|
|
insertURLs: [NSArray arrayWithObject:[current path]]
|
|
|
|
atIndex:[current origin]
|
|
|
|
sort:YES];
|
|
|
|
// make sure to dealloc the undo object after reinserting it
|
|
|
|
[current dealloc];
|
|
|
|
|
|
|
|
}
|
|
|
|
[self updateIndexesFromRow: 0];
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void)undoMove:(NSMutableArray *) undoEntries
|
|
|
|
{
|
|
|
|
NSArray *objects = [super arrangedObjects];
|
|
|
|
NSEnumerator *enumerator = [undoEntries objectEnumerator];
|
|
|
|
UndoObject *current;
|
|
|
|
id object;
|
|
|
|
int len = [undoEntries count];
|
|
|
|
int iterations = 0;
|
|
|
|
int playlistLocation;
|
|
|
|
|
|
|
|
// register an undo for the undo with the undoManager,
|
|
|
|
// so it knows what to do if a redo is requested
|
|
|
|
[undoManager registerUndoWithTarget:self
|
|
|
|
selector:@selector(undoMove:)
|
|
|
|
object:undoEntries];
|
|
|
|
|
|
|
|
while (current = [enumerator nextObject])
|
|
|
|
{
|
|
|
|
/* the exact opposite of an undo is required during a redo, hence
|
|
|
|
we have to check what we are dealing with and act accordingly */
|
|
|
|
|
|
|
|
// originally moved entry up the list
|
|
|
|
if (([current origin] > [current movedTo]))
|
|
|
|
{
|
|
|
|
if ([undoManager isUndoing]) // we are undoing
|
|
|
|
{
|
|
|
|
playlistLocation = ([current origin] - (len - 1)) + iterations++;
|
|
|
|
object = [objects objectAtIndex: playlistLocation];
|
|
|
|
[object retain];
|
|
|
|
[super insertObject:object atArrangedObjectIndex:[current movedTo]];
|
|
|
|
[super removeObjectAtArrangedObjectIndex:playlistLocation + 1];
|
|
|
|
}
|
|
|
|
else // we are redoing the undo
|
|
|
|
{
|
|
|
|
playlistLocation = [current movedTo] - iterations++;
|
|
|
|
object = [objects objectAtIndex: playlistLocation];
|
|
|
|
[object retain];
|
|
|
|
[super removeObjectAtArrangedObjectIndex:playlistLocation];
|
|
|
|
[super insertObject:object atArrangedObjectIndex:[current origin]];
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
// originally moved entry down the list
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ([undoManager isUndoing])
|
|
|
|
{
|
|
|
|
object = [objects objectAtIndex: [current origin]];
|
|
|
|
[object retain];
|
|
|
|
[super insertObject:object atArrangedObjectIndex:[current movedTo] + len--];
|
|
|
|
[super removeObjectAtArrangedObjectIndex:[current origin]];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
object = [objects objectAtIndex: [current movedTo]];
|
|
|
|
[object retain];
|
|
|
|
[super removeObjectAtArrangedObjectIndex:[current movedTo]];
|
|
|
|
[super insertObject:object atArrangedObjectIndex:[current origin] + iterations++];
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
[object release];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
[self updateIndexesFromRow: 0];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSUndoManager *)undoManager
|
|
|
|
{
|
|
|
|
return undoManager;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)doUndo:(id)sender
|
|
|
|
{
|
|
|
|
[undoManager undo];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)doRedo:(id)sender
|
|
|
|
{
|
|
|
|
[undoManager redo];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-06-02 18:16:43 +00:00
|
|
|
- (void)removeObjectsAtArrangedObjectIndexes:(NSIndexSet *)indexes
|
|
|
|
{
|
2008-02-10 16:16:45 +00:00
|
|
|
int i; // loop counter
|
|
|
|
int indexesSize = [indexes count];
|
|
|
|
NSUInteger indexBuffer[indexesSize];
|
|
|
|
UndoObject *undoEntry;
|
|
|
|
PlaylistEntry *pre;
|
|
|
|
NSMutableArray *undoEntries = [[NSMutableArray alloc] init];
|
|
|
|
|
2007-10-22 00:04:34 +00:00
|
|
|
NSLog(@"Removing indexes: %@", indexes);
|
|
|
|
NSLog(@"Current index: %i", [[currentEntry index] intValue]);
|
2008-02-10 16:16:45 +00:00
|
|
|
|
|
|
|
// get indexes from IndexSet indexes and put them in indexBuffer
|
|
|
|
[indexes getIndexes:indexBuffer maxCount:indexesSize inIndexRange:nil];
|
|
|
|
|
|
|
|
// loop through the list of indexes, saving each entry away
|
|
|
|
// in an undo object
|
|
|
|
for (i = 0; i < indexesSize; i++)
|
|
|
|
{
|
|
|
|
// alllocate a new object for each undo entry
|
|
|
|
undoEntry = [[UndoObject alloc] init];
|
|
|
|
|
|
|
|
pre = [self entryAtIndex:indexBuffer[i]];
|
|
|
|
|
|
|
|
[undoEntry setOrigin:indexBuffer[i] andPath: [pre url]];
|
|
|
|
[undoEntries addObject:undoEntry];
|
|
|
|
}
|
|
|
|
|
|
|
|
// register the removals with the undoManager
|
|
|
|
[undoManager registerUndoWithTarget:self
|
|
|
|
selector:@selector(undoDelete:)
|
|
|
|
object:undoEntries];
|
|
|
|
|
2005-06-02 18:16:43 +00:00
|
|
|
|
2007-10-22 00:04:34 +00:00
|
|
|
if ([[currentEntry index] intValue] >= 0 && [indexes containsIndex:[[currentEntry index] intValue]])
|
2005-06-02 18:16:43 +00:00
|
|
|
{
|
2007-10-22 00:04:34 +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
|
|
|
}
|
|
|
|
|
|
|
|
[super removeObjectsAtArrangedObjectIndexes:indexes];
|
|
|
|
[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
|
|
|
{
|
2007-02-18 22:27:55 +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
|
|
|
}
|
|
|
|
|
2007-03-09 01:16:06 +00:00
|
|
|
- (IBAction)sortByPath
|
2006-04-30 13:01:33 +00:00
|
|
|
{
|
2007-03-02 01:36:52 +00:00
|
|
|
NSSortDescriptor *s = [[NSSortDescriptor alloc] initWithKey:@"url" ascending:YES selector:@selector(compare:)];
|
2007-02-18 22:27:55 +00:00
|
|
|
|
|
|
|
[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];
|
|
|
|
}
|
|
|
|
|
2007-03-09 01:16:06 +00:00
|
|
|
- (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];
|
|
|
|
}
|
2007-03-09 01:16:06 +00:00
|
|
|
|
2006-04-15 13:51:40 +00:00
|
|
|
- (PlaylistEntry *)shuffledEntryAtIndex:(int)i
|
|
|
|
{
|
|
|
|
while (i < 0)
|
|
|
|
{
|
|
|
|
if (repeat == YES)
|
2006-04-14 17:28:20 +00:00
|
|
|
{
|
2006-04-15 13:51:40 +00:00
|
|
|
[self addShuffledListToFront];
|
|
|
|
//change i appropriately
|
|
|
|
i += [[self arrangedObjects] count];
|
2006-04-14 17:28:20 +00:00
|
|
|
}
|
2006-04-15 13:51:40 +00:00
|
|
|
else
|
2006-04-14 17:28:20 +00:00
|
|
|
{
|
2006-04-15 13:51:40 +00:00
|
|
|
return nil;
|
2006-04-14 17:28:20 +00:00
|
|
|
}
|
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-14 17:28:20 +00:00
|
|
|
{
|
2006-04-15 13:51:40 +00:00
|
|
|
[self addShuffledListToBack];
|
2006-04-14 17:28:20 +00:00
|
|
|
}
|
2006-04-15 13:51:40 +00:00
|
|
|
else
|
2006-04-14 17:28:20 +00:00
|
|
|
{
|
2006-04-15 13:51:40 +00:00
|
|
|
return nil;
|
2006-04-14 17:28:20 +00:00
|
|
|
}
|
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)
|
|
|
|
{
|
2007-03-14 02:28:30 +00:00
|
|
|
return [self shuffledEntryAtIndex:([[pe shuffleIndex] intValue] + 1)];
|
2006-04-15 13:51:40 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-10-22 00:04:34 +00:00
|
|
|
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)
|
|
|
|
{
|
2007-03-14 02:28:30 +00:00
|
|
|
return [self shuffledEntryAtIndex:([[pe shuffleIndex] intValue] - 1)];
|
2006-04-15 13:51:40 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-10-22 00:04:34 +00:00
|
|
|
int i;
|
|
|
|
if ([[pe index] intValue] < 0) //Was a current entry, now removed.
|
2006-04-15 14:17:46 +00:00
|
|
|
{
|
2007-10-22 00:04:34 +00:00
|
|
|
i = -[[pe index] intValue] - 2;
|
2006-04-15 14:17:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-10-22 00:04:34 +00:00
|
|
|
i = [[pe index] intValue] - 1;
|
2006-04-15 14:17:46 +00:00
|
|
|
}
|
2007-10-22 00:04:34 +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++)
|
|
|
|
{
|
2007-03-14 02:28:30 +00:00
|
|
|
[[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++)
|
|
|
|
{
|
2007-03-14 02:28:30 +00:00
|
|
|
[[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
|
|
|
|
2007-03-14 02:28:30 +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
|
|
|
{
|
2007-03-02 01:36:52 +00:00
|
|
|
if (found == NO && [[shuffleList objectAtIndex:i] url] == [currentEntry url])
|
2006-04-15 14:17:46 +00:00
|
|
|
{
|
|
|
|
found = YES;
|
|
|
|
[shuffleList removeObjectAtIndex:i];
|
|
|
|
}
|
|
|
|
|
2007-03-14 02:28:30 +00:00
|
|
|
[[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;
|
|
|
|
}
|
|
|
|
|
2007-02-18 21:41:47 +00:00
|
|
|
- (void)setCurrentEntry:(PlaylistEntry *)pe
|
2005-06-02 18:16:43 +00:00
|
|
|
{
|
2007-03-18 17:44:59 +00:00
|
|
|
[currentEntry setCurrent:[NSNumber numberWithBool:NO]];
|
2005-06-02 18:16:43 +00:00
|
|
|
|
2007-03-18 17:44:59 +00:00
|
|
|
[pe setCurrent:[NSNumber numberWithBool:YES]];
|
2007-03-14 02:28:30 +00:00
|
|
|
[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;
|
|
|
|
}
|
|
|
|
|
2007-05-26 14:09:03 +00:00
|
|
|
- (IBAction)clear:(id)sender
|
|
|
|
{
|
2007-06-05 00:33:30 +00:00
|
|
|
[currentEntry setIndex:[NSNumber numberWithInt:-1]];
|
|
|
|
|
2007-05-26 14:09:03 +00:00
|
|
|
[self removeObjects:[self content]];
|
2007-06-05 00:33:30 +00:00
|
|
|
[self updateTotalTime];
|
|
|
|
|
|
|
|
if (shuffle == YES)
|
|
|
|
[self resetShuffleList];
|
2007-05-26 14:09:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (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
|
|
|
}
|
|
|
|
|
2007-03-09 01:16:06 +00:00
|
|
|
- (IBAction)showEntryInFinder:(id)sender
|
2006-05-23 15:12:24 +00:00
|
|
|
{
|
|
|
|
NSWorkspace* ws = [NSWorkspace sharedWorkspace];
|
2006-05-24 18:09:44 +00:00
|
|
|
if ([self selectionIndex] < 0)
|
2006-05-23 15:12:24 +00:00
|
|
|
return;
|
|
|
|
|
2007-03-09 01:16:06 +00:00
|
|
|
NSURL *url = [[self entryAtIndex:[self selectionIndex]] url];
|
|
|
|
if ([url isFileURL])
|
|
|
|
[ws selectFile:[url path] inFileViewerRootedAtPath:[url path]];
|
2006-05-23 15:12:24 +00:00
|
|
|
}
|
|
|
|
|
2005-06-02 18:16:43 +00:00
|
|
|
@end
|