Added undo functionality in playlist, undo works for removals, moves and adds.
parent
4bd896afb3
commit
9b05ce02d2
|
@ -236,9 +236,11 @@ increase/decrease as long as the user holds the left/right, plus/minus button */
|
|||
[remote startListening:self];
|
||||
}
|
||||
|
||||
|
||||
NSUndoManager *undoManager = [playlistController undoManager];
|
||||
[undoManager disableUndoRegistration];
|
||||
NSString *filename = @"~/Library/Application Support/Cog/Default.m3u";
|
||||
[playlistLoader addURL:[NSURL fileURLWithPath:[filename stringByExpandingTildeInPath]]];
|
||||
[undoManager enableUndoRegistration];
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
||||
|
|
|
@ -130,6 +130,7 @@
|
|||
8EFFCD630AA093AF00C458A5 /* FileNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EFFCD470AA093AF00C458A5 /* FileNode.m */; };
|
||||
8EFFCD650AA093AF00C458A5 /* FileOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EFFCD490AA093AF00C458A5 /* FileOutlineView.m */; };
|
||||
8EFFCD6F0AA093AF00C458A5 /* PathNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EFFCD530AA093AF00C458A5 /* PathNode.m */; };
|
||||
B01946070D5F5467001A2FB8 /* UndoObject.m in Sources */ = {isa = PBXBuildFile; fileRef = B01946060D5F5467001A2FB8 /* UndoObject.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -632,6 +633,8 @@
|
|||
8EFFCD490AA093AF00C458A5 /* FileOutlineView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = FileOutlineView.m; sourceTree = "<group>"; };
|
||||
8EFFCD520AA093AF00C458A5 /* PathNode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PathNode.h; sourceTree = "<group>"; };
|
||||
8EFFCD530AA093AF00C458A5 /* PathNode.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PathNode.m; sourceTree = "<group>"; };
|
||||
B01946050D5F5467001A2FB8 /* UndoObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UndoObject.h; sourceTree = "<group>"; };
|
||||
B01946060D5F5467001A2FB8 /* UndoObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UndoObject.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -1116,6 +1119,8 @@
|
|||
8E75752A09F31D5A0080F1EE /* Playlist */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B01946050D5F5467001A2FB8 /* UndoObject.h */,
|
||||
B01946060D5F5467001A2FB8 /* UndoObject.m */,
|
||||
8E1296D80A2BA9CE00443124 /* PlaylistHeaderView.h */,
|
||||
8E1296D90A2BA9CE00443124 /* PlaylistHeaderView.m */,
|
||||
1755E1F60BA0D2B600CA3560 /* PlaylistLoader.h */,
|
||||
|
@ -1610,6 +1615,7 @@
|
|||
178BAB9B0CD4E1B700B33D47 /* PopupButton.m in Sources */,
|
||||
17BBE5BC0CD95CFA00258F7A /* InvertedToolbarWindow.m in Sources */,
|
||||
569C52E20D5F347800BDBDC9 /* SpotlightWindowController.m in Sources */,
|
||||
B01946070D5F5467001A2FB8 /* UndoObject.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -114,7 +114,6 @@ NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E";
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
- (NSIndexSet *)indexSetFromRows:(NSArray *)rows
|
||||
{
|
||||
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
|
||||
|
@ -127,7 +126,6 @@ NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E";
|
|||
return indexSet;
|
||||
}
|
||||
|
||||
|
||||
- (int)rowsAboveRow:(int)row inIndexSet:(NSIndexSet *)indexSet
|
||||
{
|
||||
unsigned currentIndex = [indexSet firstIndex];
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <Foundation/NSUndoManager.h>
|
||||
#import "UndoObject.h"
|
||||
#import "DNDArrayController.h"
|
||||
|
||||
@class PlaylistLoader;
|
||||
|
@ -18,7 +20,9 @@
|
|||
NSString *totalTimeDisplay;
|
||||
|
||||
NSMutableArray *shuffleList;
|
||||
|
||||
|
||||
NSUndoManager *undoManager;
|
||||
|
||||
PlaylistEntry *currentEntry;
|
||||
|
||||
BOOL shuffle;
|
||||
|
@ -38,6 +42,13 @@
|
|||
- (void)setRepeat:(BOOL)r;
|
||||
- (BOOL)repeat;
|
||||
|
||||
/* Methods for undoing various actions */
|
||||
- (NSUndoManager *)undoManager;
|
||||
- (void)undoDelete:(NSMutableArray *)undoEntries;
|
||||
- (void)undoMove:(NSMutableArray *) undoEntries;
|
||||
- (void)doUndo:(id)sender;
|
||||
- (void)doRedo:(id)sender;
|
||||
|
||||
- (IBAction)takeShuffleFromObject:(id)sender;
|
||||
- (IBAction)takeRepeatFromObject:(id)sender;
|
||||
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
//
|
||||
// PlaylistController.m
|
||||
// Cog
|
||||
// PlaylistController.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 3/18/05.
|
||||
// Copyright 2005 Vincent Spader All rights reserved.
|
||||
// Created by Vincent Spader on 3/18/05.
|
||||
// Copyright 2005 Vincent Spader All rights reserved.
|
||||
//
|
||||
|
||||
#import "PlaylistLoader.h"
|
||||
#import "PlaylistController.h"
|
||||
#import "PlaylistEntry.h"
|
||||
#import "Shuffle.h"
|
||||
#import "UndoObject.h"
|
||||
|
||||
#import "CogAudio/AudioPlayer.h"
|
||||
|
||||
@implementation PlaylistController
|
||||
|
||||
#define SHUFFLE_HISTORY_SIZE 100
|
||||
#define UNDO_STACK_LIMIT 25
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder
|
||||
{
|
||||
|
@ -24,6 +26,9 @@
|
|||
if (self)
|
||||
{
|
||||
shuffleList = [[NSMutableArray alloc] init];
|
||||
undoManager = [[NSUndoManager alloc] init];
|
||||
|
||||
[undoManager setLevelsOfUndo:UNDO_STACK_LIMIT];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
@ -44,18 +49,52 @@
|
|||
dropOperation:(NSTableViewDropOperation)op
|
||||
{
|
||||
[super tableView:tv acceptDrop:info row:row dropOperation:op];
|
||||
|
||||
UndoObject *undoEntry;
|
||||
NSMutableArray *undoEntries = [[NSMutableArray alloc] init];
|
||||
|
||||
if ([info draggingSource] == tableView)
|
||||
{
|
||||
//DNDArrayController handles moving...still need to update the indexes
|
||||
|
||||
int i;
|
||||
NSArray *rows = [NSKeyedUnarchiver unarchiveObjectWithData:[[info draggingPasteboard] dataForType: MovedRowsType]];
|
||||
int firstIndex = [[self indexSetFromRows:rows] firstIndex];
|
||||
NSArray *rows = [NSKeyedUnarchiver unarchiveObjectWithData:[[info draggingPasteboard] dataForType: MovedRowsType]];
|
||||
NSIndexSet *indexes = [self indexSetFromRows:rows];
|
||||
int firstIndex = [indexes firstIndex];
|
||||
int indexesSize = [indexes count];
|
||||
NSUInteger indexBuffer[indexesSize];
|
||||
|
||||
int i;
|
||||
int adjustment;
|
||||
int counter;
|
||||
|
||||
if (firstIndex > row)
|
||||
i = row;
|
||||
else
|
||||
i = firstIndex;
|
||||
|
||||
[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];
|
||||
|
||||
|
||||
|
||||
[self updateIndexesFromRow:i];
|
||||
|
||||
|
@ -159,10 +198,143 @@
|
|||
}
|
||||
}
|
||||
|
||||
-(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];
|
||||
}
|
||||
|
||||
|
||||
- (void)removeObjectsAtArrangedObjectIndexes:(NSIndexSet *)indexes
|
||||
{
|
||||
int i; // loop counter
|
||||
int indexesSize = [indexes count];
|
||||
NSUInteger indexBuffer[indexesSize];
|
||||
UndoObject *undoEntry;
|
||||
PlaylistEntry *pre;
|
||||
NSMutableArray *undoEntries = [[NSMutableArray alloc] init];
|
||||
|
||||
NSLog(@"Removing indexes: %@", indexes);
|
||||
NSLog(@"Current index: %i", [[currentEntry index] intValue]);
|
||||
|
||||
// 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];
|
||||
|
||||
|
||||
if ([[currentEntry index] intValue] >= 0 && [indexes containsIndex:[[currentEntry index] intValue]])
|
||||
{
|
||||
|
|
|
@ -23,7 +23,7 @@ typedef enum {
|
|||
- (void)addURLs:(NSArray *)urls sort:(BOOL)sort;
|
||||
- (void)addURL:(NSURL *)url;
|
||||
- (void)insertURLs:(NSArray *)urls atIndex:(int)index sort:(BOOL)sort;
|
||||
|
||||
- (void)undoAdd:(NSIndexSet *)undoEntries;
|
||||
//save playlist, auto-determines type based on extension. Uses m3u if it cannot be determined.
|
||||
- (BOOL)save:(NSString *)filename;
|
||||
- (BOOL)save:(NSString *)filename asType:(PlaylistType)type;
|
||||
|
|
|
@ -252,7 +252,8 @@
|
|||
[validURLs addObject:url];
|
||||
}
|
||||
|
||||
|
||||
NSUndoManager *undoManager = [playlistController undoManager];
|
||||
|
||||
//Create actual entries
|
||||
int i;
|
||||
NSMutableArray *entries = [NSMutableArray array];
|
||||
|
@ -271,6 +272,10 @@
|
|||
}
|
||||
|
||||
NSIndexSet *is = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, [entries count])];
|
||||
|
||||
[undoManager registerUndoWithTarget:self
|
||||
selector:@selector(undoAdd:)
|
||||
object:is];
|
||||
|
||||
[playlistController insertObjects:entries atArrangedObjectIndexes:is];
|
||||
|
||||
|
@ -283,6 +288,12 @@
|
|||
return;
|
||||
}
|
||||
|
||||
-(void)undoAdd:(NSIndexSet *)undoEntries
|
||||
{
|
||||
[playlistController removeObjectsAtArrangedObjectIndexes:undoEntries];
|
||||
|
||||
}
|
||||
|
||||
- (void)readEntriesInfoThread:(NSArray *)entries
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
|
|
@ -133,8 +133,8 @@
|
|||
{
|
||||
//Find which row is under the cursor
|
||||
[[self window] makeFirstResponder:self];
|
||||
NSPoint menuPoint = [self convertPoint:[event locationInWindow] fromView:nil];
|
||||
int row = [self rowAtPoint:menuPoint];
|
||||
NSPoint menuPoint = [self convertPoint:[event locationInWindow] fromView:nil];
|
||||
int row = [self rowAtPoint:menuPoint];
|
||||
|
||||
/* Update the table selection before showing menu
|
||||
Preserves the selection if the row under the mouse is selected (to allow for
|
||||
|
@ -171,11 +171,12 @@
|
|||
|
||||
- (void)keyDown:(NSEvent *)e
|
||||
{
|
||||
unsigned int modifiers = [e modifierFlags] & (NSCommandKeyMask | NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask);
|
||||
NSString *characters = [e characters];
|
||||
unichar c;
|
||||
unsigned int modifiers = [e modifierFlags] & (NSCommandKeyMask | NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask);
|
||||
NSString *characters = [e characters];
|
||||
unichar c;
|
||||
|
||||
if ([characters length] != 1) {
|
||||
if ([characters length] != 1)
|
||||
{
|
||||
[super keyDown:e];
|
||||
|
||||
return;
|
||||
|
@ -194,7 +195,9 @@
|
|||
{
|
||||
[playbackController play:self];
|
||||
}
|
||||
else if (modifiers == 0 && c == 0x1b) { //Escape
|
||||
// Escape
|
||||
else if (modifiers == 0 && c == 0x1b)
|
||||
{
|
||||
[playlistController clearFilterPredicate:self];
|
||||
}
|
||||
else if (modifiers == NSControlKeyMask && c == 0xf703) // right arrow
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// UndoObject.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Andre Reffhaug on 2/6/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
|
||||
@interface UndoObject : NSObject {
|
||||
int origin;
|
||||
int movedTo;
|
||||
NSURL *path;
|
||||
}
|
||||
|
||||
-(void)setPath:(NSURL *) p;
|
||||
-(void)setOrigin:(int) i;
|
||||
-(void)setMovedTo:(int) i;
|
||||
-(void)setOrigin:(int) i andPath:(NSURL *)path;
|
||||
|
||||
-(int)origin;
|
||||
-(int)movedTo;
|
||||
-(NSURL *)path;
|
||||
|
||||
@end
|
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// UndoObject.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Andre Reffhaug on 2/6/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UndoObject.h"
|
||||
|
||||
|
||||
@implementation UndoObject
|
||||
|
||||
-(void)setPath:(NSURL *)p
|
||||
{
|
||||
[p retain];
|
||||
[path release];
|
||||
path = p;
|
||||
}
|
||||
|
||||
-(void)setOrigin:(int)i
|
||||
{
|
||||
origin = i;
|
||||
}
|
||||
|
||||
-(void)setMovedTo:(int)i
|
||||
{
|
||||
movedTo = i;
|
||||
}
|
||||
-(void)setOrigin:(int) i andPath:(NSURL *)p
|
||||
{
|
||||
origin = i;
|
||||
[p retain];
|
||||
[path release];
|
||||
path = p;
|
||||
}
|
||||
|
||||
-(int) origin
|
||||
{
|
||||
return origin;
|
||||
}
|
||||
|
||||
-(int) movedTo
|
||||
{
|
||||
return movedTo;
|
||||
}
|
||||
|
||||
-(NSURL *) path
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
@end
|
Loading…
Reference in New Issue