Added move operation to DNDArrayController. Streamlined undo.

CQTexperiment
vspader 2008-02-10 19:35:58 +00:00
parent aaad9aa2dc
commit e2b40fe1a3
9 changed files with 98 additions and 297 deletions

View File

@ -130,7 +130,6 @@
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 */
@ -633,8 +632,6 @@
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 */
@ -1119,8 +1116,6 @@
8E75752A09F31D5A0080F1EE /* Playlist */ = {
isa = PBXGroup;
children = (
B01946050D5F5467001A2FB8 /* UndoObject.h */,
B01946060D5F5467001A2FB8 /* UndoObject.m */,
8E1296D80A2BA9CE00443124 /* PlaylistHeaderView.h */,
8E1296D90A2BA9CE00443124 /* PlaylistHeaderView.m */,
1755E1F60BA0D2B600CA3560 /* PlaylistLoader.h */,
@ -1615,7 +1610,6 @@
178BAB9B0CD4E1B700B33D47 /* PopupButton.m in Sources */,
17BBE5BC0CD95CFA00258F7A /* InvertedToolbarWindow.m in Sources */,
569C52E20D5F347800BDBDC9 /* SpotlightWindowController.m in Sources */,
B01946070D5F5467001A2FB8 /* UndoObject.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -17,7 +17,10 @@ extern NSString *iTunesDropType;
// utility methods
-(void)moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet *)indexSet toIndex:(unsigned)index;
-(void)moveObjectsFromArrangedObjectIndexes:(NSArray *) sources toIndexes:(NSArray *)destinations;
-(void)moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet*)indexSet toIndex:(unsigned int)insertIndex;
- (NSIndexSet *)indexSetFromRows:(NSArray *)rows;
- (int)rowsAboveRow:(int)row inIndexSet:(NSIndexSet *)indexSet;

View File

@ -69,11 +69,6 @@ NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E";
// set selected rows to those that were just moved
// Need to work out what moved where to determine proper selection...
int rowsAbove = [self rowsAboveRow:row inIndexSet:indexSet];
NSRange range = NSMakeRange(row - rowsAbove, [indexSet count]);
indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
[self setSelectionIndexes:indexSet];
return YES;
}
@ -82,16 +77,42 @@ NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E";
}
-(void) moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet*)indexSet
-(void)moveObjectsFromArrangedObjectIndexes:(NSArray *) sources toIndexes:(NSArray *)destinations;
{
//We expect [sources count] == [destinations count].
NSMutableArray *selectedObjects = [[NSMutableArray alloc] init];
NSUInteger i = 0;
for (i = 0; i < [sources count]; i++) {
NSUInteger source = [[sources objectAtIndex:i] unsignedIntegerValue];
NSUInteger dest = [[destinations objectAtIndex:i] unsignedIntegerValue];
id object = [[self arrangedObjects] objectAtIndex:source];
[object retain];
[self removeObjectAtArrangedObjectIndex:source];
[self insertObject:object atArrangedObjectIndex:dest];
[selectedObjects addObject: object];
[object release];
}
[self setSelectedObjects:selectedObjects];
[selectedObjects release];
}
-(void)moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet*)indexSet
toIndex:(unsigned int)insertIndex
{
NSArray *objects = [self arrangedObjects];
int index = [indexSet lastIndex];
int aboveInsertIndexCount = 0;
id object;
int removeIndex;
NSMutableArray *sources = [NSMutableArray array];
NSMutableArray *destinations = [NSMutableArray array];
while (NSNotFound != index)
{
@ -104,14 +125,14 @@ NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E";
removeIndex = index;
insertIndex -= 1;
}
object = [objects objectAtIndex:removeIndex];
[object retain];
[self removeObjectAtArrangedObjectIndex:removeIndex];
[self insertObject:object atArrangedObjectIndex:insertIndex];
[object release];
[sources addObject:[NSNumber numberWithUnsignedInteger:removeIndex]];
[destinations addObject: [NSNumber numberWithUnsignedInteger:insertIndex]];
index = [indexSet indexLessThanIndex:index];
}
[self moveObjectsFromArrangedObjectIndexes:sources toIndexes:destinations];
}
- (NSIndexSet *)indexSetFromRows:(NSArray *)rows
@ -126,16 +147,4 @@ NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E";
return indexSet;
}
- (int)rowsAboveRow:(int)row inIndexSet:(NSIndexSet *)indexSet
{
unsigned currentIndex = [indexSet firstIndex];
int i = 0;
while (currentIndex != NSNotFound)
{
if (currentIndex < row) { i++; }
currentIndex = [indexSet indexGreaterThanIndex:currentIndex];
}
return i;
}
@end

View File

@ -8,7 +8,6 @@
#import <Cocoa/Cocoa.h>
#import <Foundation/NSUndoManager.h>
#import "UndoObject.h"
#import "DNDArrayController.h"
@class PlaylistLoader;
@ -44,8 +43,6 @@
/* Methods for undoing various actions */
- (NSUndoManager *)undoManager;
- (void)undoDelete:(NSMutableArray *)undoEntries;
- (void)undoMove:(NSMutableArray *) undoEntries;
- (IBAction)takeShuffleFromObject:(id)sender;
- (IBAction)takeRepeatFromObject:(id)sender;

View File

@ -10,14 +10,13 @@
#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
#define UNDO_STACK_LIMIT 100
- (id)initWithCoder:(NSCoder *)decoder
{
@ -43,6 +42,42 @@
[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];
}
- (BOOL)tableView:(NSTableView*)tv
acceptDrop:(id <NSDraggingInfo>)info
row:(int)row
@ -50,53 +85,9 @@
{
[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
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];
}
[[self undoManager] registerUndoWithTarget:self
selector:@selector(undoMove:)
object:undoEntries];
[self updateIndexesFromRow:i];
//DNDArrayController handles moving...
return YES;
}
@ -198,132 +189,29 @@
}
}
-(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
[[self 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 ([[self 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 ([[self 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)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];
}
- (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
[[self undoManager] registerUndoWithTarget:self
selector:@selector(undoDelete:)
object:undoEntries];
if ([[currentEntry index] intValue] >= 0 && [indexes containsIndex:[[currentEntry index] intValue]])
{
[currentEntry setIndex:[NSNumber numberWithInt:-[[currentEntry index] intValue] - 1]];
@ -347,7 +235,9 @@
NSLog(@"UPDATING INDEX: %@", [currentEntry index]);
}
[[[self undoManager] prepareWithInvocationTarget:self] insertObjects:[[self arrangedObjects] objectsAtIndexes:indexes] atArrangedObjectIndexes:indexes];
[super removeObjectsAtArrangedObjectIndexes:indexes];
[self updateIndexesFromRow:[indexes firstIndex]];
[self updateTotalTime];

View File

@ -252,8 +252,6 @@
[validURLs addObject:url];
}
NSUndoManager *undoManager = [playlistController undoManager];
//Create actual entries
int i;
NSMutableArray *entries = [NSMutableArray array];
@ -273,10 +271,6 @@
NSIndexSet *is = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, [entries count])];
[undoManager registerUndoWithTarget:self
selector:@selector(undoAdd:)
object:is];
[playlistController insertObjects:entries atArrangedObjectIndexes:is];
//Select the first entry in the group that was just added
@ -288,12 +282,6 @@
return;
}
-(void)undoAdd:(NSIndexSet *)undoEntries
{
[playlistController removeObjectsAtArrangedObjectIndexes:undoEntries];
}
- (void)readEntriesInfoThread:(NSArray *)entries
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

View File

@ -233,17 +233,17 @@
[[playlistController undoManager] redo];
}
-(BOOL)validateMenuItem:(NSMenuItem*)menuItem
-(BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem
{
SEL action = [menuItem action];
SEL action = [anItem action];
if (action == @selector(undo:) && [[playlistController undoManager] canUndo])
return YES;
if (action == @selector(redo:) && [[playlistController undoManager] canRedo])
return YES;
return NO;
return [super validateUserInterfaceItem:anItem];
}
@end

View File

@ -1,27 +0,0 @@
//
// 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

View File

@ -1,53 +0,0 @@
//
// 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