Added menu for outlineView items.
[pithos-macos] / pithos-macos / PithosBrowserController.m
index 2672e8b..58979fd 100644 (file)
     [clipboardNodes release];
     [draggedParentNode release];
     [draggedNodes release];
+    [outlineViewMenu release];
     [browserMenu release];
     [sharedPreviewController release];
     [othersSharedNode release];
     browserMenu = [[NSMenu alloc] init];
     [browserMenu setDelegate:self];
     [browser setMenu:browserMenu];
+
+    outlineViewMenu = [[NSMenu alloc] init];
+    [outlineViewMenu setDelegate:self];
+    [outlineView setMenu:outlineViewMenu];
 }
 
 - (void)resetContainers:(NSNotification *)notification {
     [browser loadColumnZero];
     [containersNodeChildren removeAllObjects];
     [outlineView reloadData];
-    
        // Expand the folder outline view
     [outlineView expandItem:nil expandChildren:YES];
        [outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
     
     // Refresh account
     [accountNode refresh];
+    [mySharedNode refresh];
+    [othersSharedNode refresh];
 }
 
 - (void)windowDidLoad {
     // Expand the folder outline view
     [outlineView expandItem:nil expandChildren:YES];
     
-    if ((rootNode == containersNode) || (rootNode == sharedNode)) {
+    if ((rootNode == nil) || (rootNode == containersNode) || (rootNode == sharedNode)) {
         rootNode = [containersNodeChildren objectAtIndex:0];
         [browser loadColumnZero];
     }
 #pragma mark Actions
 
 - (IBAction)refresh:(id)sender {
-    if (sender)
-        [accountNode refresh];
-    for (NSInteger column = [browser lastColumn]; column >= 0; column--) {
-        [(PithosNode *)[browser parentForItemsInColumn:column] invalidateChildren];
+    if ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) {
+        if (sender)
+            [accountNode forceRefresh];
+        for (NSInteger column = [browser lastColumn]; column >= 0; column--) {
+            PithosNode *node = (PithosNode *)[browser parentForItemsInColumn:column];
+            node.forcedRefresh = YES;
+            [(PithosNode *)[browser parentForItemsInColumn:column] invalidateChildren];                      
+            //[(PithosNode *)[browser parentForItemsInColumn:column] forceRefresh];
+        }        
+    } else {
+        if (sender)
+            [accountNode refresh];
+        for (NSInteger column = [browser lastColumn]; column >= 0; column--) {
+            [(PithosNode *)[browser parentForItemsInColumn:column] invalidateChildren];
+        }
     }
     [browser validateVisibleColumns];
 }
     __block BOOL result = YES;
     [rowIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop){
         PithosNode *node = [browser itemAtIndexPath:[baseIndexPath indexPathByAddingIndex:idx]];
-        if ([node class] == [PithosContainerNode class]) {
+        if (([node class] == [PithosContainerNode class]) || ([node class] == [PithosAccountNode class])) {
             result = NO;
             *stop = 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];
-    [rowIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop){
-        PithosNode *node = [browser itemAtIndexPath:[baseIndexPath indexPathByAddingIndex:idx]];
-        
+    NSMutableArray *names = [NSMutableArray arrayWithCapacity:[draggedNodes count]];
+    for (PithosNode *node in draggedNodes) {        
         // If the node is a subdir ask if the whole tree should be downloaded
         if ([node class] == [PithosSubdirNode class]) {
             NSAlert *alert = [[[NSAlert alloc] init] autorelease];
@@ -542,7 +556,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                 [objectRequest startAsynchronous];
             }
         }
-    }];
+    }
     return names;
 }
 
@@ -972,20 +986,19 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
         NSIndexSet *missingBlocks = [PithosFileUtilities missingBlocksForHashes:[objectRequest.userInfo objectForKey:@"hashes"]
                                                       withMissingHashesResponse:[objectRequest responseString]];
         NSUInteger missingBlockIndex = [missingBlocks firstIndex];
-        ASIPithosObjectRequest *newObjectRequest = [PithosFileUtilities updateObjectDataRequestWithContainerName:[objectRequest.userInfo objectForKey:@"containerName"]
-                                                                                                      objectName:@".upload" 
-                                                                                                       blockSize:[[objectRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue]
-                                                                                                         forFile:[objectRequest.userInfo objectForKey:@"filePath"] 
-                                                                                               missingBlockIndex:missingBlockIndex 
-                                                                                                  sharingAccount:[objectRequest.userInfo objectForKey:@"sharingAccount"]];
-        newObjectRequest.delegate = self;
-        newObjectRequest.didFinishSelector = @selector(uploadMissingBlockFinished:);
-        newObjectRequest.didFailSelector = @selector(uploadMissingBlockFailed:);
-        newObjectRequest.userInfo = objectRequest.userInfo;
-        [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:iteration] forKey:@"iteration"];
-        [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:missingBlocks forKey:@"missingBlocks"];
-        [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
-        [newObjectRequest startAsynchronous];
+        ASIPithosContainerRequest *newContainerRequest = [PithosFileUtilities updateContainerDataRequestWithContainerName:[objectRequest.userInfo objectForKey:@"containerName"] 
+                                                                                                                blockSize:[[objectRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue] 
+                                                                                                                  forFile:[objectRequest.userInfo objectForKey:@"filePath"] 
+                                                                                                        missingBlockIndex:missingBlockIndex 
+                                                                                                           sharingAccount:[objectRequest.userInfo objectForKey:@"sharingAccount"]];
+        newContainerRequest.delegate = self;
+        newContainerRequest.didFinishSelector = @selector(uploadMissingBlockFinished:);
+        newContainerRequest.didFailSelector = @selector(uploadMissingBlockFailed:);
+        newContainerRequest.userInfo = objectRequest.userInfo;
+        [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:iteration] forKey:@"iteration"];
+        [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:missingBlocks forKey:@"missingBlocks"];
+        [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
+        [newContainerRequest startAsynchronous];
     } else {
         [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
     }
@@ -996,52 +1009,51 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
     [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
 }
 
-- (void)uploadMissingBlockFinished:(ASIPithosObjectRequest *)objectRequest {
-    NSLog(@"Upload of missing block completed: %@", [objectRequest url]);
-    if (objectRequest.responseStatusCode == 201) {
-        NSIndexSet *missingBlocks = [objectRequest.userInfo objectForKey:@"missingBlocks"];
-        NSUInteger missingBlockIndex = [[objectRequest.userInfo objectForKey:@"missingBlockIndex"] unsignedIntegerValue];
+- (void)uploadMissingBlockFinished:(ASIPithosContainerRequest *)containerRequest {
+    NSLog(@"Upload of missing block completed: %@", [containerRequest url]);
+    if (containerRequest.responseStatusCode == 202) {
+        NSIndexSet *missingBlocks = [containerRequest.userInfo objectForKey:@"missingBlocks"];
+        NSUInteger missingBlockIndex = [[containerRequest.userInfo objectForKey:@"missingBlockIndex"] unsignedIntegerValue];
         missingBlockIndex = [missingBlocks indexGreaterThanIndex:missingBlockIndex];
         if (missingBlockIndex == NSNotFound) {
-            NSArray *hashes = [objectRequest.userInfo objectForKey:@"hashes"];
-            ASIPithosObjectRequest *newObjectRequest = [PithosFileUtilities writeObjectDataRequestWithContainerName:[objectRequest.userInfo objectForKey:@"containerName"] 
-                                                                                                         objectName:[objectRequest.userInfo objectForKey:@"objectName"] 
-                                                                                                        contentType:[objectRequest.userInfo objectForKey:@"contentType"] 
-                                                                                                          blockSize:[[objectRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue] 
-                                                                                                          blockHash:[objectRequest.userInfo objectForKey:@"blockHash"]
-                                                                                                            forFile:[objectRequest.userInfo objectForKey:@"filePath"] 
+            NSArray *hashes = [containerRequest.userInfo objectForKey:@"hashes"];
+            ASIPithosObjectRequest *newObjectRequest = [PithosFileUtilities writeObjectDataRequestWithContainerName:[containerRequest.userInfo objectForKey:@"containerName"] 
+                                                                                                         objectName:[containerRequest.userInfo objectForKey:@"objectName"] 
+                                                                                                        contentType:[containerRequest.userInfo objectForKey:@"contentType"] 
+                                                                                                          blockSize:[[containerRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue] 
+                                                                                                          blockHash:[containerRequest.userInfo objectForKey:@"blockHash"]
+                                                                                                            forFile:[containerRequest.userInfo objectForKey:@"filePath"] 
                                                                                                       checkIfExists:NO 
                                                                                                              hashes:&hashes 
-                                                                                                     sharingAccount:[objectRequest.userInfo objectForKey:@"sharingAccount"]];
+                                                                                                     sharingAccount:[containerRequest.userInfo objectForKey:@"sharingAccount"]];
             newObjectRequest.delegate = self;
             newObjectRequest.didFinishSelector = @selector(uploadObjectUsingHashMapFinished:);
             newObjectRequest.didFailSelector = @selector(uploadObjectUsingHashMapFailed:);
-            newObjectRequest.userInfo = objectRequest.userInfo;
+            newObjectRequest.userInfo = containerRequest.userInfo;
             [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlocks"];
             [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlockIndex"];
             [newObjectRequest startAsynchronous];
         } else {
-            ASIPithosObjectRequest *newObjectRequest = [PithosFileUtilities updateObjectDataRequestWithContainerName:[objectRequest.userInfo objectForKey:@"containerName"]
-                                                                                                          objectName:@".upload" 
-                                                                                                           blockSize:[[objectRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue]
-                                                                                                             forFile:[objectRequest.userInfo objectForKey:@"filePath"] 
+            ASIPithosContainerRequest *newContainerRequest = [PithosFileUtilities updateContainerDataRequestWithContainerName:[containerRequest.userInfo objectForKey:@"containerName"]
+                                                                                                           blockSize:[[containerRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue]
+                                                                                                             forFile:[containerRequest.userInfo objectForKey:@"filePath"] 
                                                                                                    missingBlockIndex:missingBlockIndex 
-                                                                                                      sharingAccount:[objectRequest.userInfo objectForKey:@"sharingAccount"]];
-            newObjectRequest.delegate = self;
-            newObjectRequest.didFinishSelector = @selector(uploadMissingBlockFinished:);
-            newObjectRequest.didFailSelector = @selector(uploadMissingBlockFailed:);
-            newObjectRequest.userInfo = objectRequest.userInfo;
-            [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
-            [newObjectRequest startAsynchronous];
+                                                                                                      sharingAccount:[containerRequest.userInfo objectForKey:@"sharingAccount"]];
+            newContainerRequest.delegate = self;
+            newContainerRequest.didFinishSelector = @selector(uploadMissingBlockFinished:);
+            newContainerRequest.didFailSelector = @selector(uploadMissingBlockFailed:);
+            newContainerRequest.userInfo = containerRequest.userInfo;
+            [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
+            [newContainerRequest startAsynchronous];
         }
     } else {
-        [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+        [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:containerRequest];
     }
 }
 
-- (void)uploadMissingBlockFailed:(ASIPithosObjectRequest *)objectRequest {
+- (void)uploadMissingBlockFailed:(ASIPithosContainerRequest *)containerRequest {
     NSLog(@"Upload of missing block failed");
-    [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
+    [PithosFileUtilities httpRequestErrorAlertWithRequest:containerRequest];
 }
 
 - (void)moveFinished:(ASIPithosObjectRequest *)objectRequest {
@@ -1173,43 +1185,70 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
 #pragma mark NSMenuDelegate
 
 - (void)menuNeedsUpdate:(NSMenu *)menu {
-    NSInteger column = [browser clickedColumn];
-    NSInteger row = [browser clickedRow];
     [menu removeAllItems];
     NSMenuItem *menuItem;
     NSString *menuItemTitle;
-    if ((column == -1) || (row == -1)) {
-        // 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)];
+    BOOL nodeContextMenu = NO;
+    PithosNode *menuNode;
+    NSMutableArray *menuNodes;
+    if (menu == browserMenu) {
+        NSInteger column = [browser clickedColumn];
+        NSInteger row = [browser clickedRow];
+        if ((column == -1) || (row == -1)) {
+            // General context menu
+            NSArray *menuNodesIndexPaths = [browser selectionIndexPaths];
+            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]];
+            }
         } else {
-            menuNode = [browser itemAtIndexPath:[menuNodesIndexPaths objectAtIndex:0]];
+            // Node context menu
+            NSIndexPath *clickedNodeIndexPath = [[browser indexPathForColumn:column] indexPathByAddingIndex:row];
+            NSArray *menuNodesIndexPaths = [browser selectionIndexPaths];
+            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]];
+            }
+            nodeContextMenu = YES;
         }
-        if (([menuNode class] == [PithosAccountNode class]) || ([menuNode class] == [PithosSharingAccountsNode class]))
+    } else if (menu == outlineViewMenu) {
+        NSInteger row = [outlineView clickedRow];
+        if (row == -1)
+            row = [outlineView selectedRow];
+        if (row == -1)
+            return;
+        menuNode = [outlineView itemAtRow:row];
+    }
+
+    if (!nodeContextMenu) {
+        // General context menu
+        if (([menuNode class] == [PithosAccountNode class]) || 
+            ([menuNode class] == [PithosSharingAccountsNode class]) ||
+            ([menuNode class] == [PithosEmptyNode class]))
             return;
         BOOL shared = menuNode.shared;
         BOOL sharingAccount = (menuNode.sharingAccount != nil);
-        
+        // New Folder
         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
         menuItem = [[[NSMenuItem alloc] initWithTitle:@"Get Info" action:@selector(menuGetInfo:) keyEquivalent:@""] autorelease];
         [menuItem setRepresentedObject:[NSArray arrayWithObject:menuNode]];
         [menu addItem:menuItem];
-        
+        // Paste
         if (!shared && !sharingAccount) {
-            // Paste
             if (clipboardNodes) {
                 NSUInteger clipboardNodesCount = [clipboardNodes count];
                 if (clipboardNodesCount == 0) {
@@ -1228,24 +1267,13 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
         }
     } 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);
-        
+        // Move to Trash (pithos container only)
+        // Delete
         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];
@@ -1258,9 +1286,8 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                 [menu addItem:[NSMenuItem separatorItem]];
             }
         }
-        
+        // Get Info
         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];
@@ -1268,10 +1295,8 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
             if ((!shared && !sharingAccount) || ([firstMenuNode class] != [PithosContainerNode class]))
                 [menu addItem:[NSMenuItem separatorItem]];
         }
-        
+        // Cut
         if (!shared && !sharingAccount) {
-            // Cut
-            
             if (menuNodesCount == 1)
                 menuItemTitle = [NSString stringWithFormat:@"Cut \"%@\"", ((PithosNode *)[menuNodes objectAtIndex:0]).displayName];
             else 
@@ -1280,10 +1305,9 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
             [menuItem setRepresentedObject:menuNodes];
             [menu addItem:menuItem];
         }
-        
+        // Copy
         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 
@@ -1292,9 +1316,8 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
             [menuItem setRepresentedObject:menuNodes];
             [menu addItem:menuItem];
         }
-        
+        // Paste
         if (!shared && !sharingAccount) {
-            // Paste
             if (menuNodesCount == 1) {
                 PithosNode *menuNode = [menuNodes objectAtIndex:0];
                 if (([menuNode class] == [PithosSubdirNode class]) &&