From 67e3336fa39662c899f99343401518e88b523b1b Mon Sep 17 00:00:00 2001 From: Miltiadis Vasilakis Date: Fri, 30 Sep 2011 19:48:09 +0300 Subject: [PATCH] Container items in the outlineView can be drag and drop targets for upload, copy or move. --- pithos-macos/PithosBrowserController.h | 2 +- pithos-macos/PithosBrowserController.m | 574 ++++++++++++++++++-------------- 2 files changed, 333 insertions(+), 243 deletions(-) diff --git a/pithos-macos/PithosBrowserController.h b/pithos-macos/PithosBrowserController.h index f0b1150..6bf0dfe 100644 --- a/pithos-macos/PithosBrowserController.h +++ b/pithos-macos/PithosBrowserController.h @@ -41,7 +41,7 @@ @class PithosSharingAccountsNode; @class PithosEmptyNode; -@interface PithosBrowserController : NSWindowController { +@interface PithosBrowserController : NSWindowController { PithosNode *rootNode; PithosAccountNode *accountNode; PithosEmptyNode *containersNode; diff --git a/pithos-macos/PithosBrowserController.m b/pithos-macos/PithosBrowserController.m index 58979fd..f7c3f5d 100644 --- a/pithos-macos/PithosBrowserController.m +++ b/pithos-macos/PithosBrowserController.m @@ -97,6 +97,9 @@ @interface PithosBrowserController (Private) {} - (void)resetContainers:(NSNotification *)notification; +- (BOOL)uploadFiles:(NSArray *)filenames toNode:(PithosNode *)destinationNode; +- (BOOL)moveNodes:(NSArray *)nodes toNode:(PithosNode *)destinationNode; +- (BOOL)copyNodes:(NSArray *)nodes toNode:(PithosNode *)destinationNode; @end @implementation PithosBrowserController @@ -137,6 +140,10 @@ [browser setDraggingSourceOperationMask:(NSDragOperationCopy|NSDragOperationMove) forLocal:YES]; [browser setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO]; + [outlineView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, NSFilesPromisePboardType, nil]]; + [outlineView setDraggingSourceOperationMask:(NSDragOperationCopy|NSDragOperationMove) forLocal:YES]; + [outlineView setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO]; + [browser setCellClass:[PithosBrowserCell class]]; browserMenu = [[NSMenu alloc] init]; @@ -648,272 +655,305 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { else node = [browser parentForItemsInColumn:column]; NSLog(@"drag in node: %@", node.url); - if (([node class] != [PithosSubdirNode class]) && ([node class] != [PithosContainerNode class])) - return NO; - - NSFileManager *defaultManager = [NSFileManager defaultManager]; - NSString *containerName = [NSString stringWithString:node.pithosContainer.name]; - NSString *objectNamePrefix; - if ([node class] == [PithosSubdirNode class]) - objectNamePrefix = [NSString stringWithString:node.pithosObject.name]; + return [self uploadFiles:filenames toNode:node]; + } + } else if ([[[info draggingPasteboard] types] containsObject:NSFilesPromisePboardType]) { + NSLog(@"drag local operation: %lu nodes: %@", [info draggingSourceOperationMask], draggedNodes); + if ((column != -1) && (draggedNodes != nil)) { + PithosNode *node = nil; + if (row != -1) + node = [browser itemAtRow:row inColumn:column]; else - objectNamePrefix = [NSString string]; - NSUInteger blockSize = node.pithosContainer.blockSize; - NSString *blockHash = node.pithosContainer.blockHash; - - for (NSString *filePath in filenames) { - BOOL isDirectory; - if ([defaultManager fileExistsAtPath:filePath isDirectory:&isDirectory]) { - if (!isDirectory) { - // Upload file - NSString *objectName = [objectNamePrefix stringByAppendingPathComponent:[filePath lastPathComponent]]; - dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - dispatch_async(queue, ^{ - NSError *error = nil; - NSString *contentType = [PithosFileUtilities contentTypeOfFile:filePath error:&error]; - if (contentType == nil) - contentType = @"application/octet-stream"; - if (error) - NSLog(@"contentType detection error: %@", error); - NSArray *hashes = nil; - ASIPithosObjectRequest *objectRequest = [PithosFileUtilities writeObjectDataRequestWithContainerName:containerName - objectName:objectName - contentType:contentType - blockSize:blockSize - blockHash:blockHash - forFile:filePath - checkIfExists:YES - hashes:&hashes - sharingAccount:node.sharingAccount]; - if (objectRequest) { + node = [browser parentForItemsInColumn:column]; + NSLog(@"drag local node: %@", node.url); + if ([info draggingSourceOperationMask] & NSDragOperationMove) + return [self moveNodes:draggedNodes toNode:node]; + else if ([info draggingSourceOperationMask] & NSDragOperationCopy) + return [self copyNodes:draggedNodes toNode:node]; + } + } + return NO; +} + +#pragma mark - +#pragma mark Drag and Drop methods + +- (BOOL)uploadFiles:(NSArray *)filenames toNode:(PithosNode *)destinationNode { + if (([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class])) + return NO; + NSFileManager *defaultManager = [NSFileManager defaultManager]; + NSString *containerName = [NSString stringWithString:destinationNode.pithosContainer.name]; + NSString *objectNamePrefix; + if ([destinationNode class] == [PithosSubdirNode class]) + objectNamePrefix = [NSString stringWithString:destinationNode.pithosObject.name]; + else + objectNamePrefix = [NSString string]; + if ((destinationNode.pithosContainer.blockHash == nil) || (destinationNode.pithosContainer.blockSize == 0)) { + ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest containerMetadataRequestWithContainerName:containerName]; + [containerRequest startSynchronous]; + if ([containerRequest error]) { + [PithosFileUtilities httpRequestErrorAlertWithRequest:containerRequest]; + return NO; + } else if (containerRequest.responseStatusCode != 200) { + [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:containerRequest]; + return NO; + } + destinationNode.pithosContainer.blockHash = [containerRequest blockHash]; + destinationNode.pithosContainer.blockSize = [containerRequest blockSize]; + } + NSUInteger blockSize = destinationNode.pithosContainer.blockSize; + NSString *blockHash = destinationNode.pithosContainer.blockHash; + + for (NSString *filePath in filenames) { + BOOL isDirectory; + if ([defaultManager fileExistsAtPath:filePath isDirectory:&isDirectory]) { + if (!isDirectory) { + // Upload file + NSString *objectName = [objectNamePrefix stringByAppendingPathComponent:[filePath lastPathComponent]]; + dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_async(queue, ^{ + NSError *error = nil; + NSString *contentType = [PithosFileUtilities contentTypeOfFile:filePath error:&error]; + if (contentType == nil) + contentType = @"application/octet-stream"; + if (error) + NSLog(@"contentType detection error: %@", error); + NSArray *hashes = nil; + ASIPithosObjectRequest *objectRequest = [PithosFileUtilities writeObjectDataRequestWithContainerName:containerName + objectName:objectName + contentType:contentType + blockSize:blockSize + blockHash:blockHash + forFile:filePath + checkIfExists:YES + hashes:&hashes + sharingAccount:destinationNode.sharingAccount]; + if (objectRequest) { + objectRequest.delegate = self; + objectRequest.didFinishSelector = @selector(uploadObjectUsingHashMapFinished:); + objectRequest.didFailSelector = @selector(uploadObjectUsingHashMapFailed:); + NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + containerName, @"containerName", + objectName, @"objectName", + contentType, @"contentType", + [NSNumber numberWithUnsignedInteger:blockSize], @"blockSize", + blockHash, @"blockHash", + filePath, @"filePath", + hashes, @"hashes", + destinationNode, @"node", + [NSNumber numberWithUnsignedInteger:10], @"iteration", + nil]; + if (destinationNode.sharingAccount) + [userInfo setObject:destinationNode.sharingAccount forKey:@"sharingAccount"]; + objectRequest.userInfo = userInfo; + [objectRequest startAsynchronous]; + } + }); + } else { + // Upload directory, confirm first + NSAlert *alert = [[[NSAlert alloc] init] autorelease]; + [alert setMessageText:@"Upload directory"]; + [alert setInformativeText:[NSString stringWithFormat:@"'%@' is a directory, do you want to upload it and its contents?", filePath]]; + [alert addButtonWithTitle:@"OK"]; + [alert addButtonWithTitle:@"Cancel"]; + NSInteger choice = [alert runModal]; + if (choice == NSAlertFirstButtonReturn) { + NSString *objectName = [objectNamePrefix stringByAppendingPathComponent:[filePath lastPathComponent]]; + dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_async(queue, ^{ + NSMutableArray *objectNames = nil; + NSMutableArray *contentTypes = nil; + NSMutableArray *filePaths = nil; + NSMutableArray *hashesArrays = nil; + NSMutableArray *directoryObjectRequests = nil; + NSArray *objectRequests = [PithosFileUtilities writeObjectDataRequestsWithContainerName:containerName + objectName:objectName + blockSize:blockSize + blockHash:blockHash + forDirectory:filePath + checkIfExists:YES + objectNames:&objectNames + contentTypes:&contentTypes + filePaths:&filePaths + hashesArrays:&hashesArrays + directoryObjectRequests:&directoryObjectRequests + sharingAccount:destinationNode.sharingAccount]; + for (ASIPithosObjectRequest *objectRequest in directoryObjectRequests) { + objectRequest.delegate = self; + objectRequest.didFinishSelector = @selector(uploadDirectoryObjectFinished:); + objectRequest.didFailSelector = @selector(uploadDirectoryObjectFailed:); + [objectRequest startAsynchronous]; + } + if (objectRequests) { + for (NSUInteger i = 0 ; i < [objectRequests count] ; i++) { + ASIPithosObjectRequest *objectRequest = [objectRequests objectAtIndex:i]; objectRequest.delegate = self; objectRequest.didFinishSelector = @selector(uploadObjectUsingHashMapFinished:); objectRequest.didFailSelector = @selector(uploadObjectUsingHashMapFailed:); NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: containerName, @"containerName", - objectName, @"objectName", - contentType, @"contentType", + [objectNames objectAtIndex:i], @"objectName", + [contentTypes objectAtIndex:i], @"contentType", [NSNumber numberWithUnsignedInteger:blockSize], @"blockSize", blockHash, @"blockHash", - filePath, @"filePath", - hashes, @"hashes", - node, @"node", + [filePaths objectAtIndex:i], @"filePath", + [hashesArrays objectAtIndex:i], @"hashes", [NSNumber numberWithUnsignedInteger:10], @"iteration", nil]; - if (node.sharingAccount) - [userInfo setObject:node.sharingAccount forKey:@"sharingAccount"]; + if (destinationNode.sharingAccount) + [userInfo setObject:destinationNode.sharingAccount forKey:@"sharingAccount"]; objectRequest.userInfo = userInfo; [objectRequest startAsynchronous]; } - }); - } else { - // Upload directory, confirm first - NSAlert *alert = [[[NSAlert alloc] init] autorelease]; - [alert setMessageText:@"Upload directory"]; - [alert setInformativeText:[NSString stringWithFormat:@"'%@' is a directory, do you want to upload it and its contents?", filePath]]; - [alert addButtonWithTitle:@"OK"]; - [alert addButtonWithTitle:@"Cancel"]; - NSInteger choice = [alert runModal]; - if (choice == NSAlertFirstButtonReturn) { - NSString *objectName = [objectNamePrefix stringByAppendingPathComponent:[filePath lastPathComponent]]; - dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - dispatch_async(queue, ^{ - NSMutableArray *objectNames = nil; - NSMutableArray *contentTypes = nil; - NSMutableArray *filePaths = nil; - NSMutableArray *hashesArrays = nil; - NSMutableArray *directoryObjectRequests = nil; - NSArray *objectRequests = [PithosFileUtilities writeObjectDataRequestsWithContainerName:containerName - objectName:objectName - blockSize:blockSize - blockHash:blockHash - forDirectory:filePath - checkIfExists:YES - objectNames:&objectNames - contentTypes:&contentTypes - filePaths:&filePaths - hashesArrays:&hashesArrays - directoryObjectRequests:&directoryObjectRequests - sharingAccount:node.sharingAccount]; - for (ASIPithosObjectRequest *objectRequest in directoryObjectRequests) { - objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(uploadDirectoryObjectFinished:); - objectRequest.didFailSelector = @selector(uploadDirectoryObjectFailed:); - [objectRequest startAsynchronous]; - } - if (objectRequests) { - for (NSUInteger i = 0 ; i < [objectRequests count] ; i++) { - ASIPithosObjectRequest *objectRequest = [objectRequests objectAtIndex:i]; - objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(uploadObjectUsingHashMapFinished:); - objectRequest.didFailSelector = @selector(uploadObjectUsingHashMapFailed:); - NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: - containerName, @"containerName", - [objectNames objectAtIndex:i], @"objectName", - [contentTypes objectAtIndex:i], @"contentType", - [NSNumber numberWithUnsignedInteger:blockSize], @"blockSize", - blockHash, @"blockHash", - [filePaths objectAtIndex:i], @"filePath", - [hashesArrays objectAtIndex:i], @"hashes", - [NSNumber numberWithUnsignedInteger:10], @"iteration", - nil]; - if (node.sharingAccount) - [userInfo setObject:node.sharingAccount forKey:@"sharingAccount"]; - objectRequest.userInfo = userInfo; - [objectRequest startAsynchronous]; - } - } - }); } - } + }); } - } - return YES; } - } else if ([[[info draggingPasteboard] types] containsObject:NSFilesPromisePboardType]) { - NSLog(@"drag local operation: %lu nodes: %@", [info draggingSourceOperationMask], draggedNodes); - if ((column != -1) && (draggedNodes != nil)) { - PithosNode *dropNode = nil; - if (row != -1) - dropNode = [browser itemAtRow:row inColumn:column]; - else - dropNode = [browser parentForItemsInColumn:column]; - NSLog(@"drag local node: %@", dropNode.url); - if (([dropNode class] != [PithosSubdirNode class]) && ([dropNode class] != [PithosContainerNode class])) - return NO; - - NSString *containerName = [NSString stringWithString:dropNode.pithosContainer.name]; - NSString *objectNamePrefix; - if ([dropNode class] == [PithosSubdirNode class]) - objectNamePrefix = [NSString stringWithString:dropNode.pithosObject.name]; - else - objectNamePrefix = [NSString string]; - - if ([info draggingSourceOperationMask] & NSDragOperationMove) { - for (PithosNode *node in draggedNodes) { - 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]; - } - } - }); + } + return YES; +} + +- (BOOL)moveNodes:(NSArray *)nodes toNode:(PithosNode *)destinationNode { + if (([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class])) + return NO; + NSString *containerName = [NSString stringWithString:destinationNode.pithosContainer.name]; + NSString *objectNamePrefix; + if ([destinationNode class] == [PithosSubdirNode class]) + objectNamePrefix = [NSString stringWithString:destinationNode.pithosObject.name]; + else + objectNamePrefix = [NSString string]; + + for (PithosNode *node in nodes) { + 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", + destinationNode, @"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", + destinationNode, @"dropNode", + nil]; + [objectRequest startAsynchronous]; } } - } else if ([info draggingSourceOperationMask] & NSDragOperationCopy) { - for (PithosNode *node in draggedNodes) { - 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 - sharingAccount:nil]; - 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 - sharingAccount:nil]; - 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]; - } - } - }); + }); + } + } + return YES; +} +- (BOOL)copyNodes:(NSArray *)nodes toNode:(PithosNode *)destinationNode { + if (([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class])) + return NO; + NSString *containerName = [NSString stringWithString:destinationNode.pithosContainer.name]; + NSString *objectNamePrefix; + if ([destinationNode class] == [PithosSubdirNode class]) + objectNamePrefix = [NSString stringWithString:destinationNode.pithosObject.name]; + else + objectNamePrefix = [NSString string]; + + for (PithosNode *node in nodes) { + 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 (![destinationNode 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 + sharingAccount:nil]; + if (objectRequest) { + objectRequest.delegate = self; + objectRequest.didFinishSelector = @selector(copyFinished:); + objectRequest.didFailSelector = @selector(copyFailed:); + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + destinationNode, @"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 (![destinationNode 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 + sharingAccount:nil]; + if (objectRequests) { + for (ASIPithosObjectRequest *objectRequest in objectRequests) { + objectRequest.delegate = self; + objectRequest.didFinishSelector = @selector(copyFinished:); + objectRequest.didFailSelector = @selector(copyFailed:); + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + destinationNode, @"dropNode", + nil]; + [objectRequest startAsynchronous]; } } - } - return YES; + }); } } - return NO; + return YES; } #pragma mark - @@ -1157,6 +1197,56 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { return node; } +#pragma mark Drag and Drop destination + +- (NSDragOperation)outlineView:(NSOutlineView *)anOutlineView + validateDrop:(id)info + proposedItem:(id)item + proposedChildIndex:(NSInteger)index { + NSDragOperation result = NSDragOperationNone; + if ((item == nil) || (index != NSOutlineViewDropOnItemIndex)) + return result; + PithosNode *dropNode = (PithosNode *)item; + if ([dropNode class] != [PithosContainerNode class]) + return result; + if ([[[info draggingPasteboard] types] containsObject:NSFilenamesPboardType]) { + result = NSDragOperationCopy; + } else if ([[[info draggingPasteboard] types] containsObject:NSFilesPromisePboardType]) { + if ([info draggingSourceOperationMask] & NSDragOperationMove) { + // NSDragOperationCopy | NSDragOperationMove -> NSDragOperationMove + if (![dropNode isEqualTo:draggedParentNode]) + result = NSDragOperationMove; + } else if ([info draggingSourceOperationMask] & NSDragOperationCopy) { + // NSDragOperationCopy (Option modifier) -> NSDragOperationCopy + result = NSDragOperationCopy; + } + } + return result; +} + +- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id)info item:(id)item childIndex:(NSInteger)index { + if ([[[info draggingPasteboard] types] containsObject:NSFilenamesPboardType]) { + NSArray *filenames = [[info draggingPasteboard] propertyListForType:NSFilenamesPboardType]; + NSLog(@"drag in operation: %lu filenames: %@", [info draggingSourceOperationMask], filenames); + if (item && (index == NSOutlineViewDropOnItemIndex) && (filenames != nil)) { + PithosNode *node = (PithosNode *)item; + NSLog(@"drag in node: %@", node.url); + return [self uploadFiles:filenames toNode:node]; + } + } else if ([[[info draggingPasteboard] types] containsObject:NSFilesPromisePboardType]) { + NSLog(@"drag local operation: %lu nodes: %@", [info draggingSourceOperationMask], draggedNodes); + if (item && (index == NSOutlineViewDropOnItemIndex) && (draggedNodes != nil)) { + PithosNode *node = (PithosNode *)item; + NSLog(@"drag local node: %@", node.url); + if ([info draggingSourceOperationMask] & NSDragOperationMove) + return [self moveNodes:draggedNodes toNode:node]; + else if ([info draggingSourceOperationMask] & NSDragOperationCopy) + return [self copyNodes:draggedNodes toNode:node]; + } + } + return NO; +} + #pragma mark - #pragma mark NSOutlineViewDelegate -- 1.7.10.4