All requests made asynchronous.
authorMiltiadis Vasilakis <mvasilak@gmail.com>
Wed, 12 Oct 2011 18:35:17 +0000 (21:35 +0300)
committerMiltiadis Vasilakis <mvasilak@gmail.com>
Wed, 12 Oct 2011 21:01:26 +0000 (00:01 +0300)
Request are prioritized accordingly.
Download/Upload activity is more precise.
Copy/Move actions are shown in activity.
Initial implementation of request retries.
Other fixes and changes.

15 files changed:
pithos-macos.xcodeproj/project.pbxproj
pithos-macos/PithosAccountNode.m
pithos-macos/PithosActivity.h
pithos-macos/PithosActivityFacility.h
pithos-macos/PithosActivityFacility.m
pithos-macos/PithosBrowserController.h
pithos-macos/PithosBrowserController.m
pithos-macos/PithosBrowserController.xib
pithos-macos/PithosContainerNode.m
pithos-macos/PithosObjectNode.m
pithos-macos/PithosSharingAccountsNode.m
pithos-macos/PithosSubdirNode.m
pithos-macos/PithosUtilities.h [moved from pithos-macos/PithosFileUtilities.h with 97% similarity]
pithos-macos/PithosUtilities.m [moved from pithos-macos/PithosFileUtilities.m with 87% similarity]
pithos-macos/pithos_macosAppDelegate.m

index a85a486..54aac14 100644 (file)
@@ -64,7 +64,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 */; };
+               61C24BEC14161EC7007004DC /* PithosUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C24BEB14161EC3007004DC /* PithosUtilities.m */; };
                61C65ADF1428C578002597C2 /* CountTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C65ADE1428C578002597C2 /* CountTransformer.m */; };
                61C65AE31428D41C002597C2 /* PolicyVersioningTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C65AE21428D41C002597C2 /* PolicyVersioningTransformer.m */; };
                61C65AE6142918DD002597C2 /* PithosObjectNodeInfoController.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C65AE5142918DD002597C2 /* PithosObjectNodeInfoController.m */; };
                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>"; };
+               61C24BEA14161EC0007004DC /* PithosUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PithosUtilities.h; sourceTree = "<group>"; };
+               61C24BEB14161EC3007004DC /* PithosUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PithosUtilities.m; sourceTree = "<group>"; };
                61C65ADD1428C578002597C2 /* CountTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CountTransformer.h; path = "pithos-macos/CountTransformer.h"; sourceTree = "<group>"; };
                61C65ADE1428C578002597C2 /* CountTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CountTransformer.m; path = "pithos-macos/CountTransformer.m"; sourceTree = "<group>"; };
                61C65AE11428D41C002597C2 /* PolicyVersioningTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PolicyVersioningTransformer.h; path = "pithos-macos/PolicyVersioningTransformer.h"; sourceTree = "<group>"; };
                610DD2FB13E6BB2000ED982F /* pithos-macos */ = {
                        isa = PBXGroup;
                        children = (
+                               61F1C5DB1444A8CF00C1E6EB /* PithosNodes */,
+                               61F1C5DD1444A92B00C1E6EB /* PithosNodeInfoControllers */,
+                               610DD2FC13E6BB2000ED982F /* Supporting Files */,
                                610DD30713E6BB2000ED982F /* pithos_macosAppDelegate.h */,
                                610DD30813E6BB2000ED982F /* pithos_macosAppDelegate.m */,
                                610DD30A13E6BB2000ED982F /* MainMenu.xib */,
-                               610DD2FC13E6BB2000ED982F /* Supporting Files */,
                                610DD34C13E6BEF400ED982F /* PithosBrowserController.h */,
                                610DD34D13E6BEF400ED982F /* PithosBrowserController.m */,
                                610DD34F13E6C00E00ED982F /* PithosBrowserController.xib */,
                                6121250813F033F400063041 /* PithosBrowserPreviewController.xib */,
-                               616FC0B113F97D0800140A33 /* PithosNodeInfoController.h */,
-                               616FC0B213F97D0800140A33 /* PithosNodeInfoController.m */,
-                               611405CD1428BEBD00637170 /* PithosContainerNodeInfoController.h */,
-                               611405CE1428BEBE00637170 /* PithosContainerNodeInfoController.m */,
-                               611405CF1428BEC000637170 /* PithosContainerNodeInfoController.xib */,
-                               61C65AE4142918DC002597C2 /* PithosObjectNodeInfoController.h */,
-                               61C65AE5142918DD002597C2 /* PithosObjectNodeInfoController.m */,
-                               616FC0AE13F91BA400140A33 /* PithosObjectNodeInfoController.xib */,
                                619B85D213F8076F00C9371F /* PithosPreferencesController.h */,
                                619B85D313F8077100C9371F /* PithosPreferencesController.m */,
                                619B85D413F8077300C9371F /* PithosPreferencesController.xib */,
-                               610DD35713E6C3D100ED982F /* PithosNode.h */,
-                               610DD35813E6C3D100ED982F /* PithosNode.m */,
-                               610DD36213E6E2E400ED982F /* PithosAccountNode.h */,
-                               610DD36313E6E2E400ED982F /* PithosAccountNode.m */,
-                               610DD36513E6E69D00ED982F /* PithosContainerNode.h */,
-                               610DD36613E6E69D00ED982F /* PithosContainerNode.m */,
-                               610DD37313E7064E00ED982F /* PithosSubdirNode.h */,
-                               610DD37413E7064F00ED982F /* PithosSubdirNode.m */,
-                               610DD37013E7059800ED982F /* PithosObjectNode.h */,
-                               610DD37113E7059900ED982F /* PithosObjectNode.m */,
-                               6152D08A143200CB00803874 /* PithosSharingAccountsNode.h */,
-                               6152D08B143200CC00803874 /* PithosSharingAccountsNode.m */,
-                               611FFCAD13EBF0B800E43E18 /* PithosEmptyNode.h */,
-                               611FFCAE13EBF0B900E43E18 /* PithosEmptyNode.m */,
-                               61C24BEA14161EC0007004DC /* PithosFileUtilities.h */,
-                               61C24BEB14161EC3007004DC /* PithosFileUtilities.m */,
+                               61C24BEA14161EC0007004DC /* PithosUtilities.h */,
+                               61C24BEB14161EC3007004DC /* PithosUtilities.m */,
                                618A7FD61438CE5D0040F043 /* PithosActivityFacility.h */,
                                618A7FD71438CE5D0040F043 /* PithosActivityFacility.m */,
                                618A7FF4143A20830040F043 /* PithosActivity.h */,
                        name = "Value Transformers";
                        sourceTree = "<group>";
                };
+               61F1C5DB1444A8CF00C1E6EB /* PithosNodes */ = {
+                       isa = PBXGroup;
+                       children = (
+                               610DD35713E6C3D100ED982F /* PithosNode.h */,
+                               610DD35813E6C3D100ED982F /* PithosNode.m */,
+                               610DD36213E6E2E400ED982F /* PithosAccountNode.h */,
+                               610DD36313E6E2E400ED982F /* PithosAccountNode.m */,
+                               610DD36513E6E69D00ED982F /* PithosContainerNode.h */,
+                               610DD36613E6E69D00ED982F /* PithosContainerNode.m */,
+                               610DD37313E7064E00ED982F /* PithosSubdirNode.h */,
+                               610DD37413E7064F00ED982F /* PithosSubdirNode.m */,
+                               610DD37013E7059800ED982F /* PithosObjectNode.h */,
+                               610DD37113E7059900ED982F /* PithosObjectNode.m */,
+                               6152D08A143200CB00803874 /* PithosSharingAccountsNode.h */,
+                               6152D08B143200CC00803874 /* PithosSharingAccountsNode.m */,
+                               611FFCAD13EBF0B800E43E18 /* PithosEmptyNode.h */,
+                               611FFCAE13EBF0B900E43E18 /* PithosEmptyNode.m */,
+                       );
+                       name = PithosNodes;
+                       sourceTree = "<group>";
+               };
+               61F1C5DD1444A92B00C1E6EB /* PithosNodeInfoControllers */ = {
+                       isa = PBXGroup;
+                       children = (
+                               616FC0B113F97D0800140A33 /* PithosNodeInfoController.h */,
+                               616FC0B213F97D0800140A33 /* PithosNodeInfoController.m */,
+                               611405CD1428BEBD00637170 /* PithosContainerNodeInfoController.h */,
+                               611405CE1428BEBE00637170 /* PithosContainerNodeInfoController.m */,
+                               611405CF1428BEC000637170 /* PithosContainerNodeInfoController.xib */,
+                               61C65AE4142918DC002597C2 /* PithosObjectNodeInfoController.h */,
+                               61C65AE5142918DD002597C2 /* PithosObjectNodeInfoController.m */,
+                               616FC0AE13F91BA400140A33 /* PithosObjectNodeInfoController.xib */,
+                       );
+                       name = PithosNodeInfoControllers;
+                       sourceTree = "<group>";
+               };
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
                                61C24BBB1410D350007004DC /* PublicURLTransformer.m in Sources */,
                                61C24BBE1410E031007004DC /* SharingDictionaryTransformer.m in Sources */,
                                61C24BC114110BDB007004DC /* SharingNameFormatter.m in Sources */,
-                               61C24BEC14161EC7007004DC /* PithosFileUtilities.m in Sources */,
+                               61C24BEC14161EC7007004DC /* PithosUtilities.m in Sources */,
                                614592BC1417CE70002E7A8C /* ASIPithosAccount.m in Sources */,
                                61433BC9141BA1CE00CD978D /* HashMapHash.m in Sources */,
                                611405D01428BEC000637170 /* PithosContainerNodeInfoController.m in Sources */,
index 639e344..e45b6d7 100644 (file)
@@ -41,7 +41,7 @@
 #import "ASIPithosAccount.h"
 #import "ASIPithosContainer.h"
 #import "ASIDownloadCache.h"
-#import "PithosFileUtilities.h"
+#import "PithosUtilities.h"
 
 static NSImage *sharedIcon = nil;
 
@@ -97,7 +97,7 @@ static NSImage *sharedIcon = nil;
                 accountRequest.didFailSelector = @selector(accountRequestFailed:);
                 if (!forcedRefresh)
                     accountRequest.downloadCache = [ASIDownloadCache sharedCache];
-                [accountRequest startAsynchronous];
+                [[PithosUtilities prepareRequest:accountRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
                 break;
             case PithosNodeStateRefreshing:
                 break;
@@ -194,12 +194,12 @@ static NSImage *sharedIcon = nil;
         accountRequest.delegate = self;
         if (!forcedRefresh)
             accountRequest.downloadCache = [ASIDownloadCache sharedCache];
-        [accountRequest startAsynchronous];
+        [[PithosUtilities prepareRequest:accountRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
     }
 }
 
 - (void)accountRequestFailed:(ASIPithosAccountRequest *)request {
-    [PithosFileUtilities httpRequestErrorAlertWithRequest:request];
+    [PithosUtilities httpRequestErrorAlertWithRequest:request];
     [newChildren release];
     newChildren = nil;
     [accountRequest release];
@@ -233,13 +233,13 @@ static NSImage *sharedIcon = nil;
 
 - (void)accountMetadataRequestFailed:(ASIPithosAccountRequest *)request {
     if ([request isEqualTo:applyMetadataAccountRequest]) {
-        [PithosFileUtilities httpRequestErrorAlertWithRequest:applyMetadataAccountRequest];
+        [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataAccountRequest];
         @synchronized(self) {
             [applyMetadataAccountRequest release];
             applyMetadataAccountRequest = nil;
         }
     } else if ([request isEqualTo:refreshMetadataAccountRequest]) {
-        [PithosFileUtilities httpRequestErrorAlertWithRequest:refreshMetadataAccountRequest];
+        [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataAccountRequest];
         @synchronized(self) {
             [refreshMetadataAccountRequest release];
             refreshMetadataAccountRequest = nil;
@@ -262,7 +262,7 @@ static NSImage *sharedIcon = nil;
             applyMetadataAccountRequest.delegate = self;
             applyMetadataAccountRequest.didFinishSelector = @selector(accountMetadataRequestFinished:);
             applyMetadataAccountRequest.didFailSelector = @selector(accountMetadataRequestFailed:);
-            [applyMetadataAccountRequest startAsynchronous];
+            [[PithosUtilities prepareRequest:applyMetadataAccountRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
         }
     }
 }
@@ -275,7 +275,7 @@ static NSImage *sharedIcon = nil;
             refreshMetadataAccountRequest.didFinishSelector = @selector(accountMetadataRequestFinished:);
             refreshMetadataAccountRequest.didFailSelector = @selector(accountMetadataRequestFailed:);
             refreshMetadataAccountRequest.downloadCache = [ASIDownloadCache sharedCache];
-            [refreshMetadataAccountRequest startAsynchronous];
+            [[PithosUtilities prepareRequest:refreshMetadataAccountRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
         }
     }
 }
index 44aa504..2e29ad7 100644 (file)
 #import <Foundation/Foundation.h>
 
 typedef enum  {
-    PithosActivityUpload,
-    PithosActivityDownload
+    PithosActivityUpload, 
+    PithosActivityDownload, 
+    PithosActivityCopy, 
+    PithosActivityMove
 } PithosActivityType;
 
 @interface PithosActivity : NSObject {
index ce71d16..8006962 100644 (file)
                                   message:(NSString *)message 
                                totalBytes:(NSUInteger)totalBytes 
                              currentBytes:(NSUInteger)currentBytes;
+- (PithosActivity *)startActivityWithType:(PithosActivityType)type 
+                                  message:(NSString *)message;
 - (void)updateActivity:(PithosActivity *)activity 
            withMessage:(NSString *)message 
             totalBytes:(NSUInteger)totalBytes 
           currentBytes:(NSUInteger)currentBytes;
+- (void)updateActivity:(PithosActivity *)activity 
+           withMessage:(NSString *)message;
 - (void)endActivity:(PithosActivity *)activity 
         withMessage:(NSString *)message 
          totalBytes:(NSUInteger)totalBytes 
        currentBytes:(NSUInteger)currentBytes;
+- (void)endActivity:(PithosActivity *)activity 
+        withMessage:(NSString *)message;
 
 @end
\ No newline at end of file
index b3b0a52..168476c 100644 (file)
@@ -117,7 +117,7 @@ static PithosActivityFacility *defaultPithosActivityFacility = nil;
         
         pickedRunning = NO;
         
-        timer = [[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(update:) userInfo:nil repeats:YES] retain];
+        timer = [[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(update:) userInfo:nil repeats:YES] retain];
     }
 }
 
@@ -223,10 +223,17 @@ static PithosActivityFacility *defaultPithosActivityFacility = nil;
     return activity;
 }
 
+- (PithosActivity *)startActivityWithType:(PithosActivityType)type 
+                                  message:(NSString *)message {
+    return [self startActivityWithType:type message:message totalBytes:0 currentBytes:0];
+}
+
 - (void)updateActivity:(PithosActivity *)activity 
            withMessage:(NSString *)message 
             totalBytes:(NSUInteger)totalBytes 
           currentBytes:(NSUInteger)currentBytes {
+    if (!activity)
+        return;
     NSLog(@"PithosActivityFacility updatedActivity %@", activity);
     @synchronized(self) {
         activity.message = message;
@@ -250,10 +257,17 @@ static PithosActivityFacility *defaultPithosActivityFacility = nil;
     NSLog(@"PithosActivityFacility %@", self);
 }
 
+- (void)updateActivity:(PithosActivity *)activity 
+           withMessage:(NSString *)message {
+    [self updateActivity:activity withMessage:message totalBytes:activity.totalBytes currentBytes:activity.currentBytes];
+}
+
 - (void)endActivity:(PithosActivity *)activity 
         withMessage:(NSString *)message 
          totalBytes:(NSUInteger)totalBytes 
        currentBytes:(NSUInteger)currentBytes {
+    if (!activity)
+        return;
     @synchronized(self) {
         [runningActivities removeObject:activity];
         activity.message = message;
@@ -279,4 +293,9 @@ static PithosActivityFacility *defaultPithosActivityFacility = nil;
     NSLog(@"PithosActivityFacility %@", self);
 }
 
+- (void)endActivity:(PithosActivity *)activity 
+        withMessage:(NSString *)message {
+    [self endActivity:activity withMessage:message totalBytes:activity.totalBytes currentBytes:activity.currentBytes];
+}
+
 @end
index 3e107df..c3e1e85 100644 (file)
     
     NSViewController *sharedPreviewController;
     
-    NSMenu *browserMenu;
-    NSMenu *outlineViewMenu;
-    
     NSSplitView *verticalSplitView;
     NSSplitView *horizontalSplitView;
     NSView *leftTopView;
     NSView *leftBottomView;
     NSOutlineView *outlineView;
     NSBrowser *browser;
+    NSMenu *outlineViewMenu;
+    NSMenu *browserMenu;
     
     NSArray *draggedNodes;
     PithosNode *draggedParentNode;
@@ -84,6 +83,8 @@
 @property (nonatomic, assign) IBOutlet NSView *leftBottomView;
 @property (nonatomic, assign) IBOutlet NSOutlineView *outlineView;
 @property (nonatomic, assign) IBOutlet NSBrowser *browser;
+@property (nonatomic, assign) IBOutlet NSMenu *outlineViewMenu;
+@property (nonatomic, assign) IBOutlet NSMenu *browserMenu;
 
 @property (nonatomic, retain) NSArray *draggedNodes;
 @property (nonatomic, retain) PithosNode *draggedParentNode;
@@ -95,6 +96,7 @@
 @property (nonatomic, assign) IBOutlet NSTextField *activityTextField;
 @property (nonatomic, assign) IBOutlet NSProgressIndicator *activityProgressIndicator;
 
+- (IBAction)forceRefresh:(id)sender;
 - (IBAction)refresh:(id)sender;
 
 @end
index dc5832d..fce0de3 100644 (file)
@@ -51,8 +51,8 @@
 #import "ASIPithosAccount.h"
 #import "ASIPithosContainer.h"
 #import "ASIPithosObject.h"
-#import "PithosFileUtilities.h"
-#import "BytesExtendedSizeTransformer.h"
+#import "PithosUtilities.h"
+#import "BytesSizeTransformer.h"
 
 @interface PithosBrowserCell : FileSystemBrowserCell {}
 @end
     [clipboardNodes release];
     [draggedParentNode release];
     [draggedNodes release];
-    [outlineViewMenu release];
-    [browserMenu release];
     [sharedPreviewController release];
     [othersSharedNode release];
     [mySharedNode release];
     [outlineView setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO];
     
     [browser setCellClass:[PithosBrowserCell class]];
-    
-    browserMenu = [[NSMenu alloc] init];
-    [browserMenu setDelegate:self];
-    [browser setMenu:browserMenu];
-
-    outlineViewMenu = [[NSMenu alloc] init];
-    [outlineViewMenu setDelegate:self];
-    [outlineView setMenu:outlineViewMenu];
 }
 
 - (void)resetContainers:(NSNotification *)notification {
     if (!containerPithosFound) {
         // Create pithos node
         ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithContainerName:@"pithos"];
-        [containerRequest startSynchronous];
+        [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
+        while (![containerRequest isFinished]) {
+            sleep(1);
+        }
         if ([containerRequest error]) {
-            [PithosFileUtilities httpRequestErrorAlertWithRequest:containerRequest];
+            [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest];
         } else {
             refreshAccountNode = YES;
         }
     if (!containerTrashFound) {
         // Create trash node
         ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithContainerName:@"trash"];
-        [containerRequest startSynchronous];
+        [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
+        while (![containerRequest isFinished]) {
+            sleep(1);
+        }
         if ([containerRequest error]) {
-            [PithosFileUtilities httpRequestErrorAlertWithRequest:containerRequest];
+            [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest];
         } else {
             refreshAccountNode = YES;
         }
 #pragma mark -
 #pragma mark Actions
 
+- (IBAction)forceRefresh:(id)sender {
+    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];                      
+    }
+    [browser validateVisibleColumns];
+}
+
 - (IBAction)refresh:(id)sender {
     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];
-        }        
+        [self forceRefresh:sender];
     } else {
         if (sender)
             [accountNode refresh];
         for (NSInteger column = [browser lastColumn]; column >= 0; column--) {
             [(PithosNode *)[browser parentForItemsInColumn:column] invalidateChildren];
         }
+        [browser validateVisibleColumns];
     }
-    [browser validateVisibleColumns];
 }
 
 #pragma mark -
         return;
     }
     if (([node class] == [PithosObjectNode class]) || 
-        (([node class] == [PithosSubdirNode class]) && 
-         !node.pithosObject.subdir &&
-         [node.pithosObject.name hasSuffix:@"/"])) {
+        (([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];
                 destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
             NSError *error = nil;
             BOOL isDirectory;
-            if ([PithosFileUtilities objectExistsAtContainerName:node.pithosContainer.name 
-                                                      objectName:destinationObjectName 
-                                                           error:&error 
-                                                     isDirectory:&isDirectory 
-                                                  sharingAccount:nil]) {
+            if ([PithosUtilities objectExistsAtContainerName:node.pithosContainer.name 
+                                                  objectName:destinationObjectName 
+                                                       error:&error 
+                                                 isDirectory:&isDirectory 
+                                              sharingAccount:nil]) {
                 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]];
             } else if (error) {
                 return;
             }
-            ASIPithosObjectRequest *objectRequest = [PithosFileUtilities moveObjectRequestWithContainerName:node.pithosContainer.name 
-                                                                                                 objectName:node.pithosObject.name 
-                                                                                   destinationContainerName:node.pithosContainer.name 
-                                                                                      destinationObjectName:destinationObjectName 
-                                                                                              checkIfExists:NO];
+            ASIPithosObjectRequest *objectRequest = [PithosUtilities 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];
+                PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove 
+                                                                           message:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", 
+                                                                                    [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
+                                                                                    [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
+                                                                                    [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
+                                                                                    [objectRequest.userInfo objectForKey:@"destinationObjectName"]]];
+                [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
+                 [NSDictionary dictionaryWithObjectsAndKeys:
+                  [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", 
+                  [NSNumber numberWithBool:YES], @"refresh", 
+                  activity, @"activity", 
+                  [NSNumber numberWithUnsignedInteger:10], @"retries", 
+                  nil]];
+                [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
             }
         });
     } else if ([node class] == [PithosSubdirNode class]) {
             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 
-                                                  sharingAccount:nil]) {
+            if ([PithosUtilities objectExistsAtContainerName:node.pithosContainer.name 
+                                                  objectName:destinationObjectName 
+                                                       error:&error 
+                                                 isDirectory:&isDirectory 
+                                              sharingAccount:nil]) {
                 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]];
             }
             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];
+            NSArray *objectRequests = [PithosUtilities 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];
+                    PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove 
+                                                                               message:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", 
+                                                                                        [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
+                                                                                        [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
+                                                                                        [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
+                                                                                        [objectRequest.userInfo objectForKey:@"destinationObjectName"]]];
+                    [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
+                     [NSDictionary dictionaryWithObjectsAndKeys:
+                      [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", 
+                      [NSNumber numberWithBool:YES], @"refresh", 
+                      activity, @"activity", 
+                      [NSNumber numberWithUnsignedInteger:10], @"retries", 
+                      nil]];
+                    [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
                 }
             }
         });
@@ -545,13 +563,13 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
             if (choice == NSAlertFirstButtonReturn) {
                 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
                 dispatch_async(queue, ^{
-                    NSArray *objectRequests = [PithosFileUtilities objectDataRequestsForSubdirWithContainerName:node.pithosContainer.name 
+                    NSArray *objectRequests = [PithosUtilities objectDataRequestsForSubdirWithContainerName:node.pithosContainer.name 
                                                                                                      objectName:node.pithosObject.name 
                                                                                                     toDirectory:[dropDestination path] 
                                                                                                   checkIfExists:YES 
                                                                                                  sharingAccount:node.sharingAccount];
                     if (objectRequests) {
-                        for (ASIPithosObjectRequest *objectRequest in objectRequests) {
+                        for (__block ASIPithosObjectRequest *objectRequest in objectRequests) {
                             [names addObject:[objectRequest.userInfo valueForKey:@"fileName"]];
                             objectRequest.delegate = self;
                             objectRequest.didFinishSelector = @selector(downloadObjectFinished:);
@@ -560,18 +578,28 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                                                                                        message:[NSString stringWithFormat:@"Downloading '%@' (0%%)", [objectRequest.userInfo objectForKey:@"fileName"]] 
                                                                                     totalBytes:[[objectRequest.userInfo objectForKey:@"bytes"] unsignedIntegerValue] 
                                                                                   currentBytes:0];
-                            [(NSMutableDictionary *)objectRequest.userInfo setObject:activity forKey:@"activity"];
-                            [objectRequest startAsynchronous];
+                            [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
+                             [NSDictionary dictionaryWithObjectsAndKeys:
+                              activity, @"activity", 
+                              [NSNumber numberWithUnsignedInteger:10], @"retries", 
+                              nil]];
+                            [objectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){
+                                [activityFacility updateActivity:activity 
+                                                     withMessage:[NSString stringWithFormat:@"Downloading '%@' (%.0f%%)", [objectRequest.userInfo valueForKey:@"fileName"], (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))] 
+                                                      totalBytes:activity.totalBytes 
+                                                    currentBytes:(activity.currentBytes + size)];
+                            }];
+                            [[PithosUtilities prepareRequest:objectRequest] startAsynchronous];
                         }
                     }
                 });
             }
         } else {
-            ASIPithosObjectRequest *objectRequest = [PithosFileUtilities objectDataRequestWithContainerName:node.pithosContainer.name 
-                                                                                                 objectName:node.pithosObject.name 
-                                                                                                toDirectory:[dropDestination path] 
-                                                                                              checkIfExists:YES 
-                                                                                             sharingAccount:node.sharingAccount];
+            __block ASIPithosObjectRequest *objectRequest = [PithosUtilities objectDataRequestWithContainerName:node.pithosContainer.name 
+                                                                                                     objectName:node.pithosObject.name 
+                                                                                                    toDirectory:[dropDestination path] 
+                                                                                                  checkIfExists:YES 
+                                                                                                 sharingAccount:node.sharingAccount];
             if (objectRequest) {
                 [names addObject:[objectRequest.userInfo valueForKey:@"fileName"]];
                 objectRequest.delegate = self;
@@ -581,8 +609,18 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                                                                            message:[NSString stringWithFormat:@"Downloading '%@' (0%%)", [objectRequest.userInfo valueForKey:@"fileName"]]
                                                                         totalBytes:node.pithosObject.bytes 
                                                                       currentBytes:0];
-                [(NSMutableDictionary *)objectRequest.userInfo setObject:activity forKey:@"activity"];
-                [objectRequest startAsynchronous];
+                [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
+                 [NSDictionary dictionaryWithObjectsAndKeys:
+                  activity, @"activity", 
+                  [NSNumber numberWithUnsignedInteger:10], @"retries", 
+                  nil]];
+                [objectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){
+                    [activityFacility updateActivity:activity 
+                                         withMessage:[NSString stringWithFormat:@"Downloading '%@' (%.0f%%)", [objectRequest.userInfo valueForKey:@"fileName"], (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))] 
+                                          totalBytes:activity.totalBytes 
+                                        currentBytes:(activity.currentBytes + size)];
+                }];
+                [[PithosUtilities prepareRequest:objectRequest] startAsynchronous];
             }
         }
     }
@@ -671,7 +709,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
         NSArray *filenames = [[info draggingPasteboard] propertyListForType:NSFilenamesPboardType];
         NSLog(@"drag in operation: %lu filenames: %@", [info draggingSourceOperationMask], filenames);
         if ((column != -1) && (filenames != nil)) {
-            PithosNode *node = nil;
+            PithosNode *node;
             if (row != -1)
                 node = [browser itemAtRow:row inColumn:column];
             else
@@ -682,7 +720,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
     } else if ([[[info draggingPasteboard] types] containsObject:NSFilesPromisePboardType]) {
         NSLog(@"drag local operation: %lu nodes: %@", [info draggingSourceOperationMask], draggedNodes);
         if ((column != -1) && (draggedNodes != nil)) {
-            PithosNode *node = nil;
+            PithosNode *node;
             if (row != -1)
                 node = [browser itemAtRow:row inColumn:column];
             else
@@ -712,12 +750,15 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
         objectNamePrefix = [NSString string];
     if ((destinationNode.pithosContainer.blockHash == nil) || (destinationNode.pithosContainer.blockSize == 0)) {
         ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest containerMetadataRequestWithContainerName:containerName];
-        [containerRequest startSynchronous];
+        [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
+        while (![containerRequest isFinished]) {
+            sleep(1);
+        }
         if ([containerRequest error]) {
-            [PithosFileUtilities httpRequestErrorAlertWithRequest:containerRequest];
+            [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest];
             return NO;
         } else if (containerRequest.responseStatusCode != 200) {
-            [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:containerRequest];
+            [PithosUtilities unexpectedResponseStatusAlertWithRequest:containerRequest];
             return NO;
         }
         destinationNode.pithosContainer.blockHash = [containerRequest blockHash];
@@ -735,21 +776,21 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                 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];
+                    NSString *contentType = [PithosUtilities 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 
-                                                                                                          sharingAccount:destinationNode.sharingAccount];
+                    ASIPithosObjectRequest *objectRequest = [PithosUtilities writeObjectDataRequestWithContainerName:containerName 
+                                                                                                          objectName:objectName 
+                                                                                                         contentType:contentType 
+                                                                                                           blockSize:blockSize 
+                                                                                                           blockHash:blockHash 
+                                                                                                             forFile:filePath 
+                                                                                                       checkIfExists:YES 
+                                                                                                              hashes:&hashes 
+                                                                                                      sharingAccount:destinationNode.sharingAccount];
                     if (objectRequest) {
                         objectRequest.delegate = self;
                         objectRequest.didFinishSelector = @selector(uploadObjectUsingHashMapFinished:);
@@ -767,13 +808,15 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                           blockHash, @"blockHash", 
                           filePath, @"filePath", 
                           hashes, @"hashes", 
-                          destinationNode, @"node", 
+                          [NSArray arrayWithObject:destinationNode], @"refreshNodes", 
+                          [NSNumber numberWithBool:YES], @"refresh", 
                           [NSNumber numberWithUnsignedInteger:10], @"iteration", 
                           activity, @"activity", 
+                          [NSNumber numberWithUnsignedInteger:10], @"retries", 
                           nil]];
                         if (destinationNode.sharingAccount)
                             [(NSMutableDictionary *)objectRequest.userInfo setObject:destinationNode.sharingAccount forKey:@"sharingAccount"];
-                        [objectRequest startAsynchronous];
+                        [[PithosUtilities prepareRequest:objectRequest] startAsynchronous];
                     }
                 });
             } else {
@@ -793,7 +836,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                         NSMutableArray *filePaths = nil;
                         NSMutableArray *hashesArrays = nil;
                         NSMutableArray *directoryObjectRequests = nil;
-                        NSArray *objectRequests = [PithosFileUtilities writeObjectDataRequestsWithContainerName:containerName 
+                        NSArray *objectRequests = [PithosUtilities writeObjectDataRequestsWithContainerName:containerName 
                                                                                                      objectName:objectName 
                                                                                                       blockSize:blockSize 
                                                                                                       blockHash:blockHash 
@@ -809,7 +852,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                             objectRequest.delegate = self;
                             objectRequest.didFinishSelector = @selector(uploadDirectoryObjectFinished:);
                             objectRequest.didFailSelector = @selector(uploadDirectoryObjectFailed:);
-                            [objectRequest startAsynchronous];
+                            [[PithosUtilities prepareRequest:objectRequest] startAsynchronous];
                         }
                         if (objectRequests) {
                             for (NSUInteger i = 0 ; i < [objectRequests count] ; i++) {
@@ -830,12 +873,14 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                                   blockHash, @"blockHash", 
                                   [filePaths objectAtIndex:i], @"filePath", 
                                   [hashesArrays objectAtIndex:i], @"hashes", 
+                                  [NSNumber numberWithBool:YES], @"refresh", 
                                   [NSNumber numberWithUnsignedInteger:10], @"iteration", 
                                   activity, @"activity", 
+                                  [NSNumber numberWithUnsignedInteger:10], @"retries", 
                                   nil]];
                                 if (destinationNode.sharingAccount)
                                     [(NSMutableDictionary *)objectRequest.userInfo setObject:destinationNode.sharingAccount forKey:@"sharingAccount"];
-                                [objectRequest startAsynchronous];
+                                [[PithosUtilities prepareRequest:objectRequest] startAsynchronous];
                             }
                         }
                     });
@@ -847,7 +892,8 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
 }
 
 - (BOOL)moveNodes:(NSArray *)nodes toNode:(PithosNode *)destinationNode {
-    if (([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class]))
+    if ((([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class])) ||
+        (([destinationNode class] == [PithosSubdirNode class]) && !destinationNode.pithosObject.subdir && [destinationNode.pithosObject.name hasSuffix:@"/"])) 
         return NO;
     NSString *containerName = [NSString stringWithString:destinationNode.pithosContainer.name];
     NSString *objectNamePrefix;
@@ -858,15 +904,13 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
 
     for (PithosNode *node in nodes) {
         if (([node class] == [PithosObjectNode class]) || 
-            (([node class] == [PithosSubdirNode class]) && 
-             !node.pithosObject.subdir &&
-             [node.pithosObject.name hasSuffix:@"/"])) {
+            (([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 
+                ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithContainerName:node.pithosContainer.name 
                                                                                                      objectName:node.pithosObject.name 
                                                                                        destinationContainerName:containerName 
                                                                                           destinationObjectName:destinationObjectName 
@@ -875,11 +919,19 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                     objectRequest.delegate = self;
                     objectRequest.didFinishSelector = @selector(moveFinished:);
                     objectRequest.didFailSelector = @selector(moveFailed:);
-                    objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
-                                              node.parent, @"node", 
-                                              destinationNode, @"dropNode", 
-                                              nil];
-                    [objectRequest startAsynchronous];
+                    PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove 
+                                                                               message:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", 
+                                                                                        [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
+                                                                                        [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
+                                                                                        [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
+                                                                                        [objectRequest.userInfo objectForKey:@"destinationObjectName"]]];
+                    [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
+                     [NSDictionary dictionaryWithObjectsAndKeys:
+                      [NSArray arrayWithObjects:node.parent, destinationNode, nil], @"forceRefreshNodes", 
+                      activity, @"activity", 
+                      [NSNumber numberWithUnsignedInteger:10], @"retries", 
+                      nil]];
+                    [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
                 }
             });
         } else if ([node class] == [PithosSubdirNode class]) {
@@ -888,7 +940,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                 NSString *destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
                 if (node.pithosObject.subdir)
                     destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
-                NSArray *objectRequests = [PithosFileUtilities moveObjectRequestsForSubdirWithContainerName:node.pithosContainer.name 
+                NSArray *objectRequests = [PithosUtilities moveObjectRequestsForSubdirWithContainerName:node.pithosContainer.name 
                                                                                                  objectName:node.pithosObject.name 
                                                                                    destinationContainerName:containerName 
                                                                                       destinationObjectName:destinationObjectName 
@@ -898,11 +950,20 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                         objectRequest.delegate = self;
                         objectRequest.didFinishSelector = @selector(moveFinished:);
                         objectRequest.didFailSelector = @selector(moveFailed:);
-                        objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
-                                                  node.parent, @"node", 
-                                                  destinationNode, @"dropNode", 
-                                                  nil];
-                        [objectRequest startAsynchronous];
+                        PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove 
+                                                                                   message:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", 
+                                                                                            [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
+                                                                                            [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
+                                                                                            [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
+                                                                                            [objectRequest.userInfo objectForKey:@"destinationObjectName"]]];
+                        [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
+                         [NSDictionary dictionaryWithObjectsAndKeys:
+                          [NSArray arrayWithObjects:node.parent, destinationNode, nil], @"forceRefreshNodes", 
+                          [NSNumber numberWithBool:YES], @"refresh", 
+                          activity, @"activity", 
+                          [NSNumber numberWithUnsignedInteger:10], @"retries", 
+                          nil]];
+                        [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
                     }
                 }
             });
@@ -912,7 +973,8 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
 }
 
 - (BOOL)copyNodes:(NSArray *)nodes toNode:(PithosNode *)destinationNode {    
-    if (([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class]))
+    if ((([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class])) ||
+        (([destinationNode class] == [PithosSubdirNode class]) && !destinationNode.pithosObject.subdir && [destinationNode.pithosObject.name hasSuffix:@"/"])) 
         return NO;
     NSString *containerName = [NSString stringWithString:destinationNode.pithosContainer.name];
     NSString *objectNamePrefix;
@@ -923,9 +985,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
     
     for (PithosNode *node in nodes) {
         if (([node class] == [PithosObjectNode class]) || 
-            (([node class] == [PithosSubdirNode class]) && 
-             !node.pithosObject.subdir &&
-             [node.pithosObject.name hasSuffix:@"/"])) {
+            (([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;
@@ -934,23 +994,32 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                     if ([node.pithosObject.name hasSuffix:@"/"])
                         destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
                 } else {
-                    destinationObjectName = [PithosFileUtilities safeObjectNameForContainerName:containerName 
-                                                                                     objectName:node.pithosObject.name];
+                    destinationObjectName = [PithosUtilities safeObjectNameForContainerName:containerName 
+                                                                                 objectName:node.pithosObject.name];
                 }
-                ASIPithosObjectRequest *objectRequest = [PithosFileUtilities copyObjectRequestWithContainerName:node.pithosContainer.name 
+                ASIPithosObjectRequest *objectRequest = [PithosUtilities copyObjectRequestWithContainerName:node.pithosContainer.name 
                                                                                                      objectName:node.pithosObject.name 
                                                                                        destinationContainerName:containerName 
                                                                                           destinationObjectName:destinationObjectName 
                                                                                                   checkIfExists:YES 
-                                                                                                 sharingAccount:nil];
+                                                                                                 sharingAccount:node.sharingAccount];
                 if (objectRequest) {
                     objectRequest.delegate = self;
                     objectRequest.didFinishSelector = @selector(copyFinished:);
                     objectRequest.didFailSelector = @selector(copyFailed:);
-                    objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
-                                              destinationNode, @"dropNode", 
-                                              nil];
-                    [objectRequest startAsynchronous];
+                    PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCopy 
+                                                                               message:[NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@'", 
+                                                                                        [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
+                                                                                        [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
+                                                                                        [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
+                                                                                        [objectRequest.userInfo objectForKey:@"destinationObjectName"]]];
+                    [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
+                     [NSDictionary dictionaryWithObjectsAndKeys:
+                      [NSArray arrayWithObject:destinationNode], @"forceRefreshNodes", 
+                      activity, @"activity", 
+                      [NSNumber numberWithUnsignedInteger:10], @"retries", 
+                      nil]];
+                    [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
                 }
             });
         } else if ([node class] == [PithosSubdirNode class]) {
@@ -962,24 +1031,33 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                     if (node.pithosObject.subdir)
                         destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
                 } else {
-                    destinationObjectName = [PithosFileUtilities safeSubdirNameForContainerName:containerName 
+                    destinationObjectName = [PithosUtilities safeSubdirNameForContainerName:containerName 
                                                                                      subdirName:node.pithosObject.name];
                 }
-                NSArray *objectRequests = [PithosFileUtilities copyObjectRequestsForSubdirWithContainerName:node.pithosContainer.name 
+                NSArray *objectRequests = [PithosUtilities copyObjectRequestsForSubdirWithContainerName:node.pithosContainer.name 
                                                                                                  objectName:node.pithosObject.name 
                                                                                    destinationContainerName:containerName 
                                                                                       destinationObjectName:destinationObjectName 
                                                                                               checkIfExists:YES 
-                                                                                             sharingAccount:nil];
+                                                                                             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:
-                                                  destinationNode, @"dropNode", 
-                                                  nil];
-                        [objectRequest startAsynchronous];
+                        PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCopy 
+                                                                                   message:[NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@'", 
+                                                                                            [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
+                                                                                            [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
+                                                                                            [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
+                                                                                            [objectRequest.userInfo objectForKey:@"destinationObjectName"]]];
+                        [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
+                         [NSDictionary dictionaryWithObjectsAndKeys:
+                          [NSArray arrayWithObject:destinationNode], @"forceRefreshNodes", 
+                          activity, @"activity", 
+                          [NSNumber numberWithUnsignedInteger:10], @"retries", 
+                          nil]];
+                        [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
                     }
                 }
             });
@@ -992,16 +1070,13 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
 #pragma mark ASIHTTPRequestDelegate
 
 - (void)downloadObjectFinished:(ASIPithosObjectRequest *)objectRequest {
-    NSLog(@"Download completed: %@", [objectRequest url]);
-    
-    NSString *fileName = [objectRequest.userInfo objectForKey:@"fileName"];
-    NSString *filePath = [objectRequest.userInfo objectForKey:@"filePath"];
-    PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
-    NSString *activityMessage;
-    NSUInteger totalBytes = activity.totalBytes;
-    NSUInteger currentBytes = activity.currentBytes;
-    
+    NSLog(@"Download finished: %@", objectRequest.url);
     if (objectRequest.responseStatusCode == 200) {
+        NSString *filePath = [objectRequest.userInfo objectForKey:@"filePath"];
+        PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
+        NSUInteger totalBytes = activity.totalBytes;
+        NSUInteger currentBytes = activity.currentBytes;
+        
         // XXX change contentLength to objectContentLength if it is fixed in the server
         if (([objectRequest contentLength] == 0) && (![[objectRequest contentType] isEqualToString:@"application/directory"])) {
             NSLog(@"Downloaded  0 bytes");
@@ -1020,26 +1095,39 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
         currentBytes = [objectRequest objectContentLength];
         if (currentBytes == 0)
             currentBytes = totalBytes;
-        activityMessage = [NSString stringWithFormat:@"Downloading '%@' (100%%)", fileName];
-        
+        [activityFacility endActivity:activity 
+                          withMessage:[NSString stringWithFormat:@"Downloading '%@' (100%%)", 
+                                       [objectRequest.userInfo objectForKey:@"fileName"]] 
+                           totalBytes:totalBytes 
+                         currentBytes:currentBytes];
     } else {
-        [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
-        
-        activityMessage = [NSString stringWithFormat:@"Downloading '%@' (failed)", fileName];
+        NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
+        if (retries > 0) {
+            ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest];
+            [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
+            [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous];
+        } else {
+            [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
+                              withMessage:[NSString stringWithFormat:@"Downloading '%@' (failed)", 
+                                           [objectRequest.userInfo objectForKey:@"fileName"]]];
+            [PithosUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+        }
     }
-    
-    [activityFacility endActivity:activity withMessage:activityMessage totalBytes:totalBytes currentBytes:currentBytes];
 }
 
 - (void)downloadObjectFailed:(ASIPithosObjectRequest *)objectRequest {
-    NSLog(@"Download failed");
-    NSString *fileName = [objectRequest.userInfo objectForKey:@"fileName"];
-    PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
-    [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
-    [activityFacility endActivity:activity 
-                      withMessage:[NSString stringWithFormat:@"Downloading '%@' (failed)", fileName] 
-                       totalBytes:activity.totalBytes 
-                     currentBytes:activity.currentBytes];
+    NSLog(@"Download failed: %@", objectRequest.url);
+    NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
+    if (retries > 0) {
+        ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest];
+        [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
+        [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous];
+    } else {
+        [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
+                          withMessage:[NSString stringWithFormat:@"Downloading '%@' (failed)", 
+                                       [objectRequest.userInfo objectForKey:@"fileName"]]];
+        [PithosUtilities httpRequestErrorAlertWithRequest:objectRequest];
+    }
 }
 
 - (void)uploadDirectoryObjectFinished:(ASIPithosObjectRequest *)objectRequest {
@@ -1048,40 +1136,43 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
         NSLog(@"Directory object created: %@", [objectRequest url]);
         [self refresh:nil];
     } else {
-        [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+        [PithosUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
     }
 }
 
 - (void)uploadDirectoryObjectFailed:(ASIPithosObjectRequest *)objectRequest {
     NSLog(@"Upload directory object failed");
-    [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
+    [PithosUtilities httpRequestErrorAlertWithRequest:objectRequest];
 }
 
 - (void)uploadObjectUsingHashMapFinished:(ASIPithosObjectRequest *)objectRequest {
-    NSLog(@"Upload using hashmap completed: %@", [objectRequest url]);
+    NSLog(@"Upload using hashmap finished: %@", objectRequest.url);
     NSString *fileName = [objectRequest.userInfo objectForKey:@"fileName"];
     PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
     NSUInteger totalBytes = activity.totalBytes;
     NSUInteger currentBytes = activity.currentBytes;
     if (objectRequest.responseStatusCode == 201) {
-        NSLog(@"Object created: %@", [objectRequest url]);
+        NSLog(@"Object created: %@", objectRequest.url);
         [activityFacility endActivity:activity 
                           withMessage:[NSString stringWithFormat:@"Uploading '%@' (100%%)", fileName] 
                            totalBytes:totalBytes 
                          currentBytes:totalBytes];
-        PithosNode *node = [objectRequest.userInfo objectForKey:@"node"];
-        if (node)
+        for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) {
+            [node forceRefresh];
+        }
+        for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) {
             [node refresh];
-        else
-            [self refresh:nil];
+        }
+        if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue])
+            [self forceRefresh:self];
+        else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue])
+            [self refresh:self];        
     } else if (objectRequest.responseStatusCode == 409) {
-        NSUInteger iteration = [[objectRequest.userInfo objectForKey:@"iteration"] unsignedIntegerValue] - 1;
+        NSUInteger iteration = [[objectRequest.userInfo objectForKey:@"iteration"] unsignedIntegerValue];
         if (iteration == 0) {
-            NSLog(@"Upload iteration limit reached: %@", [objectRequest url]);
+            NSLog(@"Upload iteration limit reached: %@", objectRequest.url);
             [activityFacility endActivity:activity 
-                              withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", fileName] 
-                               totalBytes:totalBytes 
-                             currentBytes:currentBytes];
+                              withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", fileName]]; 
             NSAlert *alert = [[[NSAlert alloc] init] autorelease];
             [alert setMessageText:@"Upload Timeout"];
             [alert setInformativeText:[NSString stringWithFormat:@"Upload iteration limit reached for object with path '%@'", 
@@ -1090,48 +1181,68 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
             [alert runModal];
             return;
         }
-        NSLog(@"object is missing hashes: %@", [objectRequest url]);
-        NSIndexSet *missingBlocks = [PithosFileUtilities missingBlocksForHashes:[objectRequest.userInfo objectForKey:@"hashes"]
-                                                      withMissingHashesResponse:[objectRequest responseString]];
+        NSLog(@"object is missing hashes: %@", objectRequest.url);
+        NSIndexSet *missingBlocks = [PithosUtilities missingBlocksForHashes:[objectRequest.userInfo objectForKey:@"hashes"]
+                                                  withMissingHashesResponse:[objectRequest responseString]];
         NSUInteger blockSize = [[objectRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue];
         if (totalBytes >= [missingBlocks count]*blockSize)
             currentBytes = totalBytes - [missingBlocks count]*blockSize;
+        [activityFacility updateActivity:activity 
+                             withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.0f%%)", fileName, (100*(currentBytes + 0.0)/(totalBytes + 0.0))] 
+                              totalBytes:totalBytes 
+                            currentBytes:currentBytes];
         NSUInteger missingBlockIndex = [missingBlocks firstIndex];
-        ASIPithosContainerRequest *newContainerRequest = [PithosFileUtilities updateContainerDataRequestWithContainerName:[objectRequest.userInfo objectForKey:@"containerName"] 
-                                                                                                                blockSize:blockSize 
-                                                                                                                  forFile:[objectRequest.userInfo objectForKey:@"filePath"] 
-                                                                                                        missingBlockIndex:missingBlockIndex 
-                                                                                                           sharingAccount:[objectRequest.userInfo objectForKey:@"sharingAccount"]];
+        __block ASIPithosContainerRequest *newContainerRequest = [PithosUtilities updateContainerDataRequestWithContainerName:[objectRequest.userInfo objectForKey:@"containerName"] 
+                                                                                                                    blockSize:blockSize 
+                                                                                                                      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:[NSNumber numberWithUnsignedInteger:(--iteration)] forKey:@"iteration"];
+        [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
         [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:missingBlocks forKey:@"missingBlocks"];
         [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
-        [activityFacility updateActivity:activity 
-                          withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.2f%%)", fileName, (100*(currentBytes + 0.0)/(totalBytes + 0.0))] 
-                           totalBytes:totalBytes 
-                         currentBytes:currentBytes];
-        [newContainerRequest startAsynchronous];
+        [newContainerRequest setBytesSentBlock:^(unsigned long long size, unsigned long long total){
+            [activityFacility updateActivity:activity 
+                                 withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.0f%%)", fileName, (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))] 
+                                  totalBytes:activity.totalBytes 
+                                currentBytes:(activity.currentBytes + size)];
+        }];
+        [[PithosUtilities prepareRequest:newContainerRequest] startAsynchronous];
     } else {
-        [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+        NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
+        if (retries > 0) {
+            ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest];
+            [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
+            [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous];
+        } else {
+            [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
+                              withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", fileName]];
+            [PithosUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+        }
     }
 }
 
 - (void)uploadObjectUsingHashMapFailed:(ASIPithosObjectRequest *)objectRequest {
-    NSLog(@"Upload using hashmap failed");
-    NSString *fileName = [objectRequest.userInfo objectForKey:@"fileName"];
-    PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
-    [activityFacility endActivity:activity 
-                      withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", fileName] 
-                       totalBytes:activity.totalBytes 
-                     currentBytes:activity.currentBytes];
-    [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
+    NSLog(@"Upload using hashmap failed: %@", objectRequest.url);
+    NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
+    if (retries > 0) {
+        ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest];
+        [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
+        [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous];
+    } else {
+        [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
+                          withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", 
+                                       [objectRequest.userInfo objectForKey:@"fileName"]]];
+        [PithosUtilities httpRequestErrorAlertWithRequest:objectRequest];
+    }
 }
 
 - (void)uploadMissingBlockFinished:(ASIPithosContainerRequest *)containerRequest {
-    NSLog(@"Upload of missing block completed: %@", [containerRequest url]);
+    NSLog(@"Upload of missing block finished: %@", containerRequest.url);
     NSUInteger blockSize = [[containerRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue];
     NSString *fileName = [containerRequest.userInfo objectForKey:@"fileName"];
     PithosActivity *activity = [containerRequest.userInfo objectForKey:@"activity"];
@@ -1140,105 +1251,189 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
     if (currentBytes > totalBytes)
         currentBytes = totalBytes;
     if (containerRequest.responseStatusCode == 202) {
+        [activityFacility updateActivity:activity 
+                             withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.0f%%)", fileName, (100*(currentBytes + 0.0)/(totalBytes + 0.0))] 
+                              totalBytes:totalBytes 
+                            currentBytes:currentBytes];
         NSIndexSet *missingBlocks = [containerRequest.userInfo objectForKey:@"missingBlocks"];
         NSUInteger missingBlockIndex = [[containerRequest.userInfo objectForKey:@"missingBlockIndex"] unsignedIntegerValue];
         missingBlockIndex = [missingBlocks indexGreaterThanIndex:missingBlockIndex];
         if (missingBlockIndex == NSNotFound) {
             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:blockSize 
-                                                                                                          blockHash:[containerRequest.userInfo objectForKey:@"blockHash"]
-                                                                                                            forFile:[containerRequest.userInfo objectForKey:@"filePath"] 
-                                                                                                      checkIfExists:NO 
-                                                                                                             hashes:&hashes 
-                                                                                                     sharingAccount:[containerRequest.userInfo objectForKey:@"sharingAccount"]];
+            ASIPithosObjectRequest *newObjectRequest = [PithosUtilities writeObjectDataRequestWithContainerName:[containerRequest.userInfo objectForKey:@"containerName"] 
+                                                                                                     objectName:[containerRequest.userInfo objectForKey:@"objectName"] 
+                                                                                                    contentType:[containerRequest.userInfo objectForKey:@"contentType"] 
+                                                                                                      blockSize:blockSize 
+                                                                                                      blockHash:[containerRequest.userInfo objectForKey:@"blockHash"]
+                                                                                                        forFile:[containerRequest.userInfo objectForKey:@"filePath"] 
+                                                                                                  checkIfExists:NO 
+                                                                                                         hashes:&hashes 
+                                                                                                 sharingAccount:[containerRequest.userInfo objectForKey:@"sharingAccount"]];
             newObjectRequest.delegate = self;
             newObjectRequest.didFinishSelector = @selector(uploadObjectUsingHashMapFinished:);
             newObjectRequest.didFailSelector = @selector(uploadObjectUsingHashMapFailed:);
             newObjectRequest.userInfo = containerRequest.userInfo;
+            [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
             [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlocks"];
             [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlockIndex"];
-            [activityFacility updateActivity:activity 
-                                 withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.2f%%)", fileName, (100*(currentBytes + 0.0)/(totalBytes + 0.0))] 
-                                  totalBytes:totalBytes 
-                                currentBytes:currentBytes];
-            [newObjectRequest startAsynchronous];
+            [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous];
         } else {
-            ASIPithosContainerRequest *newContainerRequest = [PithosFileUtilities updateContainerDataRequestWithContainerName:[containerRequest.userInfo objectForKey:@"containerName"]
-                                                                                                           blockSize:[[containerRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue]
-                                                                                                             forFile:[containerRequest.userInfo objectForKey:@"filePath"] 
-                                                                                                   missingBlockIndex:missingBlockIndex 
-                                                                                                      sharingAccount:[containerRequest.userInfo objectForKey:@"sharingAccount"]];
+            __block ASIPithosContainerRequest *newContainerRequest = [PithosUtilities updateContainerDataRequestWithContainerName:[containerRequest.userInfo objectForKey:@"containerName"]
+                                                                                                                        blockSize:[[containerRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue]
+                                                                                                                          forFile:[containerRequest.userInfo objectForKey:@"filePath"] 
+                                                                                                                missingBlockIndex:missingBlockIndex 
+                                                                                                                   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:10] forKey:@"retries"];
             [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
-            [activityFacility updateActivity:activity 
-                                 withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.2f%%)", fileName, (100*(currentBytes + 0.0)/(totalBytes + 0.0))] 
-                                  totalBytes:totalBytes 
-                                currentBytes:currentBytes];
-            [newContainerRequest startAsynchronous];
+            [newContainerRequest setBytesSentBlock:^(unsigned long long size, unsigned long long total){
+                [activityFacility updateActivity:activity 
+                                     withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.0f%%)", fileName, (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))] 
+                                      totalBytes:activity.totalBytes 
+                                    currentBytes:(activity.currentBytes + size)];
+            }];
+            [[PithosUtilities prepareRequest:newContainerRequest] startAsynchronous];
         }
     } else {
-        [activityFacility endActivity:activity 
-                          withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", fileName] 
-                           totalBytes:activity.totalBytes 
-                         currentBytes:activity.currentBytes];
-        [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:containerRequest];
+        NSUInteger retries = [[containerRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
+        if (retries > 0) {
+            ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[PithosUtilities copyRequest:containerRequest];
+            [(NSMutableDictionary *)(newContainerRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
+            [[PithosUtilities prepareRequest:newContainerRequest] startAsynchronous];
+        } else {
+            [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"] 
+                              withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", fileName]];
+            [PithosUtilities unexpectedResponseStatusAlertWithRequest:containerRequest];
+        }
     }
 }
 
 - (void)uploadMissingBlockFailed:(ASIPithosContainerRequest *)containerRequest {
-    NSLog(@"Upload of missing block failed");
-    NSString *fileName = [containerRequest.userInfo objectForKey:@"fileName"];
-    PithosActivity *activity = [containerRequest.userInfo objectForKey:@"activity"];
-    [activityFacility endActivity:activity 
-                      withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", fileName] 
-                       totalBytes:activity.totalBytes 
-                     currentBytes:activity.currentBytes];
-    [PithosFileUtilities httpRequestErrorAlertWithRequest:containerRequest];
+    NSLog(@"Upload of missing block failed: %@", containerRequest.url);
+    NSUInteger retries = [[containerRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
+    if (retries > 0) {
+        ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[PithosUtilities copyRequest:containerRequest];
+        [(NSMutableDictionary *)(newContainerRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
+        [[PithosUtilities prepareRequest:newContainerRequest] startAsynchronous];
+    } else {
+        [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"] 
+                          withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", 
+                                       [containerRequest.userInfo objectForKey:@"fileName"]]];
+        [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest];
+    }
 }
 
 - (void)moveFinished:(ASIPithosObjectRequest *)objectRequest {
-    NSLog(@"Move object completed: %@", [objectRequest url]);
+    NSLog(@"Move object finished: %@", objectRequest.url);
     if (objectRequest.responseStatusCode == 201) {
-        PithosNode *node = [objectRequest.userInfo objectForKey:@"node"];
-        PithosNode *dropNode = [objectRequest.userInfo objectForKey:@"dropNode"];
-        if (node)
+        [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
+                          withMessage:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@' (finished)", 
+                                       [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
+                                       [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
+                                       [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
+                                       [objectRequest.userInfo objectForKey:@"destinationObjectName"]]];
+        for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) {
+            [node forceRefresh];
+        }
+        for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) {
             [node refresh];
-        if (dropNode)
-            [dropNode refresh];
-        if (!node || !dropNode)
-            [self refresh:nil];
+        }
+        if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue])
+            [self forceRefresh:self];
+        else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue])
+            [self refresh:self];
     } else {
-        [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+        NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
+        if (retries > 0) {
+            ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest];
+            [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
+            [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
+        } else {
+            [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
+                              withMessage:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@' (failed)", 
+                                           [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
+                                           [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
+                                           [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
+                                           [objectRequest.userInfo objectForKey:@"destinationObjectName"]]];
+            [PithosUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+        }
     }
 }
 
 - (void)moveFailed:(ASIPithosObjectRequest *)objectRequest {
-    NSLog(@"Move object failed");
-    [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
+    NSLog(@"Move object failed: %@", objectRequest.url);
+    NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
+    if (retries > 0) {
+        ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest];
+        [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
+        [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
+    } else {
+        [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
+                          withMessage:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@' failed", 
+                                       [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
+                                       [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
+                                       [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
+                                       [objectRequest.userInfo objectForKey:@"destinationObjectName"]]];
+        [PithosUtilities httpRequestErrorAlertWithRequest:objectRequest];
+    }
 }
 
 - (void)copyFinished:(ASIPithosObjectRequest *)objectRequest {
-    NSLog(@"Copy object completed: %@", [objectRequest url]);
+    NSLog(@"Copy object finished: %@", objectRequest.url);
     if (objectRequest.responseStatusCode == 201) {
-        PithosNode *dropNode = [objectRequest.userInfo objectForKey:@"dropNode"];
-        if (dropNode)
-            [dropNode refresh];
-        else
-            [self refresh:nil];
+        [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
+                          withMessage:[NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@' (finished)", 
+                                       [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
+                                       [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
+                                       [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
+                                       [objectRequest.userInfo objectForKey:@"destinationObjectName"]]];
+        for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) {
+            [node forceRefresh];
+        }
+        for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) {
+            [node refresh];
+        }
+        if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue])
+            [self forceRefresh:self];
+        else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue])
+            [self refresh:self];
     } else {
-        [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+        NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
+        if (retries > 0) {
+            ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest];
+            [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
+            [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
+        } else {
+            [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
+                              withMessage:[NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@' (failed)", 
+                                           [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
+                                           [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
+                                           [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
+                                           [objectRequest.userInfo objectForKey:@"destinationObjectName"]]];
+            [PithosUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+        }
     }
 }
 
 - (void)copyFailed:(ASIPithosObjectRequest *)objectRequest {
-    NSLog(@"Copy object failed");
-    [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
+    NSLog(@"Copy object failed: %@", objectRequest.url);
+    NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
+    if (retries > 0) {
+        ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest];
+        [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
+        [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
+    } else {
+        [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
+                          withMessage:[NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@' failed", 
+                                       [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
+                                       [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
+                                       [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
+                                       [objectRequest.userInfo objectForKey:@"destinationObjectName"]]];
+        [PithosUtilities httpRequestErrorAlertWithRequest:objectRequest];
+    }
 }
 
 #pragma mark -
@@ -1248,14 +1443,14 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
     if (splitView == verticalSplitView)
         return 120;
     else
-        return ([horizontalSplitView bounds].size.height - 101);
+        return ([horizontalSplitView bounds].size.height - 108);
 }
 
 - (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex {
     if (splitView == verticalSplitView)
         return 220;
     else
-        return ([horizontalSplitView bounds].size.height - 101);
+        return ([horizontalSplitView bounds].size.height - 108);
 }
 
 - (CGFloat)splitView:(NSSplitView *)splitView constrainSplitPosition:(CGFloat)proposedPosition ofSubviewAt:(NSInteger)dividerIndex {
@@ -1267,7 +1462,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
         else
             return proposedPosition;
     } else {
-        return ([horizontalSplitView bounds].size.height - 101);
+        return ([horizontalSplitView bounds].size.height - 108);
     }
 }
 
@@ -1546,7 +1741,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
     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 
+            NSString *safeObjectName = [PithosUtilities safeSubdirNameForContainerName:node.pithosContainer.name 
                                                                                 subdirName:@"untitled folder"];
             ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithContainerName:node.pithosContainer.name 
                                                                                                          objectName:safeObjectName 
@@ -1565,14 +1760,14 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
             objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                       node, @"node", 
                                       nil];
-            [objectRequest startAsynchronous];
+            [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] 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 
+            NSString *safeObjectName = [PithosUtilities safeSubdirNameForContainerName:node.pithosContainer.name 
                                                                                subdirName:[node.pithosObject.name stringByAppendingPathComponent:@"untitled folder"]];
             ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithContainerName:node.pithosContainer.name 
                                                                                                         objectName:safeObjectName 
@@ -1591,7 +1786,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
             objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                      node, @"node", 
                                      nil];
-            [objectRequest startAsynchronous];
+            [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
         });
     }
 }
@@ -1613,18 +1808,18 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
             objectRequest.delegate = self;
             objectRequest.didFinishSelector = @selector(deleteObjectFinished:);
             objectRequest.didFailSelector = @selector(deleteObjectFailed:);
-            [objectRequest startAsynchronous];
+            [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] 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 
+                NSArray *objectRequests = [PithosUtilities 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];
+                        [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
                     }
                 }
             });
@@ -1640,10 +1835,10 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
              [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" 
+                NSString *safeObjectName = [PithosUtilities safeObjectNameForContainerName:@"trash" 
                                                                                     objectName:node.pithosObject.name];
                 if (safeObjectName) {
-                    ASIPithosObjectRequest *objectRequest = [PithosFileUtilities moveObjectRequestWithContainerName:node.pithosContainer.name 
+                    ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithContainerName:node.pithosContainer.name 
                                                                                                          objectName:node.pithosObject.name 
                                                                                            destinationContainerName:@"trash" 
                                                                                               destinationObjectName:safeObjectName 
@@ -1652,17 +1847,17 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                         objectRequest.delegate = self;
                         objectRequest.didFinishSelector = @selector(moveToTrashFinished:);
                         objectRequest.didFailSelector = @selector(moveToTrashFailed:);
-                        [objectRequest startAsynchronous];
+                        [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] 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" 
+                NSString *safeObjectName = [PithosUtilities safeSubdirNameForContainerName:@"trash" 
                                                                                     subdirName:node.pithosObject.name];
                 if (safeObjectName) {
-                    NSArray *objectRequests = [PithosFileUtilities moveObjectRequestsForSubdirWithContainerName:node.pithosContainer.name 
+                    NSArray *objectRequests = [PithosUtilities moveObjectRequestsForSubdirWithContainerName:node.pithosContainer.name 
                                                                                                      objectName:node.pithosObject.name 
                                                                                        destinationContainerName:@"trash" 
                                                                                           destinationObjectName:safeObjectName 
@@ -1672,7 +1867,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
                             objectRequest.delegate = self;
                             objectRequest.didFinishSelector = @selector(moveToTrashFinished:);
                             objectRequest.didFailSelector = @selector(moveToTrashFailed:);
-                            [objectRequest startAsynchronous];
+                            [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
                         }
                     }
                 }
@@ -1697,134 +1892,13 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
     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];
-                        }
-                    }
-                });
-            }
-        }
+        [self moveNodes:localClipboardNodes toNode:dropNode];
     } 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];
-                        }
-                    }
-                });                
-            }
-        }
+        [self copyNodes:localClipboardNodes toNode:dropNode];
     }
 }
     
@@ -1840,13 +1914,13 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
         else
             [self refresh:nil];
     } else {
-        [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+        [PithosUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
     }
 }
 
 - (void)newFolderFailed:(ASIPithosObjectRequest *)objectRequest {
     NSLog(@"Creation of new application/directory object failed");
-    [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
+    [PithosUtilities httpRequestErrorAlertWithRequest:objectRequest];
 }
 
 - (void)deleteObjectFinished:(ASIPithosObjectRequest *)objectRequest {
@@ -1854,13 +1928,13 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
         NSLog(@"Object deleted: %@", [objectRequest url]);
         [self refresh:nil];
     } else {
-        [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+        [PithosUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
     }
 }
 
 - (void)deleteObjectFailed:(ASIPithosObjectRequest *)objectRequest {
     NSLog(@"Delete of object failed");
-    [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
+    [PithosUtilities httpRequestErrorAlertWithRequest:objectRequest];
 }
 
 - (void)moveToTrashFinished:(ASIPithosObjectRequest *)objectRequest {
@@ -1868,13 +1942,13 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
         NSLog(@"Object moved: %@", [objectRequest url]);
         [self refresh:nil];
     } else {
-        [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
+        [PithosUtilities unexpectedResponseStatusAlertWithRequest:objectRequest];
     }
 }
 
 - (void)moveToTrashFailed:(ASIPithosObjectRequest *)objectRequest {
     NSLog(@"Move of object failed");
-    [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest];
+    [PithosUtilities httpRequestErrorAlertWithRequest:objectRequest];
 }
 
 #pragma mark -
@@ -1899,7 +1973,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
     
     if (!message)
         message = [NSString stringWithFormat:@"%@ used", 
-                   [[[[BytesExtendedSizeTransformer alloc] init] autorelease] transformedValue: 
+                   [[[[BytesSizeTransformer alloc] init] autorelease] transformedValue: 
                     [NSNumber numberWithUnsignedInteger:accountNode.pithosAccount.bytesUsed]]];
     [activityTextField setStringValue:message];
 }
index 98d1970..add5c42 100755 (executable)
@@ -12,6 +12,7 @@
                </object>
                <object class="NSArray" key="IBDocument.IntegratedClassDependencies">
                        <bool key="EncodedWithXMLCoder">YES</bool>
+                       <string>NSMenu</string>
                        <string>NSToolbarItem</string>
                        <string>NSButton</string>
                        <string>NSToolbarFlexibleSpaceItem</string>
                                                                                                                                                <object class="NSOutlineView" id="392693553">
                                                                                                                                                        <reference key="NSNextResponder" ref="843429105"/>
                                                                                                                                                        <int key="NSvFlags">4352</int>
-                                                                                                                                                       <string key="NSFrameSize">{180, 299}</string>
+                                                                                                                                                       <string key="NSFrameSize">{180, 292}</string>
                                                                                                                                                        <reference key="NSSuperview" ref="843429105"/>
                                                                                                                                                        <reference key="NSNextKeyView" ref="624286523"/>
                                                                                                                                                        <bool key="NSEnabled">YES</bool>
                                                                                                                                                        <float key="NSOutlineViewIndentationPerLevelKey">14</float>
                                                                                                                                                </object>
                                                                                                                                        </object>
-                                                                                                                                       <string key="NSFrameSize">{180, 299}</string>
+                                                                                                                                       <string key="NSFrameSize">{180, 292}</string>
                                                                                                                                        <reference key="NSSuperview" ref="197496877"/>
                                                                                                                                        <reference key="NSNextKeyView" ref="392693553"/>
                                                                                                                                        <reference key="NSDocView" ref="392693553"/>
                                                                                                                                        <double key="NSPercent">0.97959183673469385</double>
                                                                                                                                </object>
                                                                                                                        </object>
-                                                                                                                       <string key="NSFrameSize">{180, 299}</string>
+                                                                                                                       <string key="NSFrameSize">{180, 292}</string>
                                                                                                                        <reference key="NSSuperview" ref="414504914"/>
                                                                                                                        <reference key="NSNextKeyView" ref="205521010"/>
                                                                                                                        <int key="NSsFlags">528</int>
                                                                                                                        <bytes key="NSScrollAmts">QSAAAEEgAABBoAAAQaAAAA</bytes>
                                                                                                                </object>
                                                                                                        </object>
-                                                                                                       <string key="NSFrameSize">{180, 299}</string>
+                                                                                                       <string key="NSFrameSize">{180, 292}</string>
                                                                                                        <reference key="NSSuperview" ref="462572416"/>
                                                                                                        <reference key="NSNextKeyView" ref="197496877"/>
                                                                                                        <string key="NSClassName">NSView</string>
                                                                                                                        <reference key="NSNextResponder" ref="1047973191"/>
                                                                                                                        <int key="NSvFlags">1290</int>
                                                                                                                        <object class="NSPSMatrix" key="NSDrawMatrix"/>
-                                                                                                                       <string key="NSFrame">{{7, 35}, {166, 12}}</string>
+                                                                                                                       <string key="NSFrame">{{7, 49}, {166, 12}}</string>
                                                                                                                        <reference key="NSSuperview" ref="1047973191"/>
-                                                                                                                       <reference key="NSNextKeyView" ref="620067477"/>
+                                                                                                                       <reference key="NSNextKeyView" ref="987905504"/>
                                                                                                                        <int key="NSpiFlags">16648</int>
                                                                                                                        <double key="NSMaxValue">100</double>
                                                                                                                </object>
                                                                                                                <object class="NSTextField" id="620067477">
                                                                                                                        <reference key="NSNextResponder" ref="1047973191"/>
                                                                                                                        <int key="NSvFlags">266</int>
-                                                                                                                       <string key="NSFrame">{{5, 6}, {170, 28}}</string>
+                                                                                                                       <string key="NSFrame">{{5, 13}, {170, 35}}</string>
                                                                                                                        <reference key="NSSuperview" ref="1047973191"/>
-                                                                                                                       <reference key="NSNextKeyView" ref="987905504"/>
+                                                                                                                       <reference key="NSNextKeyView" ref="744849637"/>
                                                                                                                        <bool key="NSEnabled">YES</bool>
                                                                                                                        <object class="NSTextFieldCell" key="NSCell" id="667098628">
                                                                                                                                <int key="NSCellFlags">67239424</int>
                                                                                                                                <string key="NSContents"/>
                                                                                                                                <object class="NSFont" key="NSSupport">
                                                                                                                                        <string key="NSName">LucidaGrande-Bold</string>
-                                                                                                                                       <double key="NSSize">11</double>
-                                                                                                                                       <int key="NSfFlags">3357</int>
+                                                                                                                                       <double key="NSSize">9</double>
+                                                                                                                                       <int key="NSfFlags">16</int>
                                                                                                                                </object>
                                                                                                                                <reference key="NSControlView" ref="620067477"/>
                                                                                                                                <bool key="NSDrawsBackground">YES</bool>
                                                                                                                                        <string>NeXT TIFF v4.0 pasteboard type</string>
                                                                                                                                </object>
                                                                                                                        </object>
-                                                                                                                       <string key="NSFrame">{{69, 52}, {42, 42}}</string>
+                                                                                                                       <string key="NSFrame">{{69, 66}, {42, 42}}</string>
                                                                                                                        <reference key="NSSuperview" ref="1047973191"/>
-                                                                                                                       <reference key="NSNextKeyView" ref="744849637"/>
+                                                                                                                       <reference key="NSNextKeyView" ref="620067477"/>
                                                                                                                        <bool key="NSEnabled">YES</bool>
                                                                                                                        <object class="NSImageCell" key="NSCell" id="280822281">
                                                                                                                                <int key="NSCellFlags">130560</int>
                                                                                                                        <bool key="NSEditable">YES</bool>
                                                                                                                </object>
                                                                                                        </object>
-                                                                                                       <string key="NSFrame">{{0, 300}, {180, 100}}</string>
+                                                                                                       <string key="NSFrame">{{0, 293}, {180, 107}}</string>
                                                                                                        <reference key="NSSuperview" ref="462572416"/>
                                                                                                        <reference key="NSNextKeyView" ref="805035077"/>
                                                                                                        <string key="NSClassName">NSView</string>
                        <object class="NSUserDefaultsController" id="505454360">
                                <bool key="NSSharedInstance">YES</bool>
                        </object>
+                       <object class="NSMenu" id="584319916">
+                               <string key="NSTitle"/>
+                               <object class="NSMutableArray" key="NSMenuItems">
+                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                               </object>
+                       </object>
+                       <object class="NSMenu" id="924618266">
+                               <string key="NSTitle"/>
+                               <object class="NSMutableArray" key="NSMenuItems">
+                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                               </object>
+                       </object>
                </object>
                <object class="IBObjectContainer" key="IBDocument.Objects">
                        <object class="NSMutableArray" key="connectionRecords">
                                        </object>
                                        <int key="connectionID">177</int>
                                </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">browserMenu</string>
+                                               <reference key="source" ref="1001"/>
+                                               <reference key="destination" ref="924618266"/>
+                                       </object>
+                                       <int key="connectionID">186</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">outlineViewMenu</string>
+                                               <reference key="source" ref="1001"/>
+                                               <reference key="destination" ref="584319916"/>
+                                       </object>
+                                       <int key="connectionID">187</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">menu</string>
+                                               <reference key="source" ref="392693553"/>
+                                               <reference key="destination" ref="584319916"/>
+                                       </object>
+                                       <int key="connectionID">188</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">menu</string>
+                                               <reference key="source" ref="259981942"/>
+                                               <reference key="destination" ref="924618266"/>
+                                       </object>
+                                       <int key="connectionID">189</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">delegate</string>
+                                               <reference key="source" ref="584319916"/>
+                                               <reference key="destination" ref="1001"/>
+                                       </object>
+                                       <int key="connectionID">190</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">delegate</string>
+                                               <reference key="source" ref="924618266"/>
+                                               <reference key="destination" ref="1001"/>
+                                       </object>
+                                       <int key="connectionID">191</int>
+                               </object>
                        </object>
                        <object class="IBMutableOrderedSet" key="objectRecords">
                                <object class="NSArray" key="orderedObjects">
                                                <reference key="object" ref="667098628"/>
                                                <reference key="parent" ref="620067477"/>
                                        </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">178</int>
+                                               <reference key="object" ref="924618266"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                               </object>
+                                               <reference key="parent" ref="0"/>
+                                               <string key="objectName">Menu (Browser)</string>
+                                       </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">182</int>
+                                               <reference key="object" ref="584319916"/>
+                                               <object class="NSMutableArray" key="children">
+                                                       <bool key="EncodedWithXMLCoder">YES</bool>
+                                               </object>
+                                               <reference key="parent" ref="0"/>
+                                               <string key="objectName">Menu (Outline View)</string>
+                                       </object>
                                </object>
                        </object>
                        <object class="NSMutableDictionary" key="flattenedProperties">
                                        <string>162.IBPluginDependency</string>
                                        <string>165.IBPluginDependency</string>
                                        <string>166.IBPluginDependency</string>
+                                       <string>178.IBPluginDependency</string>
                                        <string>18.IBPluginDependency</string>
+                                       <string>182.IBPluginDependency</string>
                                        <string>19.IBPluginDependency</string>
                                        <string>2.IBPluginDependency</string>
                                        <string>20.IBPluginDependency</string>
                                        <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
                                        <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
                                        <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+                                       <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
                                </object>
                        </object>
                        <object class="NSMutableDictionary" key="unlocalizedProperties">
                                <reference key="dict.values" ref="0"/>
                        </object>
                        <nil key="sourceID"/>
-                       <int key="maxID">177</int>
+                       <int key="maxID">193</int>
                </object>
                <object class="IBClassDescriber" key="IBDocument.Classes"/>
                <int key="IBDocument.localizationMode">0</int>
index 0fa0e2a..820456a 100644 (file)
@@ -42,7 +42,7 @@
 #import "ASIPithosContainer.h"
 #import "ASIPithosObject.h"
 #import "ASIDownloadCache.h"
-#import "PithosFileUtilities.h"
+#import "PithosUtilities.h"
 #import "PithosContainerNodeInfoController.h"
 
 static NSImage *sharedIcon = nil;
@@ -134,7 +134,7 @@ static NSImage *sharedIcon = nil;
                 containerRequest.didFailSelector = @selector(containerRequestFailed:);
                 if (!forcedRefresh)
                     containerRequest.downloadCache = [ASIDownloadCache sharedCache];
-                [containerRequest startAsynchronous];
+                [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
                 break;
             case PithosNodeStateRefreshing:
                 break;
@@ -307,12 +307,12 @@ static NSImage *sharedIcon = nil;
         containerRequest.delegate = self;
         if (!forcedRefresh)
         containerRequest.downloadCache = [ASIDownloadCache sharedCache];
-        [containerRequest startAsynchronous];
+        [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
     }
 }
 
 - (void)containerRequestFailed:(ASIPithosContainerRequest *)request {
-    [PithosFileUtilities httpRequestErrorAlertWithRequest:request];
+    [PithosUtilities httpRequestErrorAlertWithRequest:request];
     [newChildren release];
     newChildren = nil;
     [containerRequest release];
@@ -347,13 +347,13 @@ static NSImage *sharedIcon = nil;
 
 - (void)containerMetadataRequestFailed:(ASIPithosContainerRequest *)request {
     if ([request isEqualTo:applyMetadataContainerRequest]) {
-        [PithosFileUtilities httpRequestErrorAlertWithRequest:applyMetadataContainerRequest];
+        [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataContainerRequest];
         @synchronized(self) {
             [applyMetadataContainerRequest release];
             applyMetadataContainerRequest = nil;
         }
     } else if ([request isEqualTo:refreshMetadataContainerRequest]) {
-        [PithosFileUtilities httpRequestErrorAlertWithRequest:refreshMetadataContainerRequest];
+        [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataContainerRequest];
         @synchronized(self) {
             [refreshMetadataContainerRequest release];
             refreshMetadataContainerRequest = nil;
@@ -378,7 +378,7 @@ static NSImage *sharedIcon = nil;
             applyMetadataContainerRequest.delegate = self;
             applyMetadataContainerRequest.didFinishSelector = @selector(containerMetadataRequestFinished:);
             applyMetadataContainerRequest.didFailSelector = @selector(containerMetadataRequestFailed:);
-            [applyMetadataContainerRequest startAsynchronous];
+            [[PithosUtilities prepareRequest:applyMetadataContainerRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
         }
     }
 }
@@ -391,7 +391,7 @@ static NSImage *sharedIcon = nil;
             refreshMetadataContainerRequest.didFinishSelector = @selector(containerMetadataRequestFinished:);
             refreshMetadataContainerRequest.didFailSelector = @selector(containerMetadataRequestFailed:);
             refreshMetadataContainerRequest.downloadCache = [ASIDownloadCache sharedCache];
-            [refreshMetadataContainerRequest startAsynchronous];
+            [[PithosUtilities prepareRequest:refreshMetadataContainerRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
         }
     }
 }
index 7688f79..2c1919f 100644 (file)
@@ -41,7 +41,7 @@
 #import "ASIPithosContainer.h"
 #import "ASIPithosObject.h"
 #import "ASIDownloadCache.h"
-#import "PithosFileUtilities.h"
+#import "PithosUtilities.h"
 #import "PithosObjectNodeInfoController.h"
 
 @implementation PithosObjectNode
     if ([request isEqualTo:applyMetadataObjectRequest]) {
         int responseStatusCode = applyMetadataObjectRequest.responseStatusCode;
         if (responseStatusCode != 202)
-            [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:applyMetadataObjectRequest];
+            [PithosUtilities unexpectedResponseStatusAlertWithRequest:applyMetadataObjectRequest];
         @synchronized(self) {
             [applyMetadataObjectRequest release];
             applyMetadataObjectRequest = nil;
 
 - (void)objectRequestFailed:(ASIPithosObjectRequest *)request {
     if ([request isEqualTo:applyMetadataObjectRequest]) {
-        [PithosFileUtilities httpRequestErrorAlertWithRequest:applyMetadataObjectRequest];
+        [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataObjectRequest];
         @synchronized(self) {
             [applyMetadataObjectRequest release];
             applyMetadataObjectRequest = nil;
         }
     } else if ([request isEqualTo:refreshMetadataObjectRequest]) {
-        [PithosFileUtilities httpRequestErrorAlertWithRequest:refreshMetadataObjectRequest];
+        [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataObjectRequest];
         @synchronized(self) {
             [refreshMetadataObjectRequest release];
             refreshMetadataObjectRequest = nil;
             applyMetadataObjectRequest.delegate = self;
             applyMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:);
             applyMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:);
-            [applyMetadataObjectRequest startAsynchronous];
+            [[PithosUtilities prepareRequest:applyMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
         }
     }
 }
             refreshMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:);
             refreshMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:);
             refreshMetadataObjectRequest.downloadCache = [ASIDownloadCache sharedCache];
-            [refreshMetadataObjectRequest startAsynchronous];
+            [[PithosUtilities prepareRequest:refreshMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
         }
     }
 }
index 76868ce..9802260 100644 (file)
@@ -40,7 +40,7 @@
 #import "ASIPithosRequest.h"
 #import "ASIPithosAccount.h"
 #import "ASIDownloadCache.h"
-#import "PithosFileUtilities.h"
+#import "PithosUtilities.h"
 
 @implementation PithosSharingAccountsNode
 
@@ -84,7 +84,7 @@
                 sharingAccountsRequest.didFailSelector = @selector(sharingAccountsRequestFailed:);
                 if (!forcedRefresh)
                     sharingAccountsRequest.downloadCache = [ASIDownloadCache sharedCache];
-                [sharingAccountsRequest startAsynchronous];
+                [[PithosUtilities prepareRequest:sharingAccountsRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
                 break;
             case PithosNodeStateRefreshing:
                 break;
         sharingAccountsRequest.delegate = self;
         if (!forcedRefresh)
             sharingAccountsRequest.downloadCache = [ASIDownloadCache sharedCache];
-        [sharingAccountsRequest startAsynchronous];
+        [[PithosUtilities prepareRequest:sharingAccountsRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
     }
 }
 
 - (void)accountRequestFailed:(ASIPithosRequest *)request {
-    [PithosFileUtilities httpRequestErrorAlertWithRequest:request];
+    [PithosUtilities httpRequestErrorAlertWithRequest:request];
     [newChildren release];
     newChildren = nil;
     [sharingAccountsRequest release];
index bed0011..8188c46 100644 (file)
@@ -41,7 +41,7 @@
 #import "ASIPithosContainer.h"
 #import "ASIPithosObject.h"
 #import "ASIDownloadCache.h"
-#import "PithosFileUtilities.h"
+#import "PithosUtilities.h"
 #import "PithosObjectNodeInfoController.h"
 
 static NSImage *sharedIcon = nil;
@@ -136,7 +136,7 @@ static NSImage *sharedIcon = nil;
     if ([request isEqualTo:applyMetadataObjectRequest]) {
         int responseStatusCode = applyMetadataObjectRequest.responseStatusCode;
         if ((responseStatusCode != 201) && (responseStatusCode != 202))
-            [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:applyMetadataObjectRequest];
+            [PithosUtilities unexpectedResponseStatusAlertWithRequest:applyMetadataObjectRequest];
         @synchronized(self) {
             [applyMetadataObjectRequest release];
             applyMetadataObjectRequest = nil;
@@ -161,13 +161,13 @@ static NSImage *sharedIcon = nil;
 
 - (void)objectRequestFailed:(ASIPithosObjectRequest *)request {
     if ([request isEqualTo:applyMetadataObjectRequest]) {
-        [PithosFileUtilities httpRequestErrorAlertWithRequest:applyMetadataObjectRequest];
+        [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataObjectRequest];
         @synchronized(self) {
             [applyMetadataObjectRequest release];
             applyMetadataObjectRequest = nil;
         }
     } else if ([request isEqualTo:refreshMetadataObjectRequest]) {
-        [PithosFileUtilities httpRequestErrorAlertWithRequest:refreshMetadataObjectRequest];
+        [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataObjectRequest];
         @synchronized(self) {
             [refreshMetadataObjectRequest release];
             refreshMetadataObjectRequest = nil;
@@ -186,7 +186,10 @@ static NSImage *sharedIcon = nil;
                 NSAlert *alert;
                 ASIPithosObjectRequest *request = [ASIPithosObjectRequest objectMetadataRequestWithContainerName:pithosContainer.name 
                                                                                                       objectName:prefix];
-                [request startSynchronous];
+                [[PithosUtilities prepareRequest:request] startAsynchronous];
+                while (![request isFinished]) {
+                    sleep(1);
+                }
                 if ([request error]) {
                     alert = [[[NSAlert alloc] init] autorelease];
                     [alert setMessageText:@"HTTP Request Error"];
@@ -204,7 +207,10 @@ static NSImage *sharedIcon = nil;
                     if (choice == NSAlertFirstButtonReturn) {
                         request = [ASIPithosObjectRequest deleteObjectRequestWithContainerName:pithosContainer.name 
                                                                                        objectName:prefix];
-                        [request startSynchronous];
+                        [[PithosUtilities prepareRequest:request] startAsynchronous];
+                        while (![request isFinished]) {
+                            sleep(1);
+                        }
                         if ([request error]) {
                             alert = [[[NSAlert alloc] init] autorelease];
                             [alert setMessageText:@"HTTP Request Error"];
@@ -213,7 +219,7 @@ static NSImage *sharedIcon = nil;
                             [alert runModal];
                             return;
                         } else if (request.responseStatusCode != 204) {
-                            [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:request];
+                            [PithosUtilities unexpectedResponseStatusAlertWithRequest:request];
                             return;
                         }
                         refreshParent = YES;
@@ -224,7 +230,7 @@ static NSImage *sharedIcon = nil;
                 } else if (request.responseStatusCode == 404) {
                     createObject = YES;
                 } else {
-                    [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:request];
+                    [PithosUtilities unexpectedResponseStatusAlertWithRequest:request];
                     return;
                 }
                 if (createObject) {
@@ -244,7 +250,7 @@ static NSImage *sharedIcon = nil;
                     applyMetadataObjectRequest.delegate = self;
                     applyMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:);
                     applyMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:);
-                    [applyMetadataObjectRequest startAsynchronous];
+                    [[PithosUtilities prepareRequest:applyMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
                 }
             } else {
                 [[pithosNodeInfoController window] makeFirstResponder:nil];
@@ -273,7 +279,7 @@ static NSImage *sharedIcon = nil;
                 applyMetadataObjectRequest.delegate = self;
                 applyMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:);
                 applyMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:);
-                [applyMetadataObjectRequest startAsynchronous];
+                [[PithosUtilities prepareRequest:applyMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
             }
         }
     }
@@ -292,7 +298,7 @@ static NSImage *sharedIcon = nil;
             refreshMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:);
             refreshMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:);
             refreshMetadataObjectRequest.downloadCache = [ASIDownloadCache sharedCache];
-            [refreshMetadataObjectRequest startAsynchronous];
+            [[PithosUtilities prepareRequest:refreshMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
         }
     }
 }
similarity index 97%
rename from pithos-macos/PithosFileUtilities.h
rename to pithos-macos/PithosUtilities.h
index caf666b..0b8269a 100644 (file)
@@ -39,7 +39,7 @@
 @class ASIPithosContainerRequest;
 @class ASIPithosObjectRequest;
 
-@interface PithosFileUtilities : NSObject
+@interface PithosUtilities : NSObject
 
 + (ASIPithosObjectRequest *)objectDataRequestWithContainerName:(NSString *)containerName 
                                                     objectName:(NSString *)objectName 
 + (NSInteger)httpRequestErrorAlertWithRequest:(ASIPithosRequest *)request;
 + (NSInteger)unexpectedResponseStatusAlertWithRequest:(ASIPithosRequest *)request;
 
++ (ASIPithosRequest *)prepareRequest:(ASIPithosRequest *)request priority:(NSOperationQueuePriority)priority;
++ (ASIPithosRequest *)prepareRequest:(ASIPithosRequest *)request;
++ (ASIPithosRequest *)copyRequest:(ASIPithosRequest *)request;
+
 @end
similarity index 87%
rename from pithos-macos/PithosFileUtilities.m
rename to pithos-macos/PithosUtilities.m
index dd1ee20..5e78e47 100644 (file)
 // interpreted as representing official policies, either expressed
 // or implied, of GRNET S.A.
 
-#import "PithosFileUtilities.h"
+#import "PithosUtilities.h"
 #import "ASIPithosContainerRequest.h"
 #import "ASIPithosObjectRequest.h"
 #import "ASIPithosObject.h"
 #import "HashMapHash.h"
 
-@implementation PithosFileUtilities
+@implementation PithosUtilities
 
 #pragma mark -
 #pragma mark Download
@@ -93,6 +93,7 @@
     if (sharingAccount)
         [objectRequest setRequestUserFromDefaultTo:sharingAccount];
     objectRequest.downloadDestinationPath = destinationPath;
+    objectRequest.allowResumeForFileDownloads = YES;
     objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                               fileName, @"fileName", 
                               destinationPath, @"filePath", 
                                                                                      destinationObjectName:destinationObjectName 
                                                                                         destinationAccount:nil
                                                                                              sourceVersion:nil];
+    objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                              containerName, @"sourceContainerName", 
+                              objectName, @"sourceObjectName", 
+                              destinationContainerName, @"destinationContainerName", 
+                              destinationObjectName, @"destinationObjectName", 
+                              nil];
     if (sharingAccount) 
         [objectRequest setRequestUserFromDefaultTo:sharingAccount];
     return objectRequest;
                                                                      destinationObjectName:objectName 
                                                                         destinationAccount:nil 
                                                                              sourceVersion:nil];
+            objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                      containerName, @"sourceContainerName", 
+                                      objectName, @"sourceObjectName", 
+                                      destinationContainerName, @"destinationContainerName", 
+                                      objectName, @"destinationObjectName", 
+                                      nil];
             if (sharingAccount)
                 [objectRequest setRequestUserFromDefaultTo:sharingAccount];
             [objectRequests addObject:objectRequest];
                                                                      destinationObjectName:object.name 
                                                                         destinationAccount:nil 
                                                                              sourceVersion:nil];
+            objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                      containerName, @"sourceContainerName", 
+                                      object.name, @"sourceObjectName", 
+                                      destinationContainerName, @"destinationContainerName", 
+                                      object.name, @"destinationObjectName", 
+                                      nil];
             if (sharingAccount)
                 [objectRequest setRequestUserFromDefaultTo:sharingAccount];
             [objectRequests addObject:objectRequest];
                                                                      destinationObjectName:destinationObjectName 
                                                                         destinationAccount:nil 
                                                                              sourceVersion:nil];
+            objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                      containerName, @"sourceContainerName", 
+                                      objectName, @"sourceObjectName", 
+                                      destinationContainerName, @"destinationContainerName", 
+                                      destinationObjectName, @"destinationObjectName", 
+                                      nil];
             if (sharingAccount)
                 [objectRequest setRequestUserFromDefaultTo:sharingAccount];
             [objectRequests addObject:objectRequest];
                                                                      destinationObjectName:newObjectName 
                                                                         destinationAccount:nil 
                                                                              sourceVersion:nil];
+            objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                      containerName, @"sourceContainerName", 
+                                      object.name, @"sourceObjectName", 
+                                      destinationContainerName, @"destinationContainerName", 
+                                      newObjectName, @"destinationObjectName", 
+                                      nil];
             if (sharingAccount)
                 [objectRequest setRequestUserFromDefaultTo:sharingAccount];
             [objectRequests addObject:objectRequest];
                                                                                   destinationContainerName:destinationContainerName 
                                                                                      destinationObjectName:destinationObjectName 
                                                                                         destinationAccount:nil];
+    objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                              containerName, @"sourceContainerName", 
+                              objectName, @"sourceObjectName", 
+                              destinationContainerName, @"destinationContainerName", 
+                              destinationObjectName, @"destinationObjectName", 
+                              nil];
     return objectRequest;
 }
 
     if (objects == nil)
         return nil;
     
+    ASIPithosObjectRequest *objectRequest;
     NSMutableArray *objectRequests = [NSMutableArray arrayWithCapacity:([objects count] + 1)];
     if ([objectName isEqualToString:destinationObjectName]) {
-        if (![objectName hasSuffix:@"/"])
-            [objectRequests addObject:[ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName 
-                                                                                          objectName:objectName 
-                                                                                         contentType:nil 
-                                                                                     contentEncoding:nil 
-                                                                                  contentDisposition:nil 
-                                                                                            manifest:nil 
-                                                                                             sharing:nil 
-                                                                                            isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                            metadata:nil 
-                                                                            destinationContainerName:destinationContainerName 
-                                                                               destinationObjectName:objectName 
-                                                                                  destinationAccount:nil]];
+        if (![objectName hasSuffix:@"/"]) {
+            objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName 
+                                                                                objectName:objectName 
+                                                                               contentType:nil 
+                                                                           contentEncoding:nil 
+                                                                        contentDisposition:nil 
+                                                                                  manifest:nil 
+                                                                                   sharing:nil 
+                                                                                  isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                                  metadata:nil 
+                                                                  destinationContainerName:destinationContainerName 
+                                                                     destinationObjectName:objectName 
+                                                                        destinationAccount:nil];
+            objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                      containerName, @"sourceContainerName", 
+                                      objectName, @"sourceObjectName", 
+                                      destinationContainerName, @"destinationContainerName", 
+                                      objectName, @"destinationObjectName", 
+                                      nil];
+            [objectRequests addObject:objectRequest];
+        }
         for (ASIPithosObject *object in objects) {
-            [objectRequests addObject:[ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName 
-                                                                                          objectName:object.name 
-                                                                                         contentType:nil 
-                                                                                     contentEncoding:nil 
-                                                                                  contentDisposition:nil 
-                                                                                            manifest:nil 
-                                                                                             sharing:nil 
-                                                                                            isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                            metadata:nil 
-                                                                            destinationContainerName:destinationContainerName 
-                                                                               destinationObjectName:object.name 
-                                                                                  destinationAccount:nil]];
+            objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName 
+                                                                                objectName:object.name 
+                                                                               contentType:nil 
+                                                                           contentEncoding:nil 
+                                                                        contentDisposition:nil 
+                                                                                  manifest:nil 
+                                                                                   sharing:nil 
+                                                                                  isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                                  metadata:nil 
+                                                                  destinationContainerName:destinationContainerName 
+                                                                     destinationObjectName:object.name 
+                                                                        destinationAccount:nil];
+            objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                      containerName, @"sourceContainerName", 
+                                      object.name, @"sourceObjectName", 
+                                      destinationContainerName, @"destinationContainerName", 
+                                      object.name, @"destinationObjectName", 
+                                      nil];
+            [objectRequests addObject:objectRequest];
         }
     } else {
         if (![objectName hasSuffix:@"/"]) {
-            [objectRequests addObject:[ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName 
-                                                                                          objectName:objectName 
-                                                                                         contentType:nil 
-                                                                                     contentEncoding:nil 
-                                                                                  contentDisposition:nil 
-                                                                                            manifest:nil 
-                                                                                             sharing:nil 
-                                                                                            isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                            metadata:nil 
-                                                                            destinationContainerName:destinationContainerName 
-                                                                               destinationObjectName:destinationObjectName 
-                                                                                  destinationAccount:nil]];
+            objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName 
+                                                                                objectName:objectName 
+                                                                               contentType:nil 
+                                                                           contentEncoding:nil 
+                                                                        contentDisposition:nil 
+                                                                                  manifest:nil 
+                                                                                   sharing:nil 
+                                                                                  isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                                  metadata:nil 
+                                                                  destinationContainerName:destinationContainerName 
+                                                                     destinationObjectName:destinationObjectName 
+                                                                        destinationAccount:nil];
+            objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                      containerName, @"sourceContainerName", 
+                                      objectName, @"sourceObjectName", 
+                                      destinationContainerName, @"destinationContainerName", 
+                                      destinationObjectName, @"destinationObjectName", 
+                                      nil];
+            [objectRequests addObject:objectRequest];
         }
         NSRange prefixRange = NSMakeRange(0, [objectName length]);
         NSString *newObjectName;
                                                                    withString:destinationObjectName
                                                                       options:NSAnchoredSearch
                                                                         range:prefixRange];
-            [objectRequests addObject:[ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName 
-                                                                                          objectName:object.name
-                                                                                         contentType:nil 
-                                                                                     contentEncoding:nil 
-                                                                                  contentDisposition:nil 
-                                                                                            manifest:nil 
-                                                                                             sharing:nil 
-                                                                                            isPublic:ASIPithosObjectRequestPublicIgnore 
-                                                                                            metadata:nil 
-                                                                            destinationContainerName:destinationContainerName 
-                                                                               destinationObjectName:newObjectName 
-                                                                                  destinationAccount:nil]];
+            objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName 
+                                                                                objectName:object.name
+                                                                               contentType:nil 
+                                                                           contentEncoding:nil 
+                                                                        contentDisposition:nil 
+                                                                                  manifest:nil 
+                                                                                   sharing:nil 
+                                                                                  isPublic:ASIPithosObjectRequestPublicIgnore 
+                                                                                  metadata:nil 
+                                                                  destinationContainerName:destinationContainerName 
+                                                                     destinationObjectName:newObjectName 
+                                                                        destinationAccount:nil];
+            objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                      containerName, @"sourceContainerName", 
+                                      object.name, @"sourceObjectName", 
+                                      destinationContainerName, @"destinationContainerName", 
+                                      newObjectName, @"destinationObjectName", 
+                                      nil];
+            [objectRequests addObject:objectRequest];
         }
     }
      
                                                                                                 objectName:objectName];
     if (sharingAccount)
         [objectRequest setRequestUserFromDefaultTo:sharingAccount];
-    [objectRequest startSynchronous];
+    [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
+    while (![objectRequest isFinished]) {
+        sleep(1);
+    }
     *error = [objectRequest error];
     if (*error) {
         [self httpRequestErrorAlertWithRequest:objectRequest];
                                                                                                                until:nil];
         if (sharingAccount)
             [containerRequest setRequestUserFromDefaultTo:sharingAccount];
-        [containerRequest startSynchronous];
+        [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
+        while (![containerRequest isFinished]) {
+            sleep(1);
+        }
         if ([containerRequest error]) {
             [self httpRequestErrorAlertWithRequest:containerRequest];
             return nil;
     return [alert runModal];
 }
 
+#pragma mark -
+#pragma mark Request Helper Methods
+
++ (ASIPithosRequest *)prepareRequest:(ASIPithosRequest *)request priority:(NSOperationQueuePriority)priority {
+    [request setTimeOutSeconds:60];
+    request.numberOfTimesToRetryOnTimeout = 10;
+    [request setQueuePriority:priority];
+    return request;
+}
+
++ (ASIPithosRequest *)prepareRequest:(ASIPithosRequest *)request {
+    return [self prepareRequest:request priority:NSOperationQueuePriorityNormal];
+}
+
++ (ASIPithosRequest *)copyRequest:(ASIPithosRequest *)request {
+    NSMutableDictionary *userInfo = [[request.userInfo retain] autorelease];
+    request.userInfo = nil;
+    ASIPithosRequest *newRequest = [request copy];
+    newRequest.userInfo = userInfo;
+    return newRequest;
+}
+
 @end
index 76944c3..5188f15 100644 (file)
     NSLog(@"Authentication - storageURLPrefix:%@, authUser:%@, authToken:%@", storageURLPrefix, authUser, authToken);
     if ([authUser length] && [authToken length]) {
         [[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
+        [[ASIPithosRequest sharedQueue] cancelAllOperations];
         [ASIPithosRequest setAuthURL:storageURLPrefix];
         [ASIPithosRequest setStorageURLPrefix:storageURLPrefix];
         [ASIPithosRequest setAuthUser:authUser];