#import "PithosContainerNode.h"
#import "PithosSubdirNode.h"
#import "PithosObjectNode.h"
+#import "PithosSharingAccountsNode.h"
#import "PithosEmptyNode.h"
#import "ImageAndTextCell.h"
#import "FileSystemBrowserCell.h"
#import "ASIPithosObject.h"
#import "PithosFileUtilities.h"
-//@interface PithosBrowserCell : NSBrowserCell {}
@interface PithosBrowserCell : FileSystemBrowserCell {}
@end
- (id)init {
if ((self = [super init])) {
[self setLineBreakMode:NSLineBreakByTruncatingMiddle];
+ [self setEditable:YES];
}
return self;
}
PithosNode *node = (PithosNode *)object;
[self setStringValue:node.displayName];
[self setImage:node.icon];
-// // All cells are set as leafs because a branchingImage is already set!
-// // Maybe this cell is already inside an NSBrowserCell
-// [self setLeaf:YES];
} else {
[super setObjectValue:object];
}
@end
@interface PithosBrowserController (Private) {}
-- (void)resetContainers;
-- (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;
+- (void)resetContainers:(NSNotification *)notification;
@end
@implementation PithosBrowserController
-@synthesize outlineViewDataSourceArray, splitView, outlineView, browser;
+@synthesize verticalSplitView, horizontalSplitView, leftTopView, leftBottomView, 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];
[sharedPreviewController release];
- [outlineViewDataSourceArray release];
+ [othersSharedNode release];
+ [mySharedNode release];
+ [sharedNode release];
+ [containersNodeChildren release];
+ [containersNode release];
[accountNode release];
[rootNode release];
[super dealloc];
- (void)awakeFromNib {
[super awakeFromNib];
- [browser registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
- [browser setDraggingSourceOperationMask:NSDragOperationNone forLocal:YES];
+ [browser registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, NSFilesPromisePboardType, nil]];
+ [browser setDraggingSourceOperationMask:(NSDragOperationCopy|NSDragOperationMove) forLocal:YES];
[browser setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO];
[browser setCellClass:[PithosBrowserCell class]];
[browser setMenu:browserMenu];
}
-- (void)resetContainers {
+- (void)resetContainers:(NSNotification *)notification {
rootNode = nil;
[browser loadColumnZero];
- self.outlineViewDataSourceArray = nil;
-
- // Create the outlineView tree
- // CONTAINERS
- NSTreeNode *containersTreeNode = [NSTreeNode treeNodeWithRepresentedObject:
- [[[PithosEmptyNode alloc] initWithDisplayName:@"CONTAINERS" icon:nil] autorelease]];
-// // CONTAINERS/pithos
-// [[containersTreeNode mutableChildNodes] addObject:
-// [NSTreeNode treeNodeWithRepresentedObject:
-// [[[PithosContainerNode alloc] initWithContainerName:@"pithos"
-// icon:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kToolbarHomeIcon)]
-// ] autorelease]]];
-// // CONTAINERS/trash
-// [[containersTreeNode mutableChildNodes] addObject:
-// [NSTreeNode treeNodeWithRepresentedObject:
-// [[[PithosContainerNode alloc] initWithContainerName:@"trash"
-// icon:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kFullTrashIcon)]
-// ] autorelease]]];
- // SHARED
- NSTreeNode *sharedTreeNode = [NSTreeNode treeNodeWithRepresentedObject:
- [[[PithosEmptyNode alloc] initWithDisplayName:@"SHARED" icon:nil] autorelease]];
- // SHARED/my shared
- [[sharedTreeNode mutableChildNodes] addObject:
- [NSTreeNode treeNodeWithRepresentedObject:
- [[[PithosEmptyNode alloc] initWithDisplayName:@"my shared"
- icon:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kUserIcon)]
- ] autorelease]]];
- // SHARED/others shared
- [[sharedTreeNode mutableChildNodes] addObject:
- [NSTreeNode treeNodeWithRepresentedObject:
- [[[PithosEmptyNode alloc] initWithDisplayName:@"others shared"
- icon:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGroupIcon)]
- ] autorelease]]];
-
- self.outlineViewDataSourceArray = [NSMutableArray arrayWithObjects:containersTreeNode, sharedTreeNode, nil];
+ [containersNodeChildren removeAllObjects];
+ [outlineView reloadData];
// Expand the folder outline view
[outlineView expandItem:nil expandChildren:YES];
[outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
- // Create accountNode and trigger a refresh
- accountNode = [[PithosAccountNode alloc] init];
- accountNode.children;
+ // Refresh account
+ [accountNode refresh];
}
- (void)windowDidLoad {
[super windowDidLoad];
+ accountNode = [[PithosAccountNode alloc] init];
+ containersNode = [[PithosEmptyNode alloc] initWithDisplayName:@"CONTAINERS" icon:nil];
+ containersNodeChildren = [[NSMutableArray alloc] init];
+ sharedNode = [[PithosEmptyNode alloc] initWithDisplayName:@"SHARED" icon:nil];
+ mySharedNode = [[PithosAccountNode alloc] init];
+ mySharedNode.displayName = @"my shared";
+ mySharedNode.shared = YES;
+ mySharedNode.icon = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kUserIcon)];
+ othersSharedNode = [[PithosSharingAccountsNode alloc] init];
+ othersSharedNode.displayName = @"others shared";
+ othersSharedNode.icon = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGroupIcon)];
+
[[[outlineView tableColumns] objectAtIndex:0] setDataCell:[[[PithosOutlineViewCell alloc] init] autorelease]];
// Register for updates
+ // PithosContainerNode updates browser nodes
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(pithosNodeChildrenUpdated:)
name:@"PithosContainerNodeChildrenUpdated"
object:nil];
+ // PithosSubdirNode updates browser nodes
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(pithosNodeChildrenUpdated:)
name:@"PithosSubdirNodeChildrenUpdated"
object:nil];
+ // PithosAccountNode accountNode updates outlineView container nodes
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(pithosAccountNodeChildrenUpdated:)
name:@"PithosAccountNodeChildrenUpdated"
+ object:accountNode];
+ // PithosAccountNode other than accountNode updates nodes
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(pithosNodeChildrenUpdated:)
+ name:@"PithosAccountNodeChildrenUpdated"
object:nil];
+ // PithosSharingAccountsNode othersSharedNode updates browser nodes
[[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(resetContainers)
+ selector:@selector(pithosNodeChildrenUpdated:)
+ name:@"PithosSharingAccountsNodeChildrenUpdated"
+ object:othersSharedNode];
+ // Updated authentication credentials reset containers in the outline view
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(resetContainers:)
name:@"PithosAuthenticationCredentialsUpdated"
object:nil];
+ // Request for browser refresh
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(pithosBrowserRefreshNeeded:)
+ name:@"PithosBrowserRefreshNeeeded"
+ object:nil];
}
#pragma mark -
-#pragma Observers
+#pragma mark Observers
- (void)pithosNodeChildrenUpdated:(NSNotification *)notification {
PithosNode *node = (PithosNode *)[notification object];
+ if (node == accountNode)
+ return;
+ NSLog(@"pithosNodeChildrenUpdated:%@", node.url);
NSInteger lastColumn = [browser lastColumn];
for (NSInteger column = lastColumn; column >= 0; column--) {
if ([[browser parentForItemsInColumn:column] isEqualTo:node]) {
[browser reloadColumn:column];
- if ((column == lastColumn - 1) && ([[browser parentForItemsInColumn:lastColumn] isLeafItem])) {
- // This reloads the preview column
- [browser setLastColumn:column];
- [browser addColumn];
- }
return;
}
}
- (void)pithosAccountNodeChildrenUpdated:(NSNotification *)notification {
BOOL containerPithosFound = NO;
BOOL containerTrashFound = NO;
- //NSMutableArray *containersTreeNodeChildren = [[outlineViewDataSourceArray objectAtIndex:0] mutableChildNodes];
- NSMutableArray *containersTreeNodeChildren = [NSMutableArray array];
+ NSMutableIndexSet *removedContainersNodeChildren = [NSMutableIndexSet indexSet];
+ for (NSUInteger i = 0 ; i < [containersNodeChildren count] ; i++) {
+ if (![accountNode.children containsObject:[containersNodeChildren objectAtIndex:i]])
+ [removedContainersNodeChildren addIndex:i];
+ }
+ [containersNodeChildren removeObjectsAtIndexes:removedContainersNodeChildren];
for (PithosContainerNode *containerNode in accountNode.children) {
if ([containerNode.pithosContainer.name isEqualToString:@"pithos"]) {
- containerNode.icon = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kToolbarHomeIcon)];
- [containersTreeNodeChildren insertObject:[NSTreeNode treeNodeWithRepresentedObject:containerNode] atIndex:0];
+ if (![containersNodeChildren containsObject:containerNode])
+ [containersNodeChildren insertObject:containerNode atIndex:0];
containerPithosFound = YES;
} else if ([containerNode.pithosContainer.name isEqualToString:@"trash"]) {
- containerNode.icon = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kFullTrashIcon)];
NSUInteger insertIndex = 1;
if (!containerPithosFound)
insertIndex = 0;
- [containersTreeNodeChildren insertObject:[NSTreeNode treeNodeWithRepresentedObject:containerNode] atIndex:insertIndex];
+ if (![containersNodeChildren containsObject:containerNode])
+ [containersNodeChildren insertObject:containerNode atIndex:insertIndex];
containerTrashFound = YES;
- } else {
- [containersTreeNodeChildren addObject:[NSTreeNode treeNodeWithRepresentedObject:containerNode]];
+ } else if (![containersNodeChildren containsObject:containerNode]) {
+ [containersNodeChildren addObject:containerNode];
}
}
BOOL refreshAccountNode = NO;
if (!containerPithosFound) {
- // create pithos
+ // Create pithos node
ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithContainerName:@"pithos"];
[containerRequest startSynchronous];
if ([containerRequest error]) {
- NSLog(@"error:%@", [containerRequest error]);
- // XXX do something on error
+ [PithosFileUtilities httpRequestErrorAlertWithRequest:containerRequest];
} else {
refreshAccountNode = YES;
}
}
if (!containerTrashFound) {
- // create trash
+ // Create trash node
ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithContainerName:@"trash"];
[containerRequest startSynchronous];
if ([containerRequest error]) {
- NSLog(@"error:%@", [containerRequest error]);
- // XXX do something on error
+ [PithosFileUtilities httpRequestErrorAlertWithRequest:containerRequest];
} else {
refreshAccountNode = YES;
}
}
- if (refreshAccountNode) {
- [accountNode invalidateChildren];
- accountNode.children;
- } else {
- [[[outlineViewDataSourceArray objectAtIndex:0] mutableChildNodes] setArray:containersTreeNodeChildren];
- self.outlineViewDataSourceArray = outlineViewDataSourceArray;
-
- // Expand the folder outline view
- [outlineView expandItem:nil expandChildren:YES];
- [outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
-
- [self refresh:nil];
+
+ if (refreshAccountNode)
+ [accountNode refresh];
+
+ [outlineView reloadData];
+
+ // Expand the folder outline view
+ [outlineView expandItem:nil expandChildren:YES];
+
+ if ((rootNode == containersNode) || (rootNode == sharedNode)) {
+ rootNode = [containersNodeChildren objectAtIndex:0];
+ [browser loadColumnZero];
}
+
+ if (notification)
+ [self refresh:nil];
+}
+
+- (void)pithosBrowserRefreshNeeded:(NSNotification *)notification {
+ [self refresh:nil];
}
#pragma mark -
-#pragma Actions
+#pragma mark Actions
- (IBAction)refresh:(id)sender {
+ if (sender)
+ [accountNode refresh];
for (NSInteger column = [browser lastColumn]; column >= 0; column--) {
[(PithosNode *)[browser parentForItemsInColumn:column] invalidateChildren];
}
}
#pragma mark -
-#pragma NSBrowserDelegate
+#pragma mark NSBrowserDelegate
- (id)rootItemForBrowser:(NSBrowser *)browser {
return rootNode;
return NO;
}
+#pragma mark Editing
+
+- (BOOL)browser:(NSBrowser *)browser shouldEditItem:(id)item {
+ PithosNode *node = (PithosNode *)item;
+ if (node.shared || node.sharingAccount ||
+ ([node class] == [PithosContainerNode class]) || ([node class] == [PithosAccountNode class]))
+ return NO;
+ return YES;
+}
+
+- (void)browser:(NSBrowser *)browser setObjectValue:(id)object forItem:(id)item {
+ PithosNode *node = (PithosNode *)item;
+ NSString *newName = (NSString *)object;
+ NSUInteger newNameLength = [newName length];
+ NSRange firstSlashRange = [newName rangeOfString:@"/"];
+ if ((newNameLength == 0) ||
+ ((firstSlashRange.length == 1) && (firstSlashRange.location != (newNameLength - 1))) ||
+ ([newName isEqualToString:node.displayName])) {
+ return;
+ }
+ 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 = [[node.pithosObject.name stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName];
+ if ([newName hasSuffix:@"/"])
+ destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
+ NSError *error = nil;
+ BOOL isDirectory;
+ if ([PithosFileUtilities objectExistsAtContainerName:node.pithosContainer.name
+ objectName:destinationObjectName
+ error:&error
+ isDirectory:&isDirectory]) {
+ NSAlert *alert = [[[NSAlert alloc] init] autorelease];
+ [alert setMessageText:@"Name Taken"];
+ [alert setInformativeText:[NSString stringWithFormat:@"The name '%@' is already taken. Please choose a different name", newName]];
+ [alert addButtonWithTitle:@"OK"];
+ [alert runModal];
+ return;
+ } else if (error) {
+ return;
+ }
+ ASIPithosObjectRequest *objectRequest = [PithosFileUtilities moveObjectRequestWithContainerName:node.pithosContainer.name
+ objectName:node.pithosObject.name
+ destinationContainerName:node.pithosContainer.name
+ destinationObjectName:destinationObjectName
+ checkIfExists:NO];
+ if (objectRequest) {
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(moveFinished:);
+ objectRequest.didFailSelector = @selector(moveFailed:);
+ objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ node.parent, @"node",
+ nil];
+ [objectRequest startAsynchronous];
+ }
+ });
+ } else if ([node class] == [PithosSubdirNode class]) {
+ if (firstSlashRange.length == 1)
+ return;
+ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_async(queue, ^{
+ NSString *destinationObjectName = [[node.pithosObject.name stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName];
+ NSError *error = nil;
+ BOOL isDirectory;
+ if ([PithosFileUtilities objectExistsAtContainerName:node.pithosContainer.name
+ objectName:destinationObjectName
+ error:&error
+ isDirectory:&isDirectory]) {
+ NSAlert *alert = [[[NSAlert alloc] init] autorelease];
+ [alert setMessageText:@"Name Taken"];
+ [alert setInformativeText:[NSString stringWithFormat:@"The name '%@' is already taken. Please choose a different name", newName]];
+ [alert addButtonWithTitle:@"OK"];
+ [alert runModal];
+ return;
+ } else if (error) {
+ return;
+ }
+ if (node.pithosObject.subdir)
+ destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
+ NSArray *objectRequests = [PithosFileUtilities moveObjectRequestsForSubdirWithContainerName:node.pithosContainer.name
+ objectName:node.pithosObject.name
+ destinationContainerName:node.pithosContainer.name
+ destinationObjectName:destinationObjectName
+ checkIfExists:NO];
+ 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",
+ nil];
+ [objectRequest startAsynchronous];
+ }
+ }
+ });
+ }
+}
+
#pragma mark Drag and Drop source
+- (BOOL)browser:(NSBrowser *)aBrowser canDragRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column
+ withEvent:(NSEvent *)event {
+ NSIndexPath *baseIndexPath = [browser indexPathForColumn:column];
+ __block BOOL result = YES;
+ [rowIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop){
+ PithosNode *node = [browser itemAtIndexPath:[baseIndexPath indexPathByAddingIndex:idx]];
+ if ([node class] == [PithosContainerNode class]) {
+ result = NO;
+ *stop = YES;
+ }
+ }];
+ return result;
+}
+
- (BOOL)browser:(NSBrowser *)aBrowser writeRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column
toPasteboard:(NSPasteboard *)pasteboard {
NSMutableArray *propertyList = [NSMutableArray arrayWithCapacity:[rowIndexes count]];
- NSIndexPath *baseIndexPath = [browser indexPathForColumn:column];
- for (NSUInteger i = [rowIndexes firstIndex]; i <= [rowIndexes lastIndex]; i = [rowIndexes indexGreaterThanIndex:i]) {
- PithosNode *node = [browser itemAtIndexPath:[baseIndexPath indexPathByAddingIndex:i]];
+ NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:[rowIndexes count]];
+ NSIndexPath *baseIndexPath = [browser indexPathForColumn:column];
+ [rowIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop){
+ PithosNode *node = [browser itemAtIndexPath:[baseIndexPath indexPathByAddingIndex:idx]];
[propertyList addObject:[node.pithosObject.name pathExtension]];
- }
+ [nodes addObject:node];
+ }];
[pasteboard declareTypes:[NSArray arrayWithObject:NSFilesPromisePboardType] owner:self];
[pasteboard setPropertyList:propertyList forType:NSFilesPromisePboardType];
-
+ self.draggedNodes = nodes;
+ self.draggedParentNode = [browser parentForItemsInColumn:column];
return YES;
}
- (NSArray *)browser:(NSBrowser *)aBrowser namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
NSMutableArray *names = [NSMutableArray arrayWithCapacity:[rowIndexes count]];
- NSIndexPath *baseIndexPath = [browser indexPathForColumn:column];
- for (NSUInteger i = [rowIndexes firstIndex]; i <= [rowIndexes lastIndex]; i = [rowIndexes indexGreaterThanIndex:i]) {
- PithosNode *node = [browser itemAtIndexPath:[baseIndexPath indexPathByAddingIndex:i]];
+ NSIndexPath *baseIndexPath = [browser indexPathForColumn:column];
+ [rowIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop){
+ PithosNode *node = [browser itemAtIndexPath:[baseIndexPath indexPathByAddingIndex:idx]];
// If the node is a subdir ask if the whole tree should be downloaded
if ([node class] == [PithosSubdirNode class]) {
[alert addButtonWithTitle:@"Cancel"];
NSInteger choice = [alert runModal];
if (choice == NSAlertFirstButtonReturn) {
- NSArray *objectRequests = [PithosFileUtilities objectDataRequestsForSubdirWithContainerName:node.pithosContainer.name
- objectName:node.pithosObject.name
- toDirectory:[dropDestination path]
- checkIfExists:YES];
- if (objectRequests) {
- for (ASIPithosObjectRequest *objectRequest in objectRequests) {
- [names addObject:[objectRequest.userInfo valueForKey:@"fileName"]];
- objectRequest.delegate = self;
- objectRequest.didFinishSelector = @selector(downloadObjectFinished:);
- objectRequest.didFailSelector = @selector(downloadObjectFailed:);
- [objectRequest startAsynchronous];
+ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_async(queue, ^{
+ NSArray *objectRequests = [PithosFileUtilities objectDataRequestsForSubdirWithContainerName:node.pithosContainer.name
+ objectName:node.pithosObject.name
+ toDirectory:[dropDestination path]
+ checkIfExists:YES
+ sharingAccount:node.sharingAccount];
+ if (objectRequests) {
+ for (ASIPithosObjectRequest *objectRequest in objectRequests) {
+ [names addObject:[objectRequest.userInfo valueForKey:@"fileName"]];
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(downloadObjectFinished:);
+ objectRequest.didFailSelector = @selector(downloadObjectFailed:);
+ [objectRequest startAsynchronous];
+ }
}
- }
+ });
}
} else {
ASIPithosObjectRequest *objectRequest = [PithosFileUtilities objectDataRequestWithContainerName:node.pithosContainer.name
objectName:node.pithosObject.name
toDirectory:[dropDestination path]
- checkIfExists:YES];
+ checkIfExists:YES
+ sharingAccount:node.sharingAccount];
if (objectRequest) {
[names addObject:[objectRequest.userInfo valueForKey:@"fileName"]];
objectRequest.delegate = self;
[objectRequest startAsynchronous];
}
}
- }
+ }];
return names;
}
column:(NSInteger *)column
dropOperation:(NSBrowserDropOperation *)dropOperation {
NSDragOperation result = NSDragOperationNone;
- // Files from the finder are accepted
- if ([[[info draggingPasteboard] types] indexOfObject:NSFilenamesPboardType] != -1) {
- // For a between drop, we let the user drop "on" the parent item
+ if ([[[info draggingPasteboard] types] containsObject:NSFilenamesPboardType]) {
+ // For a drop above, the drop is redirected to the parent item
if (*dropOperation == NSBrowserDropAbove)
*row = -1;
// Only allow dropping in folders
if (*column != -1) {
+ PithosNode *dropNode;
if (*row != -1) {
- PithosNode *node = [browser itemAtRow:*row inColumn:*column];
- if ([node class] != [PithosSubdirNode class])
+ // Check if the node is not a folder and if so redirect to the parent item
+ dropNode = [browser itemAtRow:*row inColumn:*column];
+ if ([dropNode class] != [PithosSubdirNode class])
*row = -1;
}
- *dropOperation = NSBrowserDropOn;
- result = NSDragOperationCopy;
+ if (*row == -1)
+ dropNode = [browser parentForItemsInColumn:*column];
+
+ if (!dropNode.shared && !dropNode.sharingAccount) {
+ *dropOperation = NSBrowserDropOn;
+ result = NSDragOperationCopy;
+ }
+ }
+ } else if ([[[info draggingPasteboard] types] containsObject:NSFilesPromisePboardType]) {
+ // For a drop above, the drop is redirected to the parent item
+ if (*dropOperation == NSBrowserDropAbove)
+ *row = -1;
+ // Only allow dropping in folders
+ if (*column != -1) {
+ PithosNode *dropNode;
+ if (*row != -1) {
+ // Check if the node is not a folder and if so redirect to the parent item
+ dropNode = [browser itemAtRow:*row inColumn:*column];
+ if ([dropNode class] != [PithosSubdirNode class])
+ *row = -1;
+ }
+ if (*row == -1)
+ dropNode = [browser parentForItemsInColumn:*column];
+
+ if (!dropNode.shared && !dropNode.sharingAccount) {
+ if ([info draggingSourceOperationMask] & NSDragOperationMove) {
+ // NSDragOperationCopy | NSDragOperationMove -> NSDragOperationMove
+ if ((([dropNode class] == [PithosContainerNode class]) ||
+ dropNode.pithosObject.subdir ||
+ ![dropNode.pithosObject.name hasSuffix:@"/"]) &&
+ ![dropNode isEqualTo:draggedParentNode]) {
+ // ![dropNode isEqualTo:draggedParentNode] &&
+ // ![draggedNodes containsObject:dropNode]) {
+ result = NSDragOperationMove;
+ }
+ } else if ([info draggingSourceOperationMask] & NSDragOperationCopy) {
+ // NSDragOperationCopy (Option modifier) -> NSDragOperationCopy
+ if (([dropNode class] == [PithosContainerNode class]) ||
+ dropNode.pithosObject.subdir ||
+ ![dropNode.pithosObject.name hasSuffix:@"/"]) {
+ result = NSDragOperationCopy;
+ }
+ }
+ }
}
}
- // XXX else local file promises
return result;
}
atRow:(NSInteger)row
column:(NSInteger)column
dropOperation:(NSBrowserDropOperation)dropOperation {
- NSArray *filenames = [[info draggingPasteboard] propertyListForType:NSFilenamesPboardType];
- NSLog(@"drag in filenames: %@", filenames);
- PithosNode *node = nil;
- if ((column != -1) && (filenames != nil)) {
- if (row != -1)
- node = [browser itemAtRow:row inColumn: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];
- else
- objectNamePrefix = [NSString stringWithString:@""];
- 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/binary";
- 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];
- if (objectRequest) {
- objectRequest.delegate = self;
- objectRequest.didFinishSelector = @selector(uploadObjectUsingHashMapFinished:);
- objectRequest.didFailSelector = @selector(uploadObjectUsingHashMapFailed:);
- objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
- containerName, @"containerName",
- objectName, @"objectName",
- contentType, @"contentType",
- [NSNumber numberWithUnsignedInteger:blockSize], @"blockSize",
- blockHash, @"blockHash",
- filePath, @"filePath",
- hashes, @"hashes",
- node, @"node",
- [NSNumber numberWithUnsignedInteger:10], @"iteration",
- nil];
- [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) {
+ if ([[[info draggingPasteboard] types] containsObject:NSFilenamesPboardType]) {
+ NSArray *filenames = [[info draggingPasteboard] propertyListForType:NSFilenamesPboardType];
+ NSLog(@"drag in operation: %lu filenames: %@", [info draggingSourceOperationMask], filenames);
+ if ((column != -1) && (filenames != nil)) {
+ PithosNode *node = nil;
+ if (row != -1)
+ node = [browser itemAtRow:row inColumn: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];
+ 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, ^{
- NSMutableArray *objectNames = nil;
- NSMutableArray *contentTypes = nil;
- NSMutableArray *filePaths = nil;
- NSMutableArray *hashesArrays = nil;
- NSArray *objectRequests = [PithosFileUtilities writeObjectDataRequestsWithContainerName:containerName
- objectName:objectName
- blockSize:blockSize
- blockHash:blockHash
- forDirectory:filePath
- checkIfExists:YES
- objectNames:&objectNames
- contentTypes:&contentTypes
- filePaths:&filePaths
- hashesArrays:&hashesArrays];
+ 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];
+ if (objectRequest) {
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(uploadObjectUsingHashMapFinished:);
+ objectRequest.didFailSelector = @selector(uploadObjectUsingHashMapFailed:);
+ objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ containerName, @"containerName",
+ objectName, @"objectName",
+ contentType, @"contentType",
+ [NSNumber numberWithUnsignedInteger:blockSize], @"blockSize",
+ blockHash, @"blockHash",
+ filePath, @"filePath",
+ hashes, @"hashes",
+ node, @"node",
+ [NSNumber numberWithUnsignedInteger:10], @"iteration",
+ nil];
+ [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];
+ 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:);
+ objectRequest.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];
+ [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 (NSUInteger i = 0 ; i < [objectRequests count] ; i++) {
- ASIPithosObjectRequest *objectRequest = [objectRequests objectAtIndex:i];
- // XXX if dir creation requests differentiate
+ for (ASIPithosObjectRequest *objectRequest in objectRequests) {
objectRequest.delegate = self;
- objectRequest.didFinishSelector = @selector(uploadObjectUsingHashMapFinished:);
- objectRequest.didFailSelector = @selector(uploadObjectUsingHashMapFailed:);
+ objectRequest.didFinishSelector = @selector(moveFinished:);
+ objectRequest.didFailSelector = @selector(moveFailed:);
objectRequest.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",
- [NSNull null], @"node",
- [NSNumber numberWithUnsignedInteger:10], @"iteration",
+ node.parent, @"node",
+ dropNode, @"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;
}
- return YES;
}
-
return NO;
}
- (void)downloadObjectFinished:(ASIPithosObjectRequest *)objectRequest {
NSLog(@"Download completed: %@", [objectRequest url]);
- if ([objectRequest bytes] == 0) {
- NSLog(@"Downloaded 0 bytes");
- NSFileManager *defaultManager = [NSFileManager defaultManager];
- NSString *filePath = [objectRequest.userInfo objectForKey:@"filePath"];
- if (![defaultManager fileExistsAtPath:filePath]) {
- if (![defaultManager createFileAtPath:filePath contents:nil attributes:nil]) {
- NSAlert *alert = [[[NSAlert alloc] init] autorelease];
- [alert setMessageText:@"Create File Error"];
- [alert setInformativeText:[NSString stringWithFormat:@"Cannot create zero length file at %@", filePath]];
- [alert addButtonWithTitle:@"OK"];
- [alert runModal];
+ if (objectRequest.responseStatusCode == 200) {
+ if (([objectRequest contentLength] == 0) && (![[objectRequest contentType] isEqualToString:@"application/directory"])) {
+ NSLog(@"Downloaded 0 bytes");
+ NSFileManager *defaultManager = [NSFileManager defaultManager];
+ NSString *filePath = [objectRequest.userInfo objectForKey:@"filePath"];
+ if (![defaultManager fileExistsAtPath:filePath]) {
+ if (![defaultManager createFileAtPath:filePath contents:nil attributes:nil]) {
+ NSAlert *alert = [[[NSAlert alloc] init] autorelease];
+ [alert setMessageText:@"Create File Error"];
+ [alert setInformativeText:[NSString stringWithFormat:@"Cannot create zero length file at %@", filePath]];
+ [alert addButtonWithTitle:@"OK"];
+ [alert runModal];
+ }
}
}
+ } else {
+ [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
}
}
[PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
}
+- (void)uploadDirectoryObjectFinished:(ASIPithosObjectRequest *)objectRequest {
+ NSLog(@"Upload directory object completed: %@", [objectRequest url]);
+ if (objectRequest.responseStatusCode == 201) {
+ NSLog(@"Directory object created: %@", [objectRequest url]);
+ [self refresh:nil];
+ } else {
+ [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+ }
+}
+
+- (void)uploadDirectoryObjectFailed:(ASIPithosObjectRequest *)objectRequest {
+ NSLog(@"Upload directory object failed");
+ [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
+}
+
- (void)uploadObjectUsingHashMapFinished:(ASIPithosObjectRequest *)objectRequest {
NSLog(@"Upload using hashmap completed: %@", [objectRequest url]);
if (objectRequest.responseStatusCode == 201) {
NSLog(@"Object created: %@", [objectRequest url]);
PithosNode *node = [objectRequest.userInfo objectForKey:@"node"];
- if (node != (id)[NSNull null]) {
- [node invalidateChildren];
- node.children;
- } // XXX else total refresh?
+ if (node)
+ [node refresh];
+ else
+ [self refresh:nil];
} else if (objectRequest.responseStatusCode == 409) {
NSUInteger iteration = [[objectRequest.userInfo objectForKey:@"iteration"] unsignedIntegerValue] - 1;
if (iteration == 0) {
NSUInteger missingBlockIndex = [missingBlocks firstIndex];
ASIPithosObjectRequest *newObjectRequest = [PithosFileUtilities updateObjectDataRequestWithContainerName:[objectRequest.userInfo objectForKey:@"containerName"]
objectName:@".upload"
- contentType:[objectRequest.userInfo objectForKey:@"contentType"]
blockSize:[[objectRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue]
forFile:[objectRequest.userInfo objectForKey:@"filePath"]
missingBlockIndex:missingBlockIndex];
} else {
ASIPithosObjectRequest *newObjectRequest = [PithosFileUtilities updateObjectDataRequestWithContainerName:[objectRequest.userInfo objectForKey:@"containerName"]
objectName:@".upload"
- contentType:[objectRequest.userInfo objectForKey:@"contentType"]
blockSize:[[objectRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue]
forFile:[objectRequest.userInfo objectForKey:@"filePath"]
missingBlockIndex:missingBlockIndex];
[PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
}
+- (void)moveFinished:(ASIPithosObjectRequest *)objectRequest {
+ NSLog(@"Move object completed: %@", [objectRequest url]);
+ if (objectRequest.responseStatusCode == 201) {
+ PithosNode *node = [objectRequest.userInfo objectForKey:@"node"];
+ PithosNode *dropNode = [objectRequest.userInfo objectForKey:@"dropNode"];
+ if (node)
+ [node refresh];
+ if (dropNode)
+ [dropNode refresh];
+ if (!node || !dropNode)
+ [self refresh:nil];
+ } else {
+ [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+ }
+}
+
+- (void)moveFailed:(ASIPithosObjectRequest *)objectRequest {
+ NSLog(@"Move object failed");
+ [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
+}
+
+- (void)copyFinished:(ASIPithosObjectRequest *)objectRequest {
+ NSLog(@"Copy object completed: %@", [objectRequest url]);
+ if (objectRequest.responseStatusCode == 201) {
+ PithosNode *dropNode = [objectRequest.userInfo objectForKey:@"dropNode"];
+ if (dropNode)
+ [dropNode refresh];
+ else
+ [self refresh:nil];
+ } else {
+ [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+ }
+}
+
+- (void)copyFailed:(ASIPithosObjectRequest *)objectRequest {
+ NSLog(@"Copy object failed");
+ [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
+}
+
#pragma mark -
#pragma mark NSSplitViewDelegate
- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
- return 120;
+ if (splitView == verticalSplitView)
+ return 120;
+ else
+ return ([horizontalSplitView bounds].size.height - 87);
}
- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex {
- return 220;
+ if (splitView == verticalSplitView)
+ return 220;
+ else
+ return ([horizontalSplitView bounds].size.height - 87);
+}
+
+- (CGFloat)splitView:(NSSplitView *)splitView constrainSplitPosition:(CGFloat)proposedPosition ofSubviewAt:(NSInteger)dividerIndex {
+ if (splitView == verticalSplitView) {
+ if (proposedPosition < 120)
+ return 120;
+ else if (proposedPosition > 220)
+ return 220;
+ else
+ return proposedPosition;
+ } else {
+ return ([horizontalSplitView bounds].size.height - 87);
+ }
+}
+
+#pragma mark -
+#pragma mark NSOutlineViewDataSource
+
+- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
+ if (item == nil)
+ return 2;
+ if (item == containersNode)
+ return containersNodeChildren.count;
+ if (item == sharedNode)
+ return 2;
+ return 0;
+}
+
+- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
+ if (item == nil)
+ return (!index ? containersNode : sharedNode);
+ if (item == sharedNode)
+ return (!index ? mySharedNode : othersSharedNode);
+ return [containersNodeChildren objectAtIndex:index];
+}
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
+ if ((item == containersNode) || (item == sharedNode))
+ return YES;
+ return NO;
+}
+
+- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
+ PithosNode *node = (PithosNode *)item;
+ return node;
}
#pragma mark -
#pragma mark NSOutlineViewDelegate
- (BOOL)outlineView:outlineView shouldSelectItem:(id)item {
- return ([[item representedObject] isLeaf]);
+ if ((item == containersNode) || (item == sharedNode))
+ return NO;
+ return YES;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item {
- return (![[item representedObject] isLeaf]);
+ if ((item == containersNode) || (item == sharedNode))
+ return YES;
+ return NO;
}
- (void)outlineViewSelectionDidChange:(NSNotification *)notification {
- PithosNode *node = [[[outlineView itemAtRow:[outlineView selectedRow]] representedObject] representedObject];
+ PithosNode *node = (PithosNode *)[outlineView itemAtRow:[outlineView selectedRow]];
if (node) {
rootNode = node;
[browser loadColumnZero];
+ [self refresh:nil];
}
}
NSInteger column = [browser clickedColumn];
NSInteger row = [browser clickedRow];
[menu removeAllItems];
+ NSMenuItem *menuItem;
+ NSString *menuItemTitle;
if ((column == -1) || (row == -1)) {
- // General context menu has 0
- } else {
- // PithosNode menu has 1 items
+ // General context menu
+ NSArray *menuNodesIndexPaths = [browser selectionIndexPaths];
+ PithosNode *menuNode;
+ if ([menuNodesIndexPaths count] == 0) {
+ menuNode = [browser parentForItemsInColumn:0];
+ } else if (([menuNodesIndexPaths count] != 1) ||
+ ([[browser itemAtIndexPath:[menuNodesIndexPaths objectAtIndex:0]] class] == [PithosObjectNode class])) {
+ menuNode = [browser parentForItemsInColumn:([[menuNodesIndexPaths objectAtIndex:0] length] - 1)];
+ } else {
+ menuNode = [browser itemAtIndexPath:[menuNodesIndexPaths objectAtIndex:0]];
+ }
+ if (([menuNode class] == [PithosAccountNode class]) || ([menuNode class] == [PithosSharingAccountsNode class]))
+ return;
+ BOOL shared = menuNode.shared;
+ BOOL sharingAccount = (menuNode.sharingAccount != nil);
+
+ if (!shared && !sharingAccount) {
+ // New Folder
+ menuItem = [[[NSMenuItem alloc] initWithTitle:@"New Folder" action:@selector(menuNewFolder:) keyEquivalent:@""] autorelease];
+ [menuItem setRepresentedObject:menuNode];
+ [menu addItem:menuItem];
+ [menu addItem:[NSMenuItem separatorItem]];
+ }
+
// Get Info
- NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:@"Get Info" action:@selector(getInfo:) keyEquivalent:@""];
- [menuItem setRepresentedObject:[browser itemAtRow:row inColumn:column]];
+ menuItem = [[[NSMenuItem alloc] initWithTitle:@"Get Info" action:@selector(menuGetInfo:) keyEquivalent:@""] autorelease];
+ [menuItem setRepresentedObject:[NSArray arrayWithObject:menuNode]];
[menu addItem:menuItem];
+
+ if (!shared && !sharingAccount) {
+ // 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];
+ NSArray *menuNodesIndexPaths = [browser selectionIndexPaths];
+ NSMutableArray *menuNodes = [NSMutableArray arrayWithCapacity:[menuNodesIndexPaths count]];
+ if ([menuNodesIndexPaths containsObject:clickedNodeIndexPath]) {
+ for (NSIndexPath *nodeIndexPath in menuNodesIndexPaths) {
+ [menuNodes addObject:[browser itemAtIndexPath:nodeIndexPath]];
+ }
+ } else {
+ [menuNodes addObject:[browser itemAtIndexPath:clickedNodeIndexPath]];
+ }
+ NSUInteger menuNodesCount = [menuNodes count];
+ PithosNode *firstMenuNode = (PithosNode *)[menuNodes objectAtIndex:0];
+ BOOL shared = firstMenuNode.shared;
+ BOOL sharingAccount = (firstMenuNode.sharingAccount != nil);
+
+ if (!shared && !sharingAccount) {
+ // 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(menuMoveToTrash:) keyEquivalent:@""] autorelease];
+ [menuItem setRepresentedObject:menuNodes];
+ [menu addItem:menuItem];
+ }
+ menuItem = [[[NSMenuItem alloc] initWithTitle:@"Delete" action:@selector(menuDelete:) keyEquivalent:@""] autorelease];
+ [menuItem setRepresentedObject:menuNodes];
+ [menu addItem:menuItem];
+ [menu addItem:[NSMenuItem separatorItem]];
+ }
+ }
+
+ if (!sharingAccount || ([firstMenuNode class] != [PithosAccountNode class])) {
+ // Get Info
+ menuItem = [[[NSMenuItem alloc] initWithTitle:@"Get Info" action:@selector(menuGetInfo:) keyEquivalent:@""] autorelease];
+ [menuItem setRepresentedObject:menuNodes];
+ [menu addItem:menuItem];
+
+ if ((!shared && !sharingAccount) || ([firstMenuNode class] != [PithosContainerNode class]))
+ [menu addItem:[NSMenuItem separatorItem]];
+ }
+
+ if (!shared && !sharingAccount) {
+ // Cut
+
+ 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];
+ }
+
+ if ((!shared && !sharingAccount) ||
+ (([firstMenuNode class] != [PithosContainerNode class]) && ([firstMenuNode class] != [PithosAccountNode class]))) {
+ // 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];
+ }
+
+ if (!shared && !sharingAccount) {
+ // 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)getInfo:(NSMenuItem *)sender {
- [(PithosNode *)[sender representedObject] showPithosNodeInfo:sender];
+- (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)menuGetInfo:(NSMenuItem *)sender {
+ for (PithosNode *node in ((NSArray *)[sender representedObject])) {
+ [node showPithosNodeInfo:sender];
+ }
+}
+
+- (void)menuDelete:(NSMenuItem *)sender {
+ for (PithosNode *node in ((NSArray *)[sender representedObject])) {
+ if (([node class] == [PithosObjectNode class]) ||
+ (([node class] == [PithosSubdirNode class]) &&
+ !node.pithosObject.subdir &&
+ [node.pithosObject.name hasSuffix:@"/"])) {
+ ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest deleteObjectRequestWithContainerName:node.pithosContainer.name
+ objectName:node.pithosObject.name];
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(deleteObjectFinished:);
+ objectRequest.didFailSelector = @selector(deleteObjectFailed:);
+ [objectRequest startAsynchronous];
+ } else if ([node class] == [PithosSubdirNode class]) {
+ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_async(queue, ^{
+ NSArray *objectRequests = [PithosFileUtilities deleteObjectRequestsForSubdirWithContainerName:node.pithosContainer.name
+ objectName:node.pithosObject.name];
+ if (objectRequests) {
+ for (ASIPithosObjectRequest *objectRequest in objectRequests) {
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(deleteObjectFinished:);
+ objectRequest.didFailSelector = @selector(deleteObjectFailed:);
+ [objectRequest startAsynchronous];
+ }
+ }
+ });
+ }
+ }
+}
+
+- (void)menuMoveToTrash:(NSMenuItem *)sender {
+ for (PithosNode *node in ((NSArray *)[sender representedObject])) {
+ 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 *safeObjectName = [PithosFileUtilities safeObjectNameForContainerName:@"trash"
+ objectName:node.pithosObject.name];
+ if (safeObjectName) {
+ ASIPithosObjectRequest *objectRequest = [PithosFileUtilities moveObjectRequestWithContainerName:node.pithosContainer.name
+ objectName:node.pithosObject.name
+ destinationContainerName:@"trash"
+ destinationObjectName:safeObjectName
+ checkIfExists:NO];
+ if (objectRequest) {
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(moveToTrashFinished:);
+ objectRequest.didFailSelector = @selector(moveToTrashFailed:);
+ [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 *safeObjectName = [PithosFileUtilities safeSubdirNameForContainerName:@"trash"
+ subdirName:node.pithosObject.name];
+ if (safeObjectName) {
+ NSArray *objectRequests = [PithosFileUtilities moveObjectRequestsForSubdirWithContainerName:node.pithosContainer.name
+ objectName:node.pithosObject.name
+ destinationContainerName:@"trash"
+ destinationObjectName:safeObjectName
+ checkIfExists:NO];
+ if (objectRequests) {
+ for (ASIPithosObjectRequest *objectRequest in objectRequests) {
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(moveToTrashFinished:);
+ objectRequest.didFailSelector = @selector(moveToTrashFailed:);
+ [objectRequest startAsynchronous];
+ }
+ }
+ }
+ });
+ }
+ }
+}
+
+- (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
+ sharingAccount:node.sharingAccount];
+ 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:node.sharingAccount];
+ 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
+
+- (void)newFolderFinished:(ASIPithosObjectRequest *)objectRequest {
+ if (objectRequest.responseStatusCode == 201) {
+ NSLog(@"New application/directory object created: %@", [objectRequest url]);
+ PithosNode *node = [objectRequest.userInfo objectForKey:@"node"];
+ if (node)
+ [node refresh];
+ else
+ [self refresh:nil];
+ } else {
+ [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+ }
+}
+
+- (void)newFolderFailed:(ASIPithosObjectRequest *)objectRequest {
+ NSLog(@"Creation of new application/directory object failed");
+ [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
+}
+
+- (void)deleteObjectFinished:(ASIPithosObjectRequest *)objectRequest {
+ if (objectRequest.responseStatusCode == 204) {
+ NSLog(@"Object deleted: %@", [objectRequest url]);
+ [self refresh:nil];
+ } else {
+ [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+ }
+}
+
+- (void)deleteObjectFailed:(ASIPithosObjectRequest *)objectRequest {
+ NSLog(@"Delete of object failed");
+ [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
+}
+
+- (void)moveToTrashFinished:(ASIPithosObjectRequest *)objectRequest {
+ if (objectRequest.responseStatusCode == 201) {
+ NSLog(@"Object moved: %@", [objectRequest url]);
+ [self refresh:nil];
+ } else {
+ [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+ }
+}
+
+- (void)moveToTrashFailed:(ASIPithosObjectRequest *)objectRequest {
+ NSLog(@"Move of object failed");
+ [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
+}
+
+
@end
\ No newline at end of file