Initial implementation of 'others shared'.
[pithos-macos] / pithos-macos / PithosBrowserController.m
index f2cace6..aaa4e2a 100644 (file)
@@ -41,6 +41,7 @@
 #import "PithosContainerNode.h"
 #import "PithosSubdirNode.h"
 #import "PithosObjectNode.h"
+#import "PithosSharingAccountsNode.h"
 #import "PithosEmptyNode.h"
 #import "ImageAndTextCell.h"
 #import "FileSystemBrowserCell.h"
 @end
 
 @implementation PithosBrowserController
-@synthesize outlineViewDataSourceArray, verticalSplitView, horizontalSplitView, leftTopView, leftBottomView,
-            outlineView, browser;
+@synthesize verticalSplitView, horizontalSplitView, leftTopView, leftBottomView, outlineView, browser;
 @synthesize draggedNodes, draggedParentNode;
 @synthesize clipboardNodes, clipboardParentNode, clipboardCopy;
 
     [draggedNodes release];
     [browserMenu release];
     [sharedPreviewController release];
-    [outlineViewDataSourceArray release];
-    [mySharedRootNode release];
+    [othersSharedNode release];
+    [mySharedNode release];
+    [sharedNode release];
+    [containersNodeChildren release];
+    [containersNode release];
     [accountNode release];
     [rootNode release];
     [super dealloc];
 - (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]];
-
-    // SHARED
-       NSTreeNode *sharedTreeNode = [NSTreeNode treeNodeWithRepresentedObject:
-                                      [[[PithosEmptyNode alloc] initWithDisplayName:@"SHARED" icon:nil] autorelease]];
-    // SHARED/my shared
-       [[sharedTreeNode mutableChildNodes] addObject:[NSTreeNode treeNodeWithRepresentedObject:mySharedRootNode]];
-    // 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];
     [super windowDidLoad];
     
     accountNode = [[PithosAccountNode alloc] init];
-    mySharedRootNode = [[PithosAccountNode alloc] init];
-    mySharedRootNode.displayName = @"my shared";
-    mySharedRootNode.shared = YES;
-    mySharedRootNode.icon = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kUserIcon)];
+    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:mySharedRootNode];
+                                               object:nil];
+    // PithosSharingAccountsNode othersSharedNode updates browser nodes 
+    [[NSNotificationCenter defaultCenter] addObserver:self 
+                                             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--) {
 - (void)pithosAccountNodeChildrenUpdated:(NSNotification *)notification {
     BOOL containerPithosFound = NO;
     BOOL containerTrashFound = NO;
-    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"]) {
-            [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"]) {
             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;
             refreshAccountNode = YES;
         }
     }
-    if (refreshAccountNode) {
+    
+    if (refreshAccountNode)
         [accountNode refresh];
-    } 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];
+    
+    [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;    
 
 - (BOOL)browser:(NSBrowser *)browser shouldEditItem:(id)item {
     PithosNode *node = (PithosNode *)item;
-    if (node.shared || ([node class] == [PithosContainerNode class]))
+    if (node.shared || node.sharingAccount || 
+        ([node class] == [PithosContainerNode class]) || ([node class] == [PithosAccountNode class]))
         return NO;
     return YES;
 }
@@ -487,7 +513,8 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                     NSArray *objectRequests = [PithosFileUtilities objectDataRequestsForSubdirWithContainerName:node.pithosContainer.name 
                                                                                                      objectName:node.pithosObject.name 
                                                                                                     toDirectory:[dropDestination path] 
-                                                                                                  checkIfExists:YES];
+                                                                                                  checkIfExists:YES 
+                                                                                                 sharingAccount:node.sharingAccount];
                     if (objectRequests) {
                         for (ASIPithosObjectRequest *objectRequest in objectRequests) {
                             [names addObject:[objectRequest.userInfo valueForKey:@"fileName"]];
@@ -503,7 +530,8 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
             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;
@@ -530,13 +558,20 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
             *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
-                if ([[browser itemAtRow:*row inColumn:*column] class] != [PithosSubdirNode class])
+                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
@@ -554,7 +589,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
             if (*row == -1)
                 dropNode = [browser parentForItemsInColumn:*column];
             
-            if (!dropNode.shared) {
+            if (!dropNode.shared && !dropNode.sharingAccount) {
                 if ([info draggingSourceOperationMask] & NSDragOperationMove) {
                     // NSDragOperationCopy | NSDragOperationMove -> NSDragOperationMove
                     if ((([dropNode class] == [PithosContainerNode class]) || 
@@ -802,7 +837,8 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                                                                                                                  objectName:node.pithosObject.name 
                                                                                                    destinationContainerName:containerName 
                                                                                                       destinationObjectName:destinationObjectName 
-                                                                                                              checkIfExists:YES];
+                                                                                                              checkIfExists:YES 
+                                                                                                             sharingAccount:nil];
                             if (objectRequest) {
                                 objectRequest.delegate = self;
                                 objectRequest.didFinishSelector = @selector(copyFinished:);
@@ -829,7 +865,8 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                                                                                                              objectName:node.pithosObject.name 
                                                                                                destinationContainerName:containerName 
                                                                                                   destinationObjectName:destinationObjectName 
-                                                                                                          checkIfExists:YES];
+                                                                                                          checkIfExists:YES 
+                                                                                                         sharingAccount:nil];
                             if (objectRequests) {
                                 for (ASIPithosObjectRequest *objectRequest in objectRequests) {
                                     objectRequest.delegate = self;
@@ -1061,22 +1098,58 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
 }
 
 #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];                                  
+        [self refresh:nil];
     }
 }
 
@@ -1101,11 +1174,12 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
         } else {
             menuNode = [browser itemAtIndexPath:[menuNodesIndexPaths objectAtIndex:0]];
         }
-        if ([menuNode class] == [PithosAccountNode class])
+        if (([menuNode class] == [PithosAccountNode class]) || ([menuNode class] == [PithosSharingAccountsNode class]))
             return;
         BOOL shared = menuNode.shared;
+        BOOL sharingAccount = (menuNode.sharingAccount != nil);
         
-        if (!shared) {
+        if (!shared && !sharingAccount) {
             // New Folder
             menuItem = [[[NSMenuItem alloc] initWithTitle:@"New Folder" action:@selector(menuNewFolder:) keyEquivalent:@""] autorelease];
             [menuItem setRepresentedObject:menuNode];
@@ -1118,7 +1192,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
         [menuItem setRepresentedObject:[NSArray arrayWithObject:menuNode]];
         [menu addItem:menuItem];
         
-        if (!shared) {
+        if (!shared && !sharingAccount) {
             // Paste
             if (clipboardNodes) {
                 NSUInteger clipboardNodesCount = [clipboardNodes count];
@@ -1149,9 +1223,11 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
             [menuNodes addObject:[browser itemAtIndexPath:clickedNodeIndexPath]];
         }
         NSUInteger menuNodesCount = [menuNodes count];
-        BOOL shared = ((PithosNode *)[menuNodes objectAtIndex:0]).shared;
+        PithosNode *firstMenuNode = (PithosNode *)[menuNodes objectAtIndex:0];
+        BOOL shared = firstMenuNode.shared;
+        BOOL sharingAccount = (firstMenuNode.sharingAccount != nil);
         
-        if (!shared) {
+        if (!shared && !sharingAccount) {
             // Move to Trash (pithos container only)
             // Delete
             if ([rootNode class] == [PithosContainerNode class]) {
@@ -1167,14 +1243,19 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
             }
         }
         
-        // Get Info
-        menuItem = [[[NSMenuItem alloc] initWithTitle:@"Get Info" action:@selector(menuGetInfo:) keyEquivalent:@""] autorelease];
-        [menuItem setRepresentedObject:menuNodes];
-        [menu addItem:menuItem];
+        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) {
+        if (!shared && !sharingAccount) {
             // Cut
-            [menu addItem:[NSMenuItem separatorItem]];
+            
             if (menuNodesCount == 1)
                 menuItemTitle = [NSString stringWithFormat:@"Cut \"%@\"", ((PithosNode *)[menuNodes objectAtIndex:0]).displayName];
             else 
@@ -1182,6 +1263,10 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
             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];
@@ -1190,6 +1275,9 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
             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];
@@ -1458,7 +1546,8 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                                                                                                          objectName:node.pithosObject.name 
                                                                                            destinationContainerName:containerName 
                                                                                               destinationObjectName:destinationObjectName 
-                                                                                                      checkIfExists:YES];
+                                                                                                      checkIfExists:YES 
+                                                                                                     sharingAccount:node.sharingAccount];
                     if (objectRequest) {
                         objectRequest.delegate = self;
                         objectRequest.didFinishSelector = @selector(copyFinished:);
@@ -1485,7 +1574,8 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                                                                                                      objectName:node.pithosObject.name 
                                                                                        destinationContainerName:containerName 
                                                                                           destinationObjectName:destinationObjectName 
-                                                                                                  checkIfExists:YES];
+                                                                                                  checkIfExists:YES 
+                                                                                                 sharingAccount:node.sharingAccount];
                     if (objectRequests) {
                         for (ASIPithosObjectRequest *objectRequest in objectRequests) {
                             objectRequest.delegate = self;