Add undo support to file browser

This closes #17.
This commit is contained in:
Allan Odgaard
2013-01-22 19:36:24 +01:00
parent 658c17023b
commit ef012c90f2
2 changed files with 45 additions and 64 deletions

View File

@@ -14,11 +14,11 @@
#import <OakFoundation/NSString Additions.h>
#import <OakAppKit/OakAppKit.h>
#import <OakAppKit/OakFileIconImage.h>
#import <OakAppKit/OakFileManager.h>
#import <OakAppKit/OakFinderLabelChooser.h>
#import <OakAppKit/OakOpenWithMenu.h>
#import <OakAppKit/OakZoomingIcon.h>
#import <OakAppKit/NSView Additions.h>
#import <OakAppKit/OakSound.h>
#import <OakSystem/application.h>
#import <bundles/bundles.h>
#import <document/document.h>
@@ -496,21 +496,19 @@ static NSMutableSet* SymmetricDifference (NSMutableSet* aSet, NSMutableSet* anot
- (void)duplicateSelectedEntries:(id)sender
{
NSMutableArray* duplicatedURLs = [NSMutableArray array];
for(NSString* aPath in self.selectedPaths)
for(NSURL* url in self.selectedURLs)
{
std::string const& dupPath = path::duplicate([aPath fileSystemRepresentation]);
if(dupPath != NULL_STR)
[duplicatedURLs addObject:[NSURL fileURLWithPath:[NSString stringWithCxxString:dupPath]]];
else OakRunIOAlertPanel("Failed to duplicate the file at “%s”.", [aPath fileSystemRepresentation]);
if([url isFileURL])
{
if(NSURL* res = [[OakFileManager sharedInstance] createDuplicateOfURL:url window:_view.window])
[duplicatedURLs addObject:res];
}
}
if([duplicatedURLs count])
{
OakPlayUISound(OakSoundDidMoveItemUISound);
if([duplicatedURLs count] == 1)
[_outlineViewDelegate editURL:[duplicatedURLs lastObject]];
else [_outlineViewDelegate selectURLs:duplicatedURLs expandChildren:NO];
}
if([duplicatedURLs count] == 1)
[_outlineViewDelegate editURL:[duplicatedURLs lastObject]];
else if([duplicatedURLs count] > 1)
[_outlineViewDelegate selectURLs:duplicatedURLs expandChildren:NO];
}
- (void)revealSelectedItem:(id)sender
@@ -569,26 +567,18 @@ static NSMutableSet* SymmetricDifference (NSMutableSet* aSet, NSMutableSet* anot
{
if(NSString* folder = [self parentForNewFolder])
{
std::string const dst = path::unique(path::join([folder fileSystemRepresentation], "untitled folder"));
if(path::make_dir(dst))
[_outlineViewDelegate editURL:[NSURL fileURLWithPath:[NSString stringWithCxxString:dst]]];
else OakRunIOAlertPanel("Failed to create new folder in “%s”.", path::parent([folder fileSystemRepresentation]).c_str());
if(NSURL* res = [[OakFileManager sharedInstance] createUntitledDirectoryAtURL:[NSURL fileURLWithPath:folder] window:_view.window])
[_outlineViewDelegate editURL:res];
}
}
- (void)delete:(id)anArgument
{
BOOL didTrashSomething = NO;
for(NSString* aPath in self.selectedPaths)
for(NSURL* url in self.selectedURLs)
{
std::string const trashPath = path::move_to_trash([aPath fileSystemRepresentation]);
if(trashPath != NULL_STR)
didTrashSomething = YES;
else OakRunIOAlertPanel("Failed to move the file at “%s” to the trash.", [aPath fileSystemRepresentation]);
if([url isFileURL])
[[OakFileManager sharedInstance] trashItemAtURL:url window:_view.window];
}
if(didTrashSomething)
OakPlayUISound(OakSoundDidTrashItemUISound);
}
- (void)changeColor:(OakFinderLabelChooser*)labelChooser
@@ -607,15 +597,14 @@ static NSMutableSet* SymmetricDifference (NSMutableSet* aSet, NSMutableSet* anot
if(!path::make_dir(favFolder))
return (void)OakRunIOAlertPanel("Failed to create Favorites folder.");
NSArray* paths = self.selectedPaths;
if(![paths count] && [_url isFileURL])
paths = @[ [_url path] ];
NSArray* urls = self.selectedURLs;
if(![urls count] && [_url isFileURL])
urls = @[ _url ];
for(NSString* aPath in paths)
for(NSURL* url in urls)
{
std::string const src = [aPath fileSystemRepresentation];
std::string const dst = path::join(favFolder, path::name(src));
path::link(src, dst);
std::string const dst = path::join(favFolder, path::name(to_s([url path])));
[[OakFileManager sharedInstance] createSymbolicLinkAtURL:[NSURL fileURLWithPath:[NSString stringWithCxxString:dst]] withDestinationURL:url window:_view.window];
}
}
@@ -646,18 +635,17 @@ static NSMutableSet* SymmetricDifference (NSMutableSet* aSet, NSMutableSet* anot
BOOL cut = [[pboard availableTypeFromArray:@[ @"OakFileBrowserOperation" ]] isEqualToString:@"OakFileBrowserOperation"] && [[pboard stringForType:@"OakFileBrowserOperation"] isEqualToString:@"cut"];
for(NSString* path in [pboard availableTypeFromArray:@[ NSFilenamesPboardType ]] ? [pboard propertyListForType:NSFilenamesPboardType] : nil)
{
std::string const src = [path fileSystemRepresentation];
std::string const dst = path::unique(path::join([folder fileSystemRepresentation], path::name(src)));
if(cut ? path::rename(src, dst) : path::copy(src, dst))
[created addObject:[NSURL fileURLWithPath:[NSString stringWithCxxString:dst]]];
std::string const dst = path::unique(path::join([folder fileSystemRepresentation], path::name([path fileSystemRepresentation])));
NSURL* dstURL = [NSURL fileURLWithPath:[NSString stringWithCxxString:dst]];
if(cut)
[[OakFileManager sharedInstance] moveItemAtURL:[NSURL fileURLWithPath:path] toURL:dstURL window:_view.window];
else [[OakFileManager sharedInstance] copyItemAtURL:[NSURL fileURLWithPath:path] toURL:dstURL window:_view.window];
[created addObject:dstURL];
}
}
if([created count] > 0)
{
OakPlayUISound(OakSoundDidMoveItemUISound);
[_outlineViewDelegate selectURLs:created expandChildren:NO];
}
}
- (void)executeBundleCommand:(id)sender
@@ -682,6 +670,7 @@ static NSMutableSet* SymmetricDifference (NSMutableSet* aSet, NSMutableSet* anot
[menu addItem:[NSMenuItem separatorItem]];
[menu addItemWithTitle:@"New Folder" action:@selector(newFolderInSelectedFolder:) keyEquivalent:@""];
[menu addItemWithTitle:[NSString stringWithFormat:@"Add “%@” to Favorites", DisplayName(_url)] action:@selector(addSelectedEntriesToFavorites:) keyEquivalent:@""];
[menu addItem:[NSMenuItem separatorItem]];
}
}
else
@@ -763,8 +752,12 @@ static NSMutableSet* SymmetricDifference (NSMutableSet* aSet, NSMutableSet* anot
if(NSMenuItem* openWithMenuItem = [menu itemWithTitle:@"Open With"])
[OakOpenWithMenu addOpenWithMenuForPaths:[NSSet setWithArray:self.selectedPaths] toMenuItem:openWithMenuItem];
[menu addItem:[NSMenuItem separatorItem]];
}
[[menu addItemWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:@""] setTarget:_view.window];
[[menu addItemWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:@""] setTarget:_view.window];
return menu;
}

View File

@@ -7,7 +7,7 @@
#import "FSSearchDataSource.h"
#import "FSXcodeProjectDataSource.h"
#import <OakAppKit/OakAppKit.h>
#import <OakAppKit/OakSound.h>
#import <OakAppKit/OakFileManager.h>
#import <OakFoundation/OakFoundation.h>
#import <OakFoundation/NSString Additions.h>
#import <io/path.h>
@@ -111,15 +111,12 @@ static ino_t inode (std::string const& path)
}
else
{
if(rename(src.c_str(), dst.c_str()) == 0)
NSURL* dstURL = [NSURL fileURLWithPath:[NSString stringWithCxxString:dst]];
if([[OakFileManager sharedInstance] renameItemAtURL:item.url toURL:dstURL window:anOutlineView.window])
{
item.url = [NSURL fileURLWithPath:[NSString stringWithCxxString:dst]];
item.url = dstURL;
item.name = [NSString stringWithCxxString:path::display_name(dst)];
}
else
{
OakRunIOAlertPanel("Failed to rename the file at “%s”.", path::name(src).c_str());
}
}
}
@@ -264,14 +261,14 @@ static NSDragOperation filter (NSDragOperation mask)
continue;
}
switch(op)
{
case NSDragOperationMove: path::rename(src, dst); break;
case NSDragOperationCopy: path::copy(src, dst); break;
case NSDragOperationLink: path::link(path::relative_to(src, dropPath), dst); break;
}
OakFileManager* fm = [OakFileManager sharedInstance];
if(op == NSDragOperationMove)
[fm moveItemAtURL:[NSURL fileURLWithPath:[NSString stringWithCxxString:src]] toURL:[NSURL fileURLWithPath:[NSString stringWithCxxString:dst]] window:anOutlineView.window];
else if(op == NSDragOperationCopy)
[fm copyItemAtURL:[NSURL fileURLWithPath:[NSString stringWithCxxString:src]] toURL:[NSURL fileURLWithPath:[NSString stringWithCxxString:dst]] window:anOutlineView.window];
else if(op == NSDragOperationLink)
[fm createSymbolicLinkAtURL:[NSURL fileURLWithPath:[NSString stringWithCxxString:dst]] withDestinationURL:[NSURL fileURLWithPath:[NSString stringWithCxxString:src]] window:anOutlineView.window];
}
OakPlayUISound(OakSoundDidMoveItemUISound);
return YES;
}
@@ -279,20 +276,11 @@ static NSDragOperation filter (NSDragOperation mask)
{
if(aDragOperation == NSDragOperationDelete)
{
BOOL didTrashSomething = NO;
for(FSItem* item in someItems)
{
if([item.url isFileURL])
{
std::string const trashPath = path::move_to_trash([item.path fileSystemRepresentation]);
if(trashPath != NULL_STR)
didTrashSomething = YES;
else OakRunIOAlertPanel("Failed to move the file at “%s” to the trash.", [item.path fileSystemRepresentation]);
}
[[OakFileManager sharedInstance] trashItemAtURL:item.url window:anOutlineView.window];
}
if(didTrashSomething)
OakPlayUISound(OakSoundDidTrashItemUISound);
}
}
@end