Merge branch 'master' of https://code.grnet.gr/git/pithos-macos
authorAntony Chazapis <chazapis@gmail.com>
Wed, 7 Sep 2011 12:05:35 +0000 (15:05 +0300)
committerAntony Chazapis <chazapis@gmail.com>
Wed, 7 Sep 2011 12:05:35 +0000 (15:05 +0300)
LICENSE [new file with mode: 0644]
README [new file with mode: 0644]
pithos-macos.xcodeproj/project.pbxproj
pithos-macos/PithosBrowserController.m
pithos-macos/PithosFileUtilities.h [new file with mode: 0644]
pithos-macos/PithosFileUtilities.m [new file with mode: 0644]

diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..6f7fb94
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,32 @@
+Copyright 2011 GRNET S.A. All rights reserved.
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the following
+conditions are met:
+
+  1. Redistributions of source code must retain the above
+     copyright notice, this list of conditions and the following
+     disclaimer.
+
+  2. Redistributions in binary form must reproduce the above
+     copyright notice, this list of conditions and the following
+     disclaimer in the documentation and/or other materials
+     provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and
+documentation are those of the authors and should not be
+interpreted as representing official policies, either expressed
+or implied, of GRNET S.A.
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..4178cda
--- /dev/null
+++ b/README
@@ -0,0 +1,3 @@
+To retrieve the submodules run:
+       git submodule init
+       git submodule update
\ No newline at end of file
index 6de78a2..45ecc24 100644 (file)
@@ -54,6 +54,7 @@
                61C24BBB1410D350007004DC /* PublicURLTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C24BBA1410D350007004DC /* PublicURLTransformer.m */; };
                61C24BBE1410E031007004DC /* SharingDictionaryTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C24BBD1410E031007004DC /* SharingDictionaryTransformer.m */; };
                61C24BC114110BDB007004DC /* SharingNameFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C24BC014110BDB007004DC /* SharingNameFormatter.m */; };
+               61C24BEC14161EC7007004DC /* PithosFileUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C24BEB14161EC3007004DC /* PithosFileUtilities.m */; };
                61E99D9413EC348500E48DA5 /* 145-persondot.png in Resources */ = {isa = PBXBuildFile; fileRef = 61E99D9313EC348500E48DA5 /* 145-persondot.png */; };
 /* End PBXBuildFile section */
 
                61C24BBD1410E031007004DC /* SharingDictionaryTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SharingDictionaryTransformer.m; path = "pithos-macos/SharingDictionaryTransformer.m"; sourceTree = "<group>"; };
                61C24BBF14110BDB007004DC /* SharingNameFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SharingNameFormatter.h; path = "pithos-macos/SharingNameFormatter.h"; sourceTree = "<group>"; };
                61C24BC014110BDB007004DC /* SharingNameFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SharingNameFormatter.m; path = "pithos-macos/SharingNameFormatter.m"; sourceTree = "<group>"; };
+               61C24BEA14161EC0007004DC /* PithosFileUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PithosFileUtilities.h; sourceTree = "<group>"; };
+               61C24BEB14161EC3007004DC /* PithosFileUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PithosFileUtilities.m; sourceTree = "<group>"; };
                61E99D9313EC348500E48DA5 /* 145-persondot.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "145-persondot.png"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
                                610DD37413E7064F00ED982F /* PithosSubdirNode.m */,
                                611FFCAD13EBF0B800E43E18 /* PithosEmptyNode.h */,
                                611FFCAE13EBF0B900E43E18 /* PithosEmptyNode.m */,
+                               61C24BEA14161EC0007004DC /* PithosFileUtilities.h */,
+                               61C24BEB14161EC3007004DC /* PithosFileUtilities.m */,
                        );
                        path = "pithos-macos";
                        sourceTree = "<group>";
                                61C24BBB1410D350007004DC /* PublicURLTransformer.m in Sources */,
                                61C24BBE1410E031007004DC /* SharingDictionaryTransformer.m in Sources */,
                                61C24BC114110BDB007004DC /* SharingNameFormatter.m in Sources */,
+                               61C24BEC14161EC7007004DC /* PithosFileUtilities.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 820b1de..112cb4d 100644 (file)
 #import "PithosNode.h"
 #import "PithosAccountNode.h"
 #import "PithosContainerNode.h"
+#import "PithosSubdirNode.h"
+#import "PithosObjectNode.h"
 #import "PithosEmptyNode.h"
 #import "ImageAndTextCell.h"
 #import "FileSystemBrowserCell.h"
 #import "ASIPithosRequest.h"
 #import "ASIPithosContainerRequest.h"
+#import "ASIPithosObjectRequest.h"
 #import "ASIPithosContainer.h"
+#import "ASIPithosObject.h"
+#import "PithosFileUtilities.h"
 
 //@interface PithosBrowserCell : NSBrowserCell {}
 @interface PithosBrowserCell : FileSystemBrowserCell {}
 }
 
 - (void)awakeFromNib {
+    [super awakeFromNib];
+    
+    [browser setDraggingSourceOperationMask:NSDragOperationNone forLocal:YES];
+    [browser setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO];
+    
     [browser setCellClass:[PithosBrowserCell class]];
 }
 
     }
 }
 
-
 #pragma mark -
 #pragma Actions
 
     return NO;
 }
 
+#pragma mark Drag and Drop
+
+//- (BOOL)browser:(NSBrowser *)aBrowser canDragRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column 
+//      withEvent:(NSEvent *)event {    
+//    // XXX allow only objects? or when a subdir is dragged download the whole tree?
+//    NSIndexPath *baseIndexPath = [browser indexPathForColumn:column]; 
+//    for (NSUInteger i = [rowIndexes firstIndex]; i <= [rowIndexes lastIndex]; i = [rowIndexes indexGreaterThanIndex:i]) {
+//        PithosNode *node = [browser itemAtIndexPath:[baseIndexPath indexPathByAddingIndex:i]];
+//        if (node.pithosObject.subdir)
+//            return NO;
+//    }
+//    return YES;
+//}
+
+- (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]];
+        [propertyList addObject:[node.pithosObject.name pathExtension]];
+    }
+
+    [pasteboard declareTypes:[NSArray arrayWithObject:NSFilesPromisePboardType] owner:self];
+    [pasteboard setPropertyList:propertyList forType:NSFilesPromisePboardType];
+    
+    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]];
+        
+        
+        // If the node is a subdir ask if the whole tree should be downloaded
+        if (node.pithosObject.subdir) {
+            NSAlert *alert = [[NSAlert alloc] init];
+            [alert setMessageText:@"Download directory"];
+            [alert setInformativeText:[NSString stringWithFormat:@"'%@' is a directory, do you want to download its contents?", node.displayName]];
+            [alert addButtonWithTitle:@"OK"];
+            [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"]];
+                        // XXX set delegates and queue
+                        [objectRequest setCompletionBlock:^{
+                            NSLog(@"dl completed: %@", [objectRequest url]);
+                        }];
+                        [objectRequest setFailedBlock:^{
+                            NSLog(@"dl failed: %@, error: %@", [objectRequest url], [objectRequest error]);
+                        }];
+                        [objectRequest startAsynchronous];
+                    }
+                }
+            }
+        } else {
+            ASIPithosObjectRequest *objectRequest = [PithosFileUtilities objectDataRequestWithContainerName:node.pithosContainer.name 
+                                                                                                 objectName:node.pithosObject.name 
+                                                                                                toDirectory:[dropDestination path] 
+                                                                                              checkIfExists:YES];
+            if (objectRequest) {
+                [names addObject:[objectRequest.userInfo valueForKey:@"fileName"]];
+                // XXX set delegates and queue
+                [objectRequest setCompletionBlock:^{
+                    NSLog(@"dl completed: %@", [objectRequest url]);
+                }];
+                [objectRequest setFailedBlock:^{
+                    NSLog(@"dl failed: %@, error: %@", [objectRequest url], [objectRequest error]);
+                }];
+                [objectRequest startAsynchronous];
+            }
+        }
+    }
+    return names;
+}
+
 #pragma mark -
-#pragma NSSplitViewDelegate
+#pragma mark NSSplitViewDelegate
 
 - (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
     return 120;
diff --git a/pithos-macos/PithosFileUtilities.h b/pithos-macos/PithosFileUtilities.h
new file mode 100644 (file)
index 0000000..86a3060
--- /dev/null
@@ -0,0 +1,51 @@
+//
+//  PithosFileUtilities.h
+//  pithos-macos
+//
+// Copyright 2011 GRNET S.A. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or
+// without modification, are permitted provided that the following
+// conditions are met:
+// 
+//   1. Redistributions of source code must retain the above
+//      copyright notice, this list of conditions and the following
+//      disclaimer.
+// 
+//   2. Redistributions in binary form must reproduce the above
+//      copyright notice, this list of conditions and the following
+//      disclaimer in the documentation and/or other materials
+//      provided with the distribution.
+// 
+// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+// 
+// The views and conclusions contained in the software and
+// documentation are those of the authors and should not be
+// interpreted as representing official policies, either expressed
+// or implied, of GRNET S.A.
+
+@class ASIPithosObjectRequest;
+
+@interface PithosFileUtilities : NSObject
+
++ (ASIPithosObjectRequest *)objectDataRequestWithContainerName:(NSString *)containerName 
+                                                    objectName:(NSString *)objectName 
+                                                   toDirectory:(NSString *)directoryPath 
+                                                 checkIfExists:(BOOL)ifExists;
++ (NSArray *)objectDataRequestsForSubdirWithContainerName:(NSString *)containerName 
+                                               objectName:(NSString *)objectName 
+                                              toDirectory:(NSString *)directoryPath 
+                                            checkIfExists:(BOOL)ifExists;
+
+@end
diff --git a/pithos-macos/PithosFileUtilities.m b/pithos-macos/PithosFileUtilities.m
new file mode 100644 (file)
index 0000000..5a17f9d
--- /dev/null
@@ -0,0 +1,153 @@
+//
+//  PithosFileUtilities.m
+//  pithos-macos
+//
+// Copyright 2011 GRNET S.A. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or
+// without modification, are permitted provided that the following
+// conditions are met:
+// 
+//   1. Redistributions of source code must retain the above
+//      copyright notice, this list of conditions and the following
+//      disclaimer.
+// 
+//   2. Redistributions in binary form must reproduce the above
+//      copyright notice, this list of conditions and the following
+//      disclaimer in the documentation and/or other materials
+//      provided with the distribution.
+// 
+// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+// 
+// The views and conclusions contained in the software and
+// documentation are those of the authors and should not be
+// interpreted as representing official policies, either expressed
+// or implied, of GRNET S.A.
+
+#import "PithosFileUtilities.h"
+#import "ASIPithosContainerRequest.h"
+#import "ASIPithosObjectRequest.h"
+#import "ASIPithosObject.h"
+
+@implementation PithosFileUtilities
+
++ (ASIPithosObjectRequest *)objectDataRequestWithContainerName:(NSString *)containerName 
+                                                    objectName:(NSString *)objectName 
+                                                   toDirectory:(NSString *)directoryPath 
+                                                 checkIfExists:(BOOL)ifExists {
+    NSString *fileName = [objectName lastPathComponent];
+    if ([objectName hasSuffix:@"/"])
+        fileName = [fileName stringByAppendingString:@"_trailing_slash"];
+    
+    NSFileManager *defaultManager = [NSFileManager defaultManager];
+    
+    NSString *destinationPath = [directoryPath stringByAppendingPathComponent:fileName];
+    if (ifExists && [defaultManager fileExistsAtPath:destinationPath]) {
+        NSAlert *alert = [[NSAlert alloc] init];
+        [alert setMessageText:@"File exists"];
+        [alert setInformativeText:[NSString stringWithFormat:@"A file or directory named '%@' already exists, do you want to replace it?", fileName]];
+        [alert addButtonWithTitle:@"OK"];
+        [alert addButtonWithTitle:@"Cancel"];
+        NSInteger choice = [alert runModal];
+        if (choice == NSAlertSecondButtonReturn)
+            return nil;
+    }
+    
+    BOOL directoryIsDirectory;
+    BOOL directoryExists = [defaultManager fileExistsAtPath:directoryPath isDirectory:&directoryIsDirectory];
+    NSError *error = nil;
+    if (!directoryExists) {
+        [defaultManager createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:&error];
+    } else if (!directoryIsDirectory) {
+        [defaultManager removeItemAtPath:directoryPath error:&error];
+    }
+    if (error) {
+        NSLog(@"error: %@", error);
+        // XXX do something on error, an alert maybe
+        return nil;
+    }
+
+    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest objectDataRequestWithContainerName:containerName 
+                                                                                            objectName:objectName];
+    [objectRequest setDownloadDestinationPath:destinationPath];
+    [objectRequest setUserInfo:[NSDictionary dictionaryWithObjectsAndKeys:fileName, @"fileName", nil]];
+    return objectRequest;
+}
+
++ (NSArray *)objectDataRequestsForSubdirWithContainerName:(NSString *)containerName 
+                                               objectName:(NSString *)objectName 
+                                              toDirectory:(NSString *)directoryPath 
+                                            checkIfExists:(BOOL)ifExists {
+    NSString *subdirName = [objectName lastPathComponent];
+    NSString *destinationPath = [directoryPath stringByAppendingPathComponent:subdirName];
+    if (ifExists && [[NSFileManager defaultManager] fileExistsAtPath:destinationPath]) {
+        NSAlert *alert = [[NSAlert alloc] init];
+        [alert setMessageText:@"File exists"];
+        [alert setInformativeText:[NSString stringWithFormat:@"A file or directory named '%@' already exists, do you want to replace it?", subdirName]];
+        [alert addButtonWithTitle:@"OK"];
+        [alert addButtonWithTitle:@"Cancel"];
+        NSInteger choice = [alert runModal];
+        if (choice == NSAlertSecondButtonReturn)
+            return nil;
+    }
+    
+    NSMutableArray *objects = [NSMutableArray array];
+    NSString *marker = nil;
+    do {
+        ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest listObjectsRequestWithContainerName:containerName 
+                                                                                                               limit:0 
+                                                                                                              marker:marker 
+                                                                                                              prefix:objectName 
+                                                                                                           delimiter:nil 
+                                                                                                                path:nil 
+                                                                                                                meta:nil 
+                                                                                                              shared:NO 
+                                                                                                               until:nil];
+        [containerRequest startSynchronous];
+        if ([containerRequest error]) {
+            NSLog(@"error:%@", [containerRequest error]);
+            // XXX do something on error
+            return nil;
+        }
+        NSArray *someObjects = [containerRequest objects];
+        [objects addObjectsFromArray:someObjects];
+        if ([someObjects count] < 10000)
+            marker = nil;
+        else
+            marker = [[someObjects lastObject] name];
+    } while (marker);
+    
+    NSMutableArray *objectRequests = [NSMutableArray arrayWithCapacity:[objects count]];
+    NSUInteger subdirPrefixLength = [objectName length];
+    for (ASIPithosObject *object in objects) {
+        if (![objectName isEqualToString:object.name] && !object.subdir) {
+            NSString *fileName = [object.name lastPathComponent];
+            if([object.name hasSuffix:@"/"])
+                fileName = [fileName stringByAppendingString:@"/"];
+            
+            NSString *objectDirectoryPath = [directoryPath stringByAppendingPathComponent:subdirName];
+            objectDirectoryPath = [objectDirectoryPath stringByAppendingPathComponent:[object.name substringWithRange:NSMakeRange(subdirPrefixLength, [object.name length] - subdirPrefixLength - [fileName length])]];
+            
+            [objectRequests addObject:[self objectDataRequestWithContainerName:containerName 
+                                                                    objectName:object.name 
+                                                                   toDirectory:objectDirectoryPath 
+                                                                 checkIfExists:NO]];
+        }
+    }
+    
+    return objectRequests;
+}
+
+
+@end