@interface PithosBrowserController (Private) {}
- (void)resetContainers:(NSNotification *)notification;
-- (void)getInfo:(NSMenuItem *)sender;
-- (void)downloadObjectFinished:(ASIPithosObjectRequest *)objectRequest;
-- (void)downloadObjectFailed:(ASIPithosObjectRequest *)objectRequest;
-- (void)uploadObjectUsingHashMapFinished:(ASIPithosObjectRequest *)objectRequest;
-- (void)uploadObjectUsingHashMapFailed:(ASIPithosObjectRequest *)objectRequest;
-- (void)uploadMissingBlockFinished:(ASIPithosObjectRequest *)objectRequest;
-- (void)uploadMissingBlockFailed:(ASIPithosObjectRequest *)objectRequest;
@end
@implementation PithosBrowserController
@synthesize outlineViewDataSourceArray, verticalSplitView, horizontalSplitView, leftTopView, leftBottomView,
- outlineView, browser, draggedNodes, draggedParentNode;
+ outlineView, browser;
+@synthesize draggedNodes, draggedParentNode;
+@synthesize clipboardNodes, clipboardParentNode, clipboardCopy;
#pragma mark -
#pragma Object Lifecycle
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
+ [clipboardParentNode release];
+ [clipboardNodes release];
[draggedParentNode release];
[draggedNodes release];
[browserMenu release];
NSInteger row = [browser clickedRow];
[menu removeAllItems];
NSMenuItem *menuItem;
+ NSString *menuItemTitle;
if ((column == -1) || (row == -1)) {
// General context menu
NSArray *menuNodesIndexPaths = [browser selectionIndexPaths];
} else {
menuNode = [browser itemAtIndexPath:[menuNodesIndexPaths objectAtIndex:0]];
}
- NSArray *menuNodes = [NSArray arrayWithObject:menuNode];
// New Folder
- menuItem = [[[NSMenuItem alloc] initWithTitle:@"New Folder" action:@selector(newFolder:) keyEquivalent:@""] autorelease];
- [menuItem setRepresentedObject:menuNodes];
+ menuItem = [[[NSMenuItem alloc] initWithTitle:@"New Folder" action:@selector(menuNewFolder:) keyEquivalent:@""] autorelease];
+ [menuItem setRepresentedObject:menuNode];
[menu addItem:menuItem];
- [menu addItem:[NSMenuItem separatorItem]];
// Get Info
- menuItem = [[[NSMenuItem alloc] initWithTitle:@"Get Info" action:@selector(getInfo:) keyEquivalent:@""] autorelease];
- [menuItem setRepresentedObject:menuNodes];
+ [menu addItem:[NSMenuItem separatorItem]];
+ menuItem = [[[NSMenuItem alloc] initWithTitle:@"Get Info" action:@selector(menuGetInfo:) keyEquivalent:@""] autorelease];
+ [menuItem setRepresentedObject:[NSArray arrayWithObject:menuNode]];
[menu addItem:menuItem];
+ // Paste
+ if (clipboardNodes) {
+ NSUInteger clipboardNodesCount = [clipboardNodes count];
+ if (clipboardNodesCount == 0) {
+ self.clipboardNodes = nil;
+ } else if (clipboardCopy || ![menuNode isEqualTo:clipboardParentNode]) {
+ if (clipboardNodesCount == 1)
+ menuItemTitle = [NSString stringWithString:@"Paste Item"];
+ else
+ menuItemTitle = [NSString stringWithString:@"Paste Items"];
+ [menu addItem:[NSMenuItem separatorItem]];
+ menuItem = [[[NSMenuItem alloc] initWithTitle:menuItemTitle action:@selector(menuPaste:) keyEquivalent:@""] autorelease];
+ [menuItem setRepresentedObject:menuNode];
+ [menu addItem:menuItem];
+ }
+ }
} else {
// Node context menu
NSIndexPath *clickedNodeIndexPath = [[browser indexPathForColumn:column] indexPathByAddingIndex:row];
} else {
[menuNodes addObject:[browser itemAtIndexPath:clickedNodeIndexPath]];
}
+ NSUInteger menuNodesCount = [menuNodes count];
// Move to Trash (pithos container only)
// Delete
if ([rootNode class] == [PithosContainerNode class]) {
if ([rootNode.pithosContainer.name isEqualToString:@"pithos"]) {
- menuItem = [[[NSMenuItem alloc] initWithTitle:@"Move to Trash" action:@selector(moveToTrash:) keyEquivalent:@""] autorelease];
+ menuItem = [[[NSMenuItem alloc] initWithTitle:@"Move to Trash" action:@selector(menuMoveToTrash:) keyEquivalent:@""] autorelease];
[menuItem setRepresentedObject:menuNodes];
[menu addItem:menuItem];
}
- menuItem = [[[NSMenuItem alloc] initWithTitle:@"Delete" action:@selector(deleteObject:) keyEquivalent:@""] autorelease];
+ menuItem = [[[NSMenuItem alloc] initWithTitle:@"Delete" action:@selector(menuDelete:) keyEquivalent:@""] autorelease];
[menuItem setRepresentedObject:menuNodes];
[menu addItem:menuItem];
- [menu addItem:[NSMenuItem separatorItem]];
}
// Get Info
- menuItem = [[[NSMenuItem alloc] initWithTitle:@"Get Info" action:@selector(getInfo:) keyEquivalent:@""] autorelease];
+ [menu addItem:[NSMenuItem separatorItem]];
+ menuItem = [[[NSMenuItem alloc] initWithTitle:@"Get Info" action:@selector(menuGetInfo:) keyEquivalent:@""] autorelease];
+ [menuItem setRepresentedObject:menuNodes];
+ [menu addItem:menuItem];
+ // Cut
+ [menu addItem:[NSMenuItem separatorItem]];
+ if (menuNodesCount == 1)
+ menuItemTitle = [NSString stringWithFormat:@"Cut \"%@\"", ((PithosNode *)[menuNodes objectAtIndex:0]).displayName];
+ else
+ menuItemTitle = [NSString stringWithFormat:@"Cut %lu Items", menuNodesCount];
+ menuItem = [[[NSMenuItem alloc] initWithTitle:menuItemTitle action:@selector(menuCut:) keyEquivalent:@""] autorelease];
+ [menuItem setRepresentedObject:menuNodes];
+ [menu addItem:menuItem];
+ // Copy
+ if (menuNodesCount == 1)
+ menuItemTitle = [NSString stringWithFormat:@"Copy \"%@\"", ((PithosNode *)[menuNodes objectAtIndex:0]).displayName];
+ else
+ menuItemTitle = [NSString stringWithFormat:@"Copy %lu Items", menuNodesCount];
+ menuItem = [[[NSMenuItem alloc] initWithTitle:menuItemTitle action:@selector(menuCopy:) keyEquivalent:@""] autorelease];
[menuItem setRepresentedObject:menuNodes];
[menu addItem:menuItem];
+ // Paste
+ if (menuNodesCount == 1) {
+ PithosNode *menuNode = [menuNodes objectAtIndex:0];
+ if (([menuNode class] == [PithosSubdirNode class]) &&
+ (menuNode.pithosObject.subdir || ![menuNode.pithosObject.name hasSuffix:@"/"])) {
+ if (clipboardNodes) {
+ NSUInteger clipboardNodesCount = [clipboardNodes count];
+ if (clipboardNodesCount == 0) {
+ self.clipboardNodes = nil;
+ } else if (clipboardCopy || ![menuNode isEqualTo:clipboardParentNode]) {
+ if (clipboardNodesCount == 1)
+ menuItemTitle = [NSString stringWithString:@"Paste Item"];
+ else
+ menuItemTitle = [NSString stringWithString:@"Paste Items"];
+ menuItem = [[[NSMenuItem alloc] initWithTitle:menuItemTitle action:@selector(menuPaste:) keyEquivalent:@""] autorelease];
+ [menuItem setRepresentedObject:menuNode];
+ [menu addItem:menuItem];
+ }
+ }
+ }
+ }
}
}
#pragma mark -
#pragma mark Menu Actions
-- (void)newFolder:(NSMenuItem *)sender {
- for (PithosNode *node in ((NSArray *)[sender representedObject])) {
- if ([node class] == [PithosContainerNode class]) {
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_async(queue, ^{
- NSString *safeObjectName = [PithosFileUtilities safeSubdirNameForContainerName:node.pithosContainer.name
- subdirName:@"untitled folder"];
- ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithContainerName:node.pithosContainer.name
- objectName:safeObjectName
- eTag:nil
- contentType:@"application/directory"
- contentEncoding:nil
- contentDisposition:nil
- manifest:nil
- sharing:nil
- isPublic:ASIPithosObjectRequestPublicIgnore
- metadata:nil
- data:[NSData data]];
- objectRequest.delegate = self;
- objectRequest.didFinishSelector = @selector(newFolderFinished:);
- objectRequest.didFailSelector = @selector(newFolderFailed:);
- objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
- node, @"node",
- nil];
- [objectRequest startAsynchronous];
- });
- } else if (([node class] == [PithosSubdirNode class]) &&
- (node.pithosObject.subdir ||
- ![node.pithosObject.name hasSuffix:@"/"])) {
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_async(queue, ^{
- NSString *safeObjectName = [PithosFileUtilities safeSubdirNameForContainerName:node.pithosContainer.name
- subdirName:[node.pithosObject.name stringByAppendingPathComponent:@"untitled folder"]];
- ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithContainerName:node.pithosContainer.name
- objectName:safeObjectName
- eTag:nil
- contentType:@"application/directory"
- contentEncoding:nil
- contentDisposition:nil
- manifest:nil
- sharing:nil
- isPublic:ASIPithosObjectRequestPublicIgnore
- metadata:nil
- data:[NSData data]];
- objectRequest.delegate = self;
- objectRequest.didFinishSelector = @selector(newFolderFinished:);
- objectRequest.didFailSelector = @selector(newFolderFailed:);
- objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
- node, @"node",
- nil];
- [objectRequest startAsynchronous];
- });
- }
+- (void)menuNewFolder:(NSMenuItem *)sender {
+ PithosNode *node = (PithosNode *)[sender representedObject];
+ if ([node class] == [PithosContainerNode class]) {
+ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_async(queue, ^{
+ NSString *safeObjectName = [PithosFileUtilities safeSubdirNameForContainerName:node.pithosContainer.name
+ subdirName:@"untitled folder"];
+ ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithContainerName:node.pithosContainer.name
+ objectName:safeObjectName
+ eTag:nil
+ contentType:@"application/directory"
+ contentEncoding:nil
+ contentDisposition:nil
+ manifest:nil
+ sharing:nil
+ isPublic:ASIPithosObjectRequestPublicIgnore
+ metadata:nil
+ data:[NSData data]];
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(newFolderFinished:);
+ objectRequest.didFailSelector = @selector(newFolderFailed:);
+ objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ node, @"node",
+ nil];
+ [objectRequest startAsynchronous];
+ });
+ } else if (([node class] == [PithosSubdirNode class]) &&
+ (node.pithosObject.subdir ||
+ ![node.pithosObject.name hasSuffix:@"/"])) {
+ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_async(queue, ^{
+ NSString *safeObjectName = [PithosFileUtilities safeSubdirNameForContainerName:node.pithosContainer.name
+ subdirName:[node.pithosObject.name stringByAppendingPathComponent:@"untitled folder"]];
+ ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithContainerName:node.pithosContainer.name
+ objectName:safeObjectName
+ eTag:nil
+ contentType:@"application/directory"
+ contentEncoding:nil
+ contentDisposition:nil
+ manifest:nil
+ sharing:nil
+ isPublic:ASIPithosObjectRequestPublicIgnore
+ metadata:nil
+ data:[NSData data]];
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(newFolderFinished:);
+ objectRequest.didFailSelector = @selector(newFolderFailed:);
+ objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ node, @"node",
+ nil];
+ [objectRequest startAsynchronous];
+ });
}
}
-- (void)getInfo:(NSMenuItem *)sender {
+- (void)menuGetInfo:(NSMenuItem *)sender {
for (PithosNode *node in ((NSArray *)[sender representedObject])) {
[node showPithosNodeInfo:sender];
}
}
-- (void)deleteObject:(NSMenuItem *)sender {
+- (void)menuDelete:(NSMenuItem *)sender {
for (PithosNode *node in ((NSArray *)[sender representedObject])) {
if (([node class] == [PithosObjectNode class]) ||
(([node class] == [PithosSubdirNode class]) &&
}
}
-- (void)moveToTrash:(NSMenuItem *)sender {
+- (void)menuMoveToTrash:(NSMenuItem *)sender {
for (PithosNode *node in ((NSArray *)[sender representedObject])) {
if (([node class] == [PithosObjectNode class]) ||
(([node class] == [PithosSubdirNode class]) &&
}
}
+- (void)menuCut:(NSMenuItem *)sender {
+ self.clipboardNodes = (NSArray *)[sender representedObject];
+ self.clipboardParentNode = ((PithosNode *)[clipboardNodes objectAtIndex:0]).parent;
+ self.clipboardCopy = NO;
+}
+
+- (void)menuCopy:(NSMenuItem *)sender {
+ self.clipboardNodes = (NSArray *)[sender representedObject];
+ self.clipboardParentNode = ((PithosNode *)[clipboardNodes objectAtIndex:0]).parent;
+ self.clipboardCopy = YES;
+}
+
+- (void)menuPaste:(NSMenuItem *)sender {
+ if (!clipboardNodes || ![clipboardNodes count])
+ return;
+ PithosNode *dropNode = (PithosNode *)[sender representedObject];
+ if ((([dropNode class] != [PithosSubdirNode class]) && ([dropNode class] != [PithosContainerNode class])) ||
+ (([dropNode class] == [PithosSubdirNode class]) && !dropNode.pithosObject.subdir && [dropNode.pithosObject.name hasSuffix:@"/"]))
+ return;
+
+ NSString *containerName = [NSString stringWithString:dropNode.pithosContainer.name];
+ NSString *objectNamePrefix;
+ if ([dropNode class] == [PithosSubdirNode class])
+ objectNamePrefix = [NSString stringWithString:dropNode.pithosObject.name];
+ else
+ objectNamePrefix = [NSString string];
+
+ NSArray *localClipboardNodes = [NSArray arrayWithArray:clipboardNodes];
+ if (!clipboardCopy && ![dropNode isEqualTo:clipboardParentNode]) {
+ self.clipboardNodes = nil;
+ self.clipboardParentNode = nil;
+ for (PithosNode *node in localClipboardNodes) {
+ if (([node class] == [PithosObjectNode class]) ||
+ (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) {
+ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_async(queue, ^{
+ NSString *destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
+ if ([node.pithosObject.name hasSuffix:@"/"])
+ destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
+ ASIPithosObjectRequest *objectRequest = [PithosFileUtilities moveObjectRequestWithContainerName:node.pithosContainer.name
+ objectName:node.pithosObject.name
+ destinationContainerName:containerName
+ destinationObjectName:destinationObjectName
+ checkIfExists:YES];
+ if (objectRequest) {
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(moveFinished:);
+ objectRequest.didFailSelector = @selector(moveFailed:);
+ objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ node.parent, @"node",
+ dropNode, @"dropNode",
+ nil];
+ [objectRequest startAsynchronous];
+ }
+ });
+ } else if ([node class] == [PithosSubdirNode class]) {
+ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_async(queue, ^{
+ NSString *destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
+ if (node.pithosObject.subdir)
+ destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
+ NSArray *objectRequests = [PithosFileUtilities moveObjectRequestsForSubdirWithContainerName:node.pithosContainer.name
+ objectName:node.pithosObject.name
+ destinationContainerName:containerName
+ destinationObjectName:destinationObjectName
+ checkIfExists:YES];
+ if (objectRequests) {
+ for (ASIPithosObjectRequest *objectRequest in objectRequests) {
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(moveFinished:);
+ objectRequest.didFailSelector = @selector(moveFailed:);
+ objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ node.parent, @"node",
+ dropNode, @"dropNode",
+ nil];
+ [objectRequest startAsynchronous];
+ }
+ }
+ });
+ }
+ }
+ } else {
+ for (PithosNode *node in localClipboardNodes) {
+ if (([node class] == [PithosObjectNode class]) ||
+ (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) {
+ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_async(queue, ^{
+ NSString *destinationObjectName;
+ if (![dropNode isEqualTo:node.parent]) {
+ destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
+ if ([node.pithosObject.name hasSuffix:@"/"])
+ destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
+ } else {
+ destinationObjectName = [PithosFileUtilities safeObjectNameForContainerName:containerName
+ objectName:node.pithosObject.name];
+ }
+ ASIPithosObjectRequest *objectRequest = [PithosFileUtilities copyObjectRequestWithContainerName:node.pithosContainer.name
+ objectName:node.pithosObject.name
+ destinationContainerName:containerName
+ destinationObjectName:destinationObjectName
+ checkIfExists:YES];
+ if (objectRequest) {
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(copyFinished:);
+ objectRequest.didFailSelector = @selector(copyFailed:);
+ objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ dropNode, @"dropNode",
+ nil];
+ [objectRequest startAsynchronous];
+ }
+ });
+ } else if ([node class] == [PithosSubdirNode class]) {
+ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_async(queue, ^{
+ NSString *destinationObjectName;
+ if (![dropNode isEqualTo:node.parent]) {
+ destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
+ if (node.pithosObject.subdir)
+ destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
+ } else {
+ destinationObjectName = [PithosFileUtilities safeSubdirNameForContainerName:containerName
+ subdirName:node.pithosObject.name];
+ }
+ NSArray *objectRequests = [PithosFileUtilities copyObjectRequestsForSubdirWithContainerName:node.pithosContainer.name
+ objectName:node.pithosObject.name
+ destinationContainerName:containerName
+ destinationObjectName:destinationObjectName
+ checkIfExists:YES];
+ if (objectRequests) {
+ for (ASIPithosObjectRequest *objectRequest in objectRequests) {
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(copyFinished:);
+ objectRequest.didFailSelector = @selector(copyFailed:);
+ objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ dropNode, @"dropNode",
+ nil];
+ [objectRequest startAsynchronous];
+ }
+ }
+ });
+ }
+ }
+ }
+}
+
#pragma mark -
#pragma mark Menu Actions ASIHTTPRequestDelegate