--- /dev/null
+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.
--- /dev/null
+To retrieve the submodules run:
+ git submodule init
+ git submodule update
\ No newline at end of file
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;
};
#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;
--- /dev/null
+//
+// 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
--- /dev/null
+//
+// 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