Statistics
| Branch: | Tag: | Revision:

root / pithos-macos / PithosBrowserController.m @ 6d9d5dce

History | View | Annotate | Download (163.6 kB)

1 589a14ca Miltiadis Vasilakis
//
2 d8d08dc1 Miltiadis Vasilakis
//  PithosBrowserController.m
3 d8d08dc1 Miltiadis Vasilakis
//  pithos-macos
4 d8d08dc1 Miltiadis Vasilakis
//
5 fb27f368 Miltiadis Vasilakis
// Copyright 2011-2013 GRNET S.A. All rights reserved.
6 d8d08dc1 Miltiadis Vasilakis
//
7 e5fdf4d9 Miltiadis Vasilakis
// Redistribution and use in source and binary forms, with or
8 e5fdf4d9 Miltiadis Vasilakis
// without modification, are permitted provided that the following
9 e5fdf4d9 Miltiadis Vasilakis
// conditions are met:
10 e5fdf4d9 Miltiadis Vasilakis
// 
11 e5fdf4d9 Miltiadis Vasilakis
//   1. Redistributions of source code must retain the above
12 e5fdf4d9 Miltiadis Vasilakis
//      copyright notice, this list of conditions and the following
13 e5fdf4d9 Miltiadis Vasilakis
//      disclaimer.
14 e5fdf4d9 Miltiadis Vasilakis
// 
15 e5fdf4d9 Miltiadis Vasilakis
//   2. Redistributions in binary form must reproduce the above
16 e5fdf4d9 Miltiadis Vasilakis
//      copyright notice, this list of conditions and the following
17 e5fdf4d9 Miltiadis Vasilakis
//      disclaimer in the documentation and/or other materials
18 e5fdf4d9 Miltiadis Vasilakis
//      provided with the distribution.
19 e5fdf4d9 Miltiadis Vasilakis
// 
20 e5fdf4d9 Miltiadis Vasilakis
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
21 e5fdf4d9 Miltiadis Vasilakis
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 e5fdf4d9 Miltiadis Vasilakis
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 e5fdf4d9 Miltiadis Vasilakis
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
24 e5fdf4d9 Miltiadis Vasilakis
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 e5fdf4d9 Miltiadis Vasilakis
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 e5fdf4d9 Miltiadis Vasilakis
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27 e5fdf4d9 Miltiadis Vasilakis
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 e5fdf4d9 Miltiadis Vasilakis
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 e5fdf4d9 Miltiadis Vasilakis
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 e5fdf4d9 Miltiadis Vasilakis
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 e5fdf4d9 Miltiadis Vasilakis
// POSSIBILITY OF SUCH DAMAGE.
32 e5fdf4d9 Miltiadis Vasilakis
// 
33 e5fdf4d9 Miltiadis Vasilakis
// The views and conclusions contained in the software and
34 e5fdf4d9 Miltiadis Vasilakis
// documentation are those of the authors and should not be
35 e5fdf4d9 Miltiadis Vasilakis
// interpreted as representing official policies, either expressed
36 e5fdf4d9 Miltiadis Vasilakis
// or implied, of GRNET S.A.
37 d8d08dc1 Miltiadis Vasilakis
38 d8d08dc1 Miltiadis Vasilakis
#import "PithosBrowserController.h"
39 4bf68b77 Miltiadis Vasilakis
#import "PithosNode.h"
40 9f3a92de Miltiadis Vasilakis
#import "PithosAccountNode.h"
41 9f3a92de Miltiadis Vasilakis
#import "PithosContainerNode.h"
42 6dc7e931 Miltiadis Vasilakis
#import "PithosSubdirNode.h"
43 6dc7e931 Miltiadis Vasilakis
#import "PithosObjectNode.h"
44 af3b9f06 Miltiadis Vasilakis
#import "PithosSharingAccountsNode.h"
45 9f3a92de Miltiadis Vasilakis
#import "PithosEmptyNode.h"
46 e5fdf4d9 Miltiadis Vasilakis
#import "ImageAndTextCell.h"
47 9f3a92de Miltiadis Vasilakis
#import "FileSystemBrowserCell.h"
48 4c1c46fd Miltiadis Vasilakis
#import "ASINetworkQueue.h"
49 4bf68b77 Miltiadis Vasilakis
#import "ASIPithosRequest.h"
50 919cb043 Miltiadis Vasilakis
#import "ASIPithos.h"
51 4bf68b77 Miltiadis Vasilakis
#import "ASIPithosContainerRequest.h"
52 6dc7e931 Miltiadis Vasilakis
#import "ASIPithosObjectRequest.h"
53 470e6f81 Miltiadis Vasilakis
#import "ASIPithosAccount.h"
54 4bf68b77 Miltiadis Vasilakis
#import "ASIPithosContainer.h"
55 6dc7e931 Miltiadis Vasilakis
#import "ASIPithosObject.h"
56 1b1e6fa1 Miltiadis Vasilakis
#import "PithosUtilities.h"
57 fb27f368 Miltiadis Vasilakis
#import "PithosAccount.h"
58 2943d6d4 Miltiadis Vasilakis
#import "UsingSizeTransformer.h"
59 d8d08dc1 Miltiadis Vasilakis
60 4e6acad7 Miltiadis Vasilakis
#define REFRESH_TIMER_INTERVAL 5
61 4e6acad7 Miltiadis Vasilakis
62 9f3a92de Miltiadis Vasilakis
@interface PithosBrowserCell : FileSystemBrowserCell {}
63 e5fdf4d9 Miltiadis Vasilakis
@end
64 d8d08dc1 Miltiadis Vasilakis
65 e5fdf4d9 Miltiadis Vasilakis
@implementation PithosBrowserCell
66 d8d08dc1 Miltiadis Vasilakis
67 9f3a92de Miltiadis Vasilakis
- (id)init {
68 9f3a92de Miltiadis Vasilakis
    if ((self = [super init])) {
69 9f3a92de Miltiadis Vasilakis
        [self setLineBreakMode:NSLineBreakByTruncatingMiddle];
70 19c353fe Miltiadis Vasilakis
        [self setEditable:YES];
71 9f3a92de Miltiadis Vasilakis
    }
72 9f3a92de Miltiadis Vasilakis
    return self;
73 9f3a92de Miltiadis Vasilakis
}
74 9f3a92de Miltiadis Vasilakis
75 e5fdf4d9 Miltiadis Vasilakis
- (void)setObjectValue:(id)object {
76 e5fdf4d9 Miltiadis Vasilakis
    if ([object isKindOfClass:[PithosNode class]]) {
77 e5fdf4d9 Miltiadis Vasilakis
        PithosNode *node = (PithosNode *)object;
78 e5fdf4d9 Miltiadis Vasilakis
        [self setStringValue:node.displayName];
79 e5fdf4d9 Miltiadis Vasilakis
        [self setImage:node.icon];
80 e5fdf4d9 Miltiadis Vasilakis
    } else {
81 e5fdf4d9 Miltiadis Vasilakis
        [super setObjectValue:object];
82 d8d08dc1 Miltiadis Vasilakis
    }
83 d8d08dc1 Miltiadis Vasilakis
}
84 d8d08dc1 Miltiadis Vasilakis
85 e5fdf4d9 Miltiadis Vasilakis
@end
86 e5fdf4d9 Miltiadis Vasilakis
87 e5fdf4d9 Miltiadis Vasilakis
@interface PithosOutlineViewCell : ImageAndTextCell {}
88 e5fdf4d9 Miltiadis Vasilakis
@end
89 e5fdf4d9 Miltiadis Vasilakis
90 e5fdf4d9 Miltiadis Vasilakis
@implementation PithosOutlineViewCell
91 e5fdf4d9 Miltiadis Vasilakis
92 e5fdf4d9 Miltiadis Vasilakis
- (void)setObjectValue:(id)object {
93 e5fdf4d9 Miltiadis Vasilakis
    if ([object isKindOfClass:[PithosNode class]]) {
94 e5fdf4d9 Miltiadis Vasilakis
        PithosNode *node = (PithosNode *)object;
95 e5fdf4d9 Miltiadis Vasilakis
        [self setStringValue:node.displayName];
96 e5fdf4d9 Miltiadis Vasilakis
        [self setImage:node.icon];
97 e5fdf4d9 Miltiadis Vasilakis
        [self setEditable:NO];
98 e5fdf4d9 Miltiadis Vasilakis
    } else {
99 e5fdf4d9 Miltiadis Vasilakis
        [super setObjectValue:object];
100 e5fdf4d9 Miltiadis Vasilakis
    }
101 e5fdf4d9 Miltiadis Vasilakis
}
102 e5fdf4d9 Miltiadis Vasilakis
103 e5fdf4d9 Miltiadis Vasilakis
@end
104 e5fdf4d9 Miltiadis Vasilakis
105 0224a49f Miltiadis Vasilakis
@interface PithosBrowserController (Private)
106 67e3336f Miltiadis Vasilakis
- (BOOL)uploadFiles:(NSArray *)filenames toNode:(PithosNode *)destinationNode;
107 67e3336f Miltiadis Vasilakis
- (BOOL)moveNodes:(NSArray *)nodes toNode:(PithosNode *)destinationNode;
108 3f220848 Miltiadis Vasilakis
- (BOOL)cpyNodes:(NSArray *)nodes toNode:(PithosNode *)destinationNode;
109 e5fdf4d9 Miltiadis Vasilakis
@end
110 e5fdf4d9 Miltiadis Vasilakis
111 e5fdf4d9 Miltiadis Vasilakis
@implementation PithosBrowserController
112 eebb5f02 Miltiadis Vasilakis
@synthesize pithosAccountManager, accountNode;
113 c950a94d Miltiadis Vasilakis
@synthesize draggedNodes, draggedParentNode;
114 c950a94d Miltiadis Vasilakis
@synthesize clipboardNodes, clipboardParentNode, clipboardCopy;
115 e5fdf4d9 Miltiadis Vasilakis
116 e5fdf4d9 Miltiadis Vasilakis
#pragma mark -
117 e5fdf4d9 Miltiadis Vasilakis
#pragma Object Lifecycle
118 e5fdf4d9 Miltiadis Vasilakis
119 e5fdf4d9 Miltiadis Vasilakis
- (id)init {
120 e5fdf4d9 Miltiadis Vasilakis
    return [super initWithWindowNibName:@"PithosBrowserController"];
121 e5fdf4d9 Miltiadis Vasilakis
}
122 e5fdf4d9 Miltiadis Vasilakis
123 d8426ffb Miltiadis Vasilakis
- (void)windowDidLoad {
124 d8426ffb Miltiadis Vasilakis
    [super windowDidLoad];
125 d8426ffb Miltiadis Vasilakis
    if (browser && !browserInitialized) {
126 d8426ffb Miltiadis Vasilakis
        browserInitialized = YES;
127 d8426ffb Miltiadis Vasilakis
        [self initBrowser];
128 d8426ffb Miltiadis Vasilakis
    }
129 d8d08dc1 Miltiadis Vasilakis
}
130 d8d08dc1 Miltiadis Vasilakis
131 919cb043 Miltiadis Vasilakis
- (void)initBrowser {
132 d41b3577 Miltiadis Vasilakis
    [browser registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, NSFilesPromisePboardType, nil]];
133 d41b3577 Miltiadis Vasilakis
    [browser setDraggingSourceOperationMask:(NSDragOperationCopy|NSDragOperationMove) forLocal:YES];
134 6dc7e931 Miltiadis Vasilakis
    [browser setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO];
135 6dc7e931 Miltiadis Vasilakis
    
136 67e3336f Miltiadis Vasilakis
    [outlineView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, NSFilesPromisePboardType, nil]];
137 67e3336f Miltiadis Vasilakis
    [outlineView setDraggingSourceOperationMask:(NSDragOperationCopy|NSDragOperationMove) forLocal:YES];
138 67e3336f Miltiadis Vasilakis
    [outlineView setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO];
139 67e3336f Miltiadis Vasilakis
    
140 e5fdf4d9 Miltiadis Vasilakis
    [browser setCellClass:[PithosBrowserCell class]];
141 919cb043 Miltiadis Vasilakis
    [browser setAllowsBranchSelection:YES];
142 919cb043 Miltiadis Vasilakis
    [browser setAllowsMultipleSelection:YES];
143 919cb043 Miltiadis Vasilakis
    [browser setAllowsEmptySelection:YES];
144 919cb043 Miltiadis Vasilakis
    [browser setAllowsTypeSelect:YES];
145 af9f2aee Miltiadis Vasilakis
    [browser setDoubleAction:@selector(browserDoubleAction:)];
146 4c1c46fd Miltiadis Vasilakis
    
147 4c1c46fd Miltiadis Vasilakis
    moveNetworkQueue = [[ASINetworkQueue alloc] init];
148 4c1c46fd Miltiadis Vasilakis
    moveNetworkQueue.shouldCancelAllRequestsOnFailure = NO;
149 d8426ffb Miltiadis Vasilakis
//    moveNetworkQueue.maxConcurrentOperationCount = 1;
150 4c1c46fd Miltiadis Vasilakis
    copyNetworkQueue = [[ASINetworkQueue alloc] init];
151 4c1c46fd Miltiadis Vasilakis
    copyNetworkQueue.shouldCancelAllRequestsOnFailure = NO;
152 d8426ffb Miltiadis Vasilakis
//    copyNetworkQueue.maxConcurrentOperationCount = 1;
153 4c1c46fd Miltiadis Vasilakis
    deleteNetworkQueue = [[ASINetworkQueue alloc] init];
154 4c1c46fd Miltiadis Vasilakis
    deleteNetworkQueue.shouldCancelAllRequestsOnFailure = NO;
155 d8426ffb Miltiadis Vasilakis
//    deleteNetworkQueue.maxConcurrentOperationCount = 1;
156 4c1c46fd Miltiadis Vasilakis
    uploadNetworkQueue = [[ASINetworkQueue alloc] init];
157 4c1c46fd Miltiadis Vasilakis
    uploadNetworkQueue.showAccurateProgress = YES;
158 4c1c46fd Miltiadis Vasilakis
    uploadNetworkQueue.shouldCancelAllRequestsOnFailure = NO;
159 d8426ffb Miltiadis Vasilakis
//    uploadNetworkQueue.maxConcurrentOperationCount = 1;
160 4c1c46fd Miltiadis Vasilakis
    downloadNetworkQueue = [[ASINetworkQueue alloc] init];
161 4c1c46fd Miltiadis Vasilakis
    downloadNetworkQueue.showAccurateProgress = YES;
162 4c1c46fd Miltiadis Vasilakis
    downloadNetworkQueue.shouldCancelAllRequestsOnFailure = NO;
163 d8426ffb Miltiadis Vasilakis
//    downloadNetworkQueue.maxConcurrentOperationCount = 1;
164 d8426ffb Miltiadis Vasilakis
    
165 d8426ffb Miltiadis Vasilakis
    moveQueue = [[NSOperationQueue alloc] init];
166 d8426ffb Miltiadis Vasilakis
    [moveQueue setSuspended:YES];
167 d8426ffb Miltiadis Vasilakis
    moveQueue.name = @"gr.grnet.pithos.MoveQueue";
168 d8426ffb Miltiadis Vasilakis
//    moveQueue.maxConcurrentOperationCount = 1;
169 d8426ffb Miltiadis Vasilakis
    copyQueue = [[NSOperationQueue alloc] init];
170 d8426ffb Miltiadis Vasilakis
    [copyQueue setSuspended:YES];
171 d8426ffb Miltiadis Vasilakis
    copyQueue.name = @"gr.grnet.pithos.CopyQueue";
172 d8426ffb Miltiadis Vasilakis
//    copyQueue.maxConcurrentOperationCount = 1;
173 d8426ffb Miltiadis Vasilakis
    deleteQueue = [[NSOperationQueue alloc] init];
174 d8426ffb Miltiadis Vasilakis
    [deleteQueue setSuspended:YES];
175 d8426ffb Miltiadis Vasilakis
    deleteQueue.name = @"gr.grnet.pithos.DeleteQueue";
176 d8426ffb Miltiadis Vasilakis
//    deleteQueue.maxConcurrentOperationCount = 1;
177 d8426ffb Miltiadis Vasilakis
    uploadQueue = [[NSOperationQueue alloc] init];
178 d8426ffb Miltiadis Vasilakis
    [uploadQueue setSuspended:YES];
179 d8426ffb Miltiadis Vasilakis
    uploadQueue.name = @"gr.grnet.pithos.UploadQueue";
180 d8426ffb Miltiadis Vasilakis
//    uploadQueue.maxConcurrentOperationCount = 1;
181 d8426ffb Miltiadis Vasilakis
    downloadQueue = [[NSOperationQueue alloc] init];
182 d8426ffb Miltiadis Vasilakis
    [downloadQueue setSuspended:YES];
183 d8426ffb Miltiadis Vasilakis
    downloadQueue.name = @"gr.grnet.pithos.DownloadQueue";
184 d8426ffb Miltiadis Vasilakis
//    downloadQueue.maxConcurrentOperationCount = 1;
185 4c1c46fd Miltiadis Vasilakis
    
186 d8426ffb Miltiadis Vasilakis
    moveCallbackQueue = [[NSOperationQueue alloc] init];
187 d8426ffb Miltiadis Vasilakis
    [moveCallbackQueue setSuspended:YES];
188 d8426ffb Miltiadis Vasilakis
    moveCallbackQueue.name = @"gr.grnet.pithos.MoveCallbackQueue";
189 d8426ffb Miltiadis Vasilakis
//    moveCallbackQueue.maxConcurrentOperationCount = 1;
190 d8426ffb Miltiadis Vasilakis
    copyCallbackQueue = [[NSOperationQueue alloc] init];
191 d8426ffb Miltiadis Vasilakis
    [copyCallbackQueue setSuspended:YES];
192 d8426ffb Miltiadis Vasilakis
    copyCallbackQueue.name = @"gr.grnet.pithos.CopyCallbackQueue";
193 d8426ffb Miltiadis Vasilakis
//    copyCallbackQueue.maxConcurrentOperationCount = 1;
194 d8426ffb Miltiadis Vasilakis
    deleteCallbackQueue = [[NSOperationQueue alloc] init];
195 d8426ffb Miltiadis Vasilakis
    [deleteCallbackQueue setSuspended:YES];
196 d8426ffb Miltiadis Vasilakis
    deleteCallbackQueue.name = @"gr.grnet.pithos.DeleteCallbackQueue";
197 d8426ffb Miltiadis Vasilakis
//    deleteCallbackQueue.maxConcurrentOperationCount = 1;
198 d8426ffb Miltiadis Vasilakis
    uploadCallbackQueue = [[NSOperationQueue alloc] init];
199 d8426ffb Miltiadis Vasilakis
    [uploadCallbackQueue setSuspended:YES];
200 d8426ffb Miltiadis Vasilakis
    uploadCallbackQueue.name = @"gr.grnet.pithos.UploadCallbackQueue";
201 d8426ffb Miltiadis Vasilakis
//    uploadCallbackQueue.maxConcurrentOperationCount = 1;
202 d8426ffb Miltiadis Vasilakis
    downloadCallbackQueue = [[NSOperationQueue alloc] init];
203 d8426ffb Miltiadis Vasilakis
    [downloadCallbackQueue setSuspended:YES];
204 d8426ffb Miltiadis Vasilakis
    downloadCallbackQueue.name = @"gr.grnet.pithos.DownloadCallbackQueue";
205 d8426ffb Miltiadis Vasilakis
//    downloadCallbackQueue.maxConcurrentOperationCount = 1;
206 2d9996a2 Miltiadis Vasilakis
    
207 470e6f81 Miltiadis Vasilakis
    [activityProgressIndicator setUsesThreadedAnimation:YES];
208 470e6f81 Miltiadis Vasilakis
    [activityProgressIndicator setMinValue:0.0];
209 470e6f81 Miltiadis Vasilakis
    [activityProgressIndicator setMaxValue:1.0];
210 470e6f81 Miltiadis Vasilakis
    activityFacility = [PithosActivityFacility defaultPithosActivityFacility];
211 470e6f81 Miltiadis Vasilakis
    
212 fb27f368 Miltiadis Vasilakis
    self.accountNode = [[PithosAccountNode alloc] initWithPithosAccountManager:pithosAccountManager];
213 20f54e18 Miltiadis Vasilakis
    containersNode = [[PithosEmptyNode alloc] initWithDisplayName:@"CONTAINERS" icon:nil];
214 20f54e18 Miltiadis Vasilakis
    containersNodeChildren = [[NSMutableArray alloc] init];
215 20f54e18 Miltiadis Vasilakis
    sharedNode = [[PithosEmptyNode alloc] initWithDisplayName:@"SHARED" icon:nil];
216 fb27f368 Miltiadis Vasilakis
    mySharedNode = [[PithosAccountNode alloc] initWithPithosAccountManager:pithosAccountManager];
217 320d154b Miltiadis Vasilakis
    mySharedNode.displayName = @"shared by me";
218 20f54e18 Miltiadis Vasilakis
    mySharedNode.shared = YES;
219 20f54e18 Miltiadis Vasilakis
    mySharedNode.icon = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kUserIcon)];
220 fb27f368 Miltiadis Vasilakis
    othersSharedNode = [[PithosSharingAccountsNode alloc] initWithPithosAccountManager:pithosAccountManager];
221 e1f12510 Miltiadis Vasilakis
    othersSharedNode.displayName = @"shared with me";
222 af3b9f06 Miltiadis Vasilakis
    othersSharedNode.icon = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGroupIcon)];
223 4ae10a2b Miltiadis Vasilakis
    
224 cb6abe72 Miltiadis Vasilakis
    [[[outlineView tableColumns] objectAtIndex:0] setDataCell:[[PithosOutlineViewCell alloc] init]];
225 e5fdf4d9 Miltiadis Vasilakis
    
226 e5fdf4d9 Miltiadis Vasilakis
    // Register for updates
227 af3b9f06 Miltiadis Vasilakis
    // PithosAccountNode accountNode updates outlineView container nodes 
228 589a14ca Miltiadis Vasilakis
    [[NSNotificationCenter defaultCenter] addObserver:self 
229 4bf68b77 Miltiadis Vasilakis
                                             selector:@selector(pithosAccountNodeChildrenUpdated:) 
230 d4433f6f Miltiadis Vasilakis
                                                 name:@"PithosNodeChildrenUpdated" 
231 4ae10a2b Miltiadis Vasilakis
                                               object:accountNode];
232 d4433f6f Miltiadis Vasilakis
    // PithosNode updates browser nodes
233 4ae10a2b Miltiadis Vasilakis
    [[NSNotificationCenter defaultCenter] addObserver:self 
234 4ae10a2b Miltiadis Vasilakis
                                             selector:@selector(pithosNodeChildrenUpdated:) 
235 d4433f6f Miltiadis Vasilakis
                                                 name:@"PithosNodeChildrenUpdated" 
236 af3b9f06 Miltiadis Vasilakis
                                               object:nil];
237 af3b9f06 Miltiadis Vasilakis
    // Request for browser refresh 
238 20f54e18 Miltiadis Vasilakis
    [[NSNotificationCenter defaultCenter] addObserver:self 
239 20f54e18 Miltiadis Vasilakis
                                             selector:@selector(pithosBrowserRefreshNeeded:) 
240 258db46f Miltiadis Vasilakis
                                                 name:@"PithosBrowserRefreshNeeded" 
241 919cb043 Miltiadis Vasilakis
                                               object:nil];
242 919cb043 Miltiadis Vasilakis
}
243 919cb043 Miltiadis Vasilakis
244 919cb043 Miltiadis Vasilakis
- (void)resetBrowser {
245 d8426ffb Miltiadis Vasilakis
    @synchronized(self) {
246 d8426ffb Miltiadis Vasilakis
        if (!browserActive)
247 d8426ffb Miltiadis Vasilakis
            return;
248 d8426ffb Miltiadis Vasilakis
    }
249 d8426ffb Miltiadis Vasilakis
250 919cb043 Miltiadis Vasilakis
    [refreshTimer invalidate];
251 919cb043 Miltiadis Vasilakis
    
252 d8426ffb Miltiadis Vasilakis
    [moveNetworkQueue reset];
253 d8426ffb Miltiadis Vasilakis
    [copyNetworkQueue reset];
254 d8426ffb Miltiadis Vasilakis
    [deleteNetworkQueue reset];
255 d8426ffb Miltiadis Vasilakis
    [uploadNetworkQueue reset];
256 d8426ffb Miltiadis Vasilakis
    [downloadNetworkQueue reset];
257 919cb043 Miltiadis Vasilakis
    
258 d8426ffb Miltiadis Vasilakis
    [moveQueue cancelAllOperations];
259 d8426ffb Miltiadis Vasilakis
    [moveQueue setSuspended:YES];
260 d8426ffb Miltiadis Vasilakis
    [copyQueue cancelAllOperations];
261 d8426ffb Miltiadis Vasilakis
    [copyQueue setSuspended:YES];
262 d8426ffb Miltiadis Vasilakis
    [deleteQueue cancelAllOperations];
263 d8426ffb Miltiadis Vasilakis
    [deleteQueue setSuspended:YES];
264 d8426ffb Miltiadis Vasilakis
    [uploadQueue cancelAllOperations];
265 d8426ffb Miltiadis Vasilakis
    [uploadQueue setSuspended:YES];
266 d8426ffb Miltiadis Vasilakis
    [downloadQueue cancelAllOperations];
267 d8426ffb Miltiadis Vasilakis
    [downloadQueue setSuspended:YES];
268 d8426ffb Miltiadis Vasilakis
269 d8426ffb Miltiadis Vasilakis
    [moveCallbackQueue cancelAllOperations];
270 d8426ffb Miltiadis Vasilakis
    [moveCallbackQueue setSuspended:YES];
271 d8426ffb Miltiadis Vasilakis
    [copyCallbackQueue cancelAllOperations];
272 d8426ffb Miltiadis Vasilakis
    [copyCallbackQueue setSuspended:YES];
273 d8426ffb Miltiadis Vasilakis
    [deleteCallbackQueue cancelAllOperations];
274 d8426ffb Miltiadis Vasilakis
    [deleteCallbackQueue setSuspended:YES];
275 d8426ffb Miltiadis Vasilakis
    [uploadCallbackQueue cancelAllOperations];
276 d8426ffb Miltiadis Vasilakis
    [uploadCallbackQueue setSuspended:YES];
277 d8426ffb Miltiadis Vasilakis
    [downloadCallbackQueue cancelAllOperations];
278 d8426ffb Miltiadis Vasilakis
    [downloadCallbackQueue setSuspended:YES];
279 d8426ffb Miltiadis Vasilakis
280 e8e3d71e Miltiadis Vasilakis
    [accountNode pithosNodeWillBeRemoved];
281 e8e3d71e Miltiadis Vasilakis
    [mySharedNode pithosNodeWillBeRemoved];
282 e8e3d71e Miltiadis Vasilakis
    [othersSharedNode pithosNodeWillBeRemoved];
283 e8e3d71e Miltiadis Vasilakis
    
284 919cb043 Miltiadis Vasilakis
    rootNode = nil;
285 919cb043 Miltiadis Vasilakis
    [browser loadColumnZero];
286 919cb043 Miltiadis Vasilakis
    [containersNodeChildren removeAllObjects];
287 919cb043 Miltiadis Vasilakis
    [outlineView reloadData];
288 d8426ffb Miltiadis Vasilakis
    // Expand the folder outline view
289 919cb043 Miltiadis Vasilakis
    [outlineView expandItem:nil expandChildren:YES];
290 d8426ffb Miltiadis Vasilakis
    [outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
291 919cb043 Miltiadis Vasilakis
    
292 919cb043 Miltiadis Vasilakis
    activityFacility.delegate = nil;
293 919cb043 Miltiadis Vasilakis
    [activityProgressIndicator setDoubleValue:1.0];
294 919cb043 Miltiadis Vasilakis
    [activityProgressIndicator stopAnimation:self];
295 d8426ffb Miltiadis Vasilakis
    
296 d8426ffb Miltiadis Vasilakis
    @synchronized(self) {
297 d8426ffb Miltiadis Vasilakis
        browserActive = NO;
298 d8426ffb Miltiadis Vasilakis
    }
299 919cb043 Miltiadis Vasilakis
}
300 919cb043 Miltiadis Vasilakis
301 919cb043 Miltiadis Vasilakis
- (void)startBrowser {
302 d8426ffb Miltiadis Vasilakis
    @synchronized(self) {
303 d8426ffb Miltiadis Vasilakis
        if (browserActive)
304 d8426ffb Miltiadis Vasilakis
            return;
305 d8426ffb Miltiadis Vasilakis
    }
306 d8426ffb Miltiadis Vasilakis
    
307 d8426ffb Miltiadis Vasilakis
    // In the improbable case of leftover operations
308 d8426ffb Miltiadis Vasilakis
    [moveNetworkQueue reset];
309 d8426ffb Miltiadis Vasilakis
    [copyNetworkQueue reset];
310 d8426ffb Miltiadis Vasilakis
    [deleteNetworkQueue reset];
311 d8426ffb Miltiadis Vasilakis
    [uploadNetworkQueue reset];
312 d8426ffb Miltiadis Vasilakis
    [downloadNetworkQueue reset];
313 d8426ffb Miltiadis Vasilakis
    [moveQueue cancelAllOperations];
314 d8426ffb Miltiadis Vasilakis
    [copyQueue cancelAllOperations];
315 d8426ffb Miltiadis Vasilakis
    [deleteQueue cancelAllOperations];
316 d8426ffb Miltiadis Vasilakis
    [uploadQueue cancelAllOperations];
317 d8426ffb Miltiadis Vasilakis
    [downloadQueue cancelAllOperations];
318 d8426ffb Miltiadis Vasilakis
    [moveCallbackQueue cancelAllOperations];
319 d8426ffb Miltiadis Vasilakis
    [copyCallbackQueue cancelAllOperations];
320 d8426ffb Miltiadis Vasilakis
    [deleteCallbackQueue cancelAllOperations];
321 d8426ffb Miltiadis Vasilakis
    [uploadCallbackQueue cancelAllOperations];
322 d8426ffb Miltiadis Vasilakis
    [downloadCallbackQueue cancelAllOperations];
323 d8426ffb Miltiadis Vasilakis
324 d8426ffb Miltiadis Vasilakis
    [moveNetworkQueue go];
325 d8426ffb Miltiadis Vasilakis
    [copyNetworkQueue go];
326 d8426ffb Miltiadis Vasilakis
    [deleteNetworkQueue go];
327 d8426ffb Miltiadis Vasilakis
    [uploadNetworkQueue go];
328 d8426ffb Miltiadis Vasilakis
    [downloadNetworkQueue go];
329 d8426ffb Miltiadis Vasilakis
    [moveQueue setSuspended:NO];
330 d8426ffb Miltiadis Vasilakis
    [copyQueue setSuspended:NO];
331 d8426ffb Miltiadis Vasilakis
    [deleteQueue setSuspended:NO];
332 d8426ffb Miltiadis Vasilakis
    [uploadQueue setSuspended:NO];
333 d8426ffb Miltiadis Vasilakis
    [downloadQueue setSuspended:NO];
334 d8426ffb Miltiadis Vasilakis
    [moveCallbackQueue setSuspended:NO];
335 d8426ffb Miltiadis Vasilakis
    [copyCallbackQueue setSuspended:NO];
336 d8426ffb Miltiadis Vasilakis
    [deleteCallbackQueue setSuspended:NO];
337 d8426ffb Miltiadis Vasilakis
    [uploadCallbackQueue setSuspended:NO];
338 d8426ffb Miltiadis Vasilakis
    [downloadCallbackQueue setSuspended:NO];
339 d8426ffb Miltiadis Vasilakis
340 eebb5f02 Miltiadis Vasilakis
    accountNode.pithosAccountManager = pithosAccountManager;
341 fb27f368 Miltiadis Vasilakis
    [accountNode reset];
342 eebb5f02 Miltiadis Vasilakis
    mySharedNode.pithosAccountManager = pithosAccountManager;
343 fb27f368 Miltiadis Vasilakis
    [mySharedNode reset];
344 eebb5f02 Miltiadis Vasilakis
    othersSharedNode.pithosAccountManager = pithosAccountManager;
345 fb27f368 Miltiadis Vasilakis
    [othersSharedNode reset];
346 fb27f368 Miltiadis Vasilakis
    
347 d8426ffb Miltiadis Vasilakis
//    [activityFacility reset];
348 919cb043 Miltiadis Vasilakis
    activityFacility.delegate = self;
349 d8426ffb Miltiadis Vasilakis
            
350 cb6abe72 Miltiadis Vasilakis
    refreshTimer = [NSTimer scheduledTimerWithTimeInterval:REFRESH_TIMER_INTERVAL 
351 d8426ffb Miltiadis Vasilakis
                                                     target:self 
352 d8426ffb Miltiadis Vasilakis
                                                   selector:@selector(forceRefresh:) 
353 d8426ffb Miltiadis Vasilakis
                                                   userInfo:self 
354 cb6abe72 Miltiadis Vasilakis
                                                    repeats:YES];
355 d8426ffb Miltiadis Vasilakis
    @synchronized(self) {
356 d8426ffb Miltiadis Vasilakis
        browserActive = YES;
357 d8426ffb Miltiadis Vasilakis
    }
358 919cb043 Miltiadis Vasilakis
}
359 919cb043 Miltiadis Vasilakis
360 d8426ffb Miltiadis Vasilakis
- (BOOL)operationsPending {
361 d8426ffb Miltiadis Vasilakis
    return ([moveNetworkQueue operationCount] || 
362 d8426ffb Miltiadis Vasilakis
            [copyNetworkQueue operationCount] || 
363 d8426ffb Miltiadis Vasilakis
            [deleteNetworkQueue operationCount] || 
364 d8426ffb Miltiadis Vasilakis
            [uploadNetworkQueue operationCount] || 
365 d8426ffb Miltiadis Vasilakis
            [downloadNetworkQueue operationCount] || 
366 d8426ffb Miltiadis Vasilakis
            [moveQueue operationCount] || 
367 d8426ffb Miltiadis Vasilakis
            [copyQueue operationCount] || 
368 d8426ffb Miltiadis Vasilakis
            [deleteQueue operationCount] || 
369 d8426ffb Miltiadis Vasilakis
            [uploadQueue operationCount] || 
370 d8426ffb Miltiadis Vasilakis
            [downloadQueue operationCount] || 
371 d8426ffb Miltiadis Vasilakis
            [moveCallbackQueue operationCount] || 
372 d8426ffb Miltiadis Vasilakis
            [copyCallbackQueue operationCount] || 
373 d8426ffb Miltiadis Vasilakis
            [deleteCallbackQueue operationCount] || 
374 d8426ffb Miltiadis Vasilakis
            [uploadCallbackQueue operationCount] || 
375 d8426ffb Miltiadis Vasilakis
            [downloadCallbackQueue operationCount]);
376 919cb043 Miltiadis Vasilakis
}
377 919cb043 Miltiadis Vasilakis
378 d8426ffb Miltiadis Vasilakis
- (void)dealloc {
379 d8426ffb Miltiadis Vasilakis
    [[NSNotificationCenter defaultCenter] removeObserver:self];
380 d8426ffb Miltiadis Vasilakis
    [self resetBrowser];
381 d8426ffb Miltiadis Vasilakis
}
382 d8426ffb Miltiadis Vasilakis
383 fb27f368 Miltiadis Vasilakis
- (void)setPithosAccountManager:(PithosAccount *)aPithosAccountManager {
384 fb27f368 Miltiadis Vasilakis
    if (aPithosAccountManager && (aPithosAccountManager != pithosAccountManager)) {
385 fb27f368 Miltiadis Vasilakis
        [self resetBrowser];
386 fb27f368 Miltiadis Vasilakis
        if (pithosAccountManager)
387 fb27f368 Miltiadis Vasilakis
            [[NSNotificationCenter defaultCenter] removeObserver:self name:@"PithosAccountPithosChanged" object:pithosAccountManager];
388 fb27f368 Miltiadis Vasilakis
        pithosAccountManager = aPithosAccountManager;
389 fb27f368 Miltiadis Vasilakis
        [[NSNotificationCenter defaultCenter] addObserver:self
390 fb27f368 Miltiadis Vasilakis
                                                 selector:@selector(pithosAccountManagerPithosChanged:)
391 fb27f368 Miltiadis Vasilakis
                                                     name:@"PithosAccountPithosChanged"
392 fb27f368 Miltiadis Vasilakis
                                                   object:pithosAccountManager];
393 fb27f368 Miltiadis Vasilakis
        [self startBrowser];
394 919cb043 Miltiadis Vasilakis
    }
395 e5fdf4d9 Miltiadis Vasilakis
}
396 e5fdf4d9 Miltiadis Vasilakis
397 e5fdf4d9 Miltiadis Vasilakis
#pragma mark -
398 20f54e18 Miltiadis Vasilakis
#pragma mark Observers
399 e5fdf4d9 Miltiadis Vasilakis
400 fb27f368 Miltiadis Vasilakis
-(void)pithosAccountManagerPithosChanged:(NSNotification *)notification {
401 fb27f368 Miltiadis Vasilakis
    if (![NSThread isMainThread]) {
402 fb27f368 Miltiadis Vasilakis
        [self performSelectorOnMainThread:@selector(pithosAccountManagerPithosChanged:) withObject:notification waitUntilDone:NO];
403 fb27f368 Miltiadis Vasilakis
        return;
404 fb27f368 Miltiadis Vasilakis
    }
405 fb27f368 Miltiadis Vasilakis
    [self resetBrowser];
406 fb27f368 Miltiadis Vasilakis
    [self startBrowser];
407 fb27f368 Miltiadis Vasilakis
}
408 fb27f368 Miltiadis Vasilakis
409 e5fdf4d9 Miltiadis Vasilakis
- (void)pithosNodeChildrenUpdated:(NSNotification *)notification {
410 258db46f Miltiadis Vasilakis
    if (![NSThread isMainThread]) {
411 258db46f Miltiadis Vasilakis
        [self performSelectorOnMainThread:@selector(pithosNodeChildrenUpdated:) withObject:notification waitUntilDone:NO];
412 258db46f Miltiadis Vasilakis
        return;
413 258db46f Miltiadis Vasilakis
    }
414 605c8932 Miltiadis Vasilakis
    PithosNode *node = (PithosNode *)[notification object];
415 fb27f368 Miltiadis Vasilakis
    if ((node == accountNode) || (node.pithosAccountManager != pithosAccountManager))
416 af3b9f06 Miltiadis Vasilakis
        return;
417 9990166e Miltiadis Vasilakis
    DLog(@"pithosNodeChildrenUpdated:%@", node.url);
418 605c8932 Miltiadis Vasilakis
    NSInteger lastColumn = [browser lastColumn];
419 605c8932 Miltiadis Vasilakis
    for (NSInteger column = lastColumn; column >= 0; column--) {
420 605c8932 Miltiadis Vasilakis
        if ([[browser parentForItemsInColumn:column] isEqualTo:node]) {
421 605c8932 Miltiadis Vasilakis
            [browser reloadColumn:column];
422 605c8932 Miltiadis Vasilakis
            return;
423 605c8932 Miltiadis Vasilakis
        }
424 605c8932 Miltiadis Vasilakis
    }
425 e5fdf4d9 Miltiadis Vasilakis
}
426 e5fdf4d9 Miltiadis Vasilakis
427 4bf68b77 Miltiadis Vasilakis
- (void)pithosAccountNodeChildrenUpdated:(NSNotification *)notification {
428 258db46f Miltiadis Vasilakis
    if (![NSThread isMainThread]) {
429 258db46f Miltiadis Vasilakis
        [self performSelectorOnMainThread:@selector(pithosAccountNodeChildrenUpdated:) withObject:notification waitUntilDone:NO];
430 258db46f Miltiadis Vasilakis
        return;
431 258db46f Miltiadis Vasilakis
    }
432 4bf68b77 Miltiadis Vasilakis
    BOOL containerPithosFound = NO;
433 4bf68b77 Miltiadis Vasilakis
    BOOL containerTrashFound = NO;
434 20f54e18 Miltiadis Vasilakis
    NSMutableIndexSet *removedContainersNodeChildren = [NSMutableIndexSet indexSet];
435 20f54e18 Miltiadis Vasilakis
    for (NSUInteger i = 0 ; i < [containersNodeChildren count] ; i++) {
436 20f54e18 Miltiadis Vasilakis
        if (![accountNode.children containsObject:[containersNodeChildren objectAtIndex:i]])
437 20f54e18 Miltiadis Vasilakis
            [removedContainersNodeChildren addIndex:i];
438 20f54e18 Miltiadis Vasilakis
    }
439 20f54e18 Miltiadis Vasilakis
    [containersNodeChildren removeObjectsAtIndexes:removedContainersNodeChildren];
440 4bf68b77 Miltiadis Vasilakis
    for (PithosContainerNode *containerNode in accountNode.children) {
441 4bf68b77 Miltiadis Vasilakis
        if ([containerNode.pithosContainer.name isEqualToString:@"pithos"]) {
442 20f54e18 Miltiadis Vasilakis
            if (![containersNodeChildren containsObject:containerNode])
443 20f54e18 Miltiadis Vasilakis
                [containersNodeChildren insertObject:containerNode atIndex:0];
444 4bf68b77 Miltiadis Vasilakis
            containerPithosFound = YES;
445 4bf68b77 Miltiadis Vasilakis
        } else if ([containerNode.pithosContainer.name isEqualToString:@"trash"]) {
446 4bf68b77 Miltiadis Vasilakis
            NSUInteger insertIndex = 1;
447 4bf68b77 Miltiadis Vasilakis
            if (!containerPithosFound)
448 4bf68b77 Miltiadis Vasilakis
                insertIndex = 0;
449 20f54e18 Miltiadis Vasilakis
            if (![containersNodeChildren containsObject:containerNode])
450 20f54e18 Miltiadis Vasilakis
                [containersNodeChildren insertObject:containerNode atIndex:insertIndex];
451 4bf68b77 Miltiadis Vasilakis
            containerTrashFound = YES;
452 20f54e18 Miltiadis Vasilakis
        } else if (![containersNodeChildren containsObject:containerNode]) {
453 20f54e18 Miltiadis Vasilakis
            [containersNodeChildren addObject:containerNode];
454 4bf68b77 Miltiadis Vasilakis
        }
455 4bf68b77 Miltiadis Vasilakis
    }
456 4bf68b77 Miltiadis Vasilakis
    BOOL refreshAccountNode = NO;
457 4bf68b77 Miltiadis Vasilakis
    if (!containerPithosFound) {
458 4ae10a2b Miltiadis Vasilakis
        // Create pithos node
459 fb27f368 Miltiadis Vasilakis
        ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithPithos:pithosAccountManager.pithos
460 919cb043 Miltiadis Vasilakis
                                                                                                            containerName:@"pithos"];
461 8aa8e10c Miltiadis Vasilakis
        [PithosUtilities startAndWaitForRequest:containerRequest];
462 4bf68b77 Miltiadis Vasilakis
        if ([containerRequest error]) {
463 89dfe4a3 Miltiadis Vasilakis
            [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest];
464 4bf68b77 Miltiadis Vasilakis
        } else {
465 4bf68b77 Miltiadis Vasilakis
            refreshAccountNode = YES;
466 4bf68b77 Miltiadis Vasilakis
        }
467 4bf68b77 Miltiadis Vasilakis
    }
468 4bf68b77 Miltiadis Vasilakis
    if (!containerTrashFound) {
469 4ae10a2b Miltiadis Vasilakis
        // Create trash node
470 fb27f368 Miltiadis Vasilakis
        ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithPithos:pithosAccountManager.pithos 
471 919cb043 Miltiadis Vasilakis
                                                                                                            containerName:@"trash"];
472 8aa8e10c Miltiadis Vasilakis
        [PithosUtilities startAndWaitForRequest:containerRequest];
473 4bf68b77 Miltiadis Vasilakis
        if ([containerRequest error]) {
474 89dfe4a3 Miltiadis Vasilakis
            [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest];
475 4bf68b77 Miltiadis Vasilakis
        } else {
476 4bf68b77 Miltiadis Vasilakis
            refreshAccountNode = YES;
477 4bf68b77 Miltiadis Vasilakis
        }
478 4bf68b77 Miltiadis Vasilakis
    }
479 20f54e18 Miltiadis Vasilakis
    
480 20f54e18 Miltiadis Vasilakis
    if (refreshAccountNode)
481 4ae10a2b Miltiadis Vasilakis
        [accountNode refresh];
482 20f54e18 Miltiadis Vasilakis
    
483 20f54e18 Miltiadis Vasilakis
    [outlineView reloadData];
484 20f54e18 Miltiadis Vasilakis
    
485 20f54e18 Miltiadis Vasilakis
    // Expand the folder outline view
486 20f54e18 Miltiadis Vasilakis
    [outlineView expandItem:nil expandChildren:YES];
487 20f54e18 Miltiadis Vasilakis
    
488 d8426ffb Miltiadis Vasilakis
    if (((rootNode == nil) || (rootNode == containersNode) || (rootNode == sharedNode)) && [containersNodeChildren count]) {
489 20f54e18 Miltiadis Vasilakis
        rootNode = [containersNodeChildren objectAtIndex:0];
490 20f54e18 Miltiadis Vasilakis
        [browser loadColumnZero];
491 4bf68b77 Miltiadis Vasilakis
    }
492 20f54e18 Miltiadis Vasilakis
    
493 20f54e18 Miltiadis Vasilakis
    if (notification)
494 20f54e18 Miltiadis Vasilakis
        [self refresh:nil];
495 20f54e18 Miltiadis Vasilakis
}
496 20f54e18 Miltiadis Vasilakis
497 20f54e18 Miltiadis Vasilakis
- (void)pithosBrowserRefreshNeeded:(NSNotification *)notification {
498 20f54e18 Miltiadis Vasilakis
    [self refresh:nil];
499 4bf68b77 Miltiadis Vasilakis
}
500 4bf68b77 Miltiadis Vasilakis
501 e5fdf4d9 Miltiadis Vasilakis
#pragma mark -
502 20f54e18 Miltiadis Vasilakis
#pragma mark Actions
503 e5fdf4d9 Miltiadis Vasilakis
504 1b1e6fa1 Miltiadis Vasilakis
- (IBAction)forceRefresh:(id)sender {
505 258db46f Miltiadis Vasilakis
    if (![NSThread isMainThread]) {
506 258db46f Miltiadis Vasilakis
        [self performSelectorOnMainThread:@selector(forceRefresh:) withObject:sender waitUntilDone:NO];
507 258db46f Miltiadis Vasilakis
        return;
508 258db46f Miltiadis Vasilakis
    }
509 4e6acad7 Miltiadis Vasilakis
    if (editingItem)
510 4e6acad7 Miltiadis Vasilakis
        return;
511 1b1e6fa1 Miltiadis Vasilakis
    if (sender)
512 1b1e6fa1 Miltiadis Vasilakis
        [accountNode forceRefresh];
513 1b1e6fa1 Miltiadis Vasilakis
    for (NSInteger column = [browser lastColumn]; column >= 0; column--) {
514 1b1e6fa1 Miltiadis Vasilakis
        PithosNode *node = (PithosNode *)[browser parentForItemsInColumn:column];
515 1b1e6fa1 Miltiadis Vasilakis
        node.forcedRefresh = YES;
516 1b1e6fa1 Miltiadis Vasilakis
        [(PithosNode *)[browser parentForItemsInColumn:column] invalidateChildren];                      
517 1b1e6fa1 Miltiadis Vasilakis
    }
518 1b1e6fa1 Miltiadis Vasilakis
    [browser validateVisibleColumns];
519 1b1e6fa1 Miltiadis Vasilakis
}
520 1b1e6fa1 Miltiadis Vasilakis
521 e5fdf4d9 Miltiadis Vasilakis
- (IBAction)refresh:(id)sender {
522 258db46f Miltiadis Vasilakis
    if (![NSThread isMainThread]) {
523 258db46f Miltiadis Vasilakis
        [self performSelectorOnMainThread:@selector(refresh:) withObject:sender waitUntilDone:NO];
524 258db46f Miltiadis Vasilakis
        return;
525 258db46f Miltiadis Vasilakis
    }
526 4e6acad7 Miltiadis Vasilakis
    if (editingItem)
527 4e6acad7 Miltiadis Vasilakis
        return;
528 90fadc45 Miltiadis Vasilakis
    if ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) {
529 1b1e6fa1 Miltiadis Vasilakis
        [self forceRefresh:sender];
530 90fadc45 Miltiadis Vasilakis
    } else {
531 90fadc45 Miltiadis Vasilakis
        if (sender)
532 90fadc45 Miltiadis Vasilakis
            [accountNode refresh];
533 90fadc45 Miltiadis Vasilakis
        for (NSInteger column = [browser lastColumn]; column >= 0; column--) {
534 90fadc45 Miltiadis Vasilakis
            [(PithosNode *)[browser parentForItemsInColumn:column] invalidateChildren];
535 90fadc45 Miltiadis Vasilakis
        }
536 1b1e6fa1 Miltiadis Vasilakis
        [browser validateVisibleColumns];
537 605c8932 Miltiadis Vasilakis
    }
538 e5fdf4d9 Miltiadis Vasilakis
}
539 e5fdf4d9 Miltiadis Vasilakis
540 e5fdf4d9 Miltiadis Vasilakis
#pragma mark -
541 20f54e18 Miltiadis Vasilakis
#pragma mark NSBrowserDelegate
542 e5fdf4d9 Miltiadis Vasilakis
543 e5fdf4d9 Miltiadis Vasilakis
- (id)rootItemForBrowser:(NSBrowser *)browser {
544 e5fdf4d9 Miltiadis Vasilakis
    return rootNode;    
545 e5fdf4d9 Miltiadis Vasilakis
}
546 e5fdf4d9 Miltiadis Vasilakis
547 e5fdf4d9 Miltiadis Vasilakis
- (NSInteger)browser:(NSBrowser *)browser numberOfChildrenOfItem:(id)item {
548 e5fdf4d9 Miltiadis Vasilakis
    PithosNode *node = (PithosNode *)item;
549 e5fdf4d9 Miltiadis Vasilakis
    return node.children.count;
550 e5fdf4d9 Miltiadis Vasilakis
}
551 e5fdf4d9 Miltiadis Vasilakis
552 e5fdf4d9 Miltiadis Vasilakis
- (id)browser:(NSBrowser *)browser child:(NSInteger)index ofItem:(id)item {
553 e5fdf4d9 Miltiadis Vasilakis
    PithosNode *node = (PithosNode *)item;
554 e5fdf4d9 Miltiadis Vasilakis
    return [node.children objectAtIndex:index];
555 e5fdf4d9 Miltiadis Vasilakis
}
556 e5fdf4d9 Miltiadis Vasilakis
557 e5fdf4d9 Miltiadis Vasilakis
- (BOOL)browser:(NSBrowser *)browser isLeafItem:(id)item {
558 e5fdf4d9 Miltiadis Vasilakis
    PithosNode *node = (PithosNode *)item;
559 e5fdf4d9 Miltiadis Vasilakis
    return node.isLeafItem;
560 e5fdf4d9 Miltiadis Vasilakis
}
561 e5fdf4d9 Miltiadis Vasilakis
562 e5fdf4d9 Miltiadis Vasilakis
- (id)browser:(NSBrowser *)browser objectValueForItem:(id)item {
563 e5fdf4d9 Miltiadis Vasilakis
    PithosNode *node = (PithosNode *)item;
564 e5fdf4d9 Miltiadis Vasilakis
    return node;
565 e5fdf4d9 Miltiadis Vasilakis
}
566 e5fdf4d9 Miltiadis Vasilakis
567 9f3a92de Miltiadis Vasilakis
- (NSViewController *)browser:(NSBrowser *)browser previewViewControllerForLeafItem:(id)item {
568 9f3a92de Miltiadis Vasilakis
    if (sharedPreviewController == nil)
569 9f3a92de Miltiadis Vasilakis
        sharedPreviewController = [[NSViewController alloc] initWithNibName:@"PithosBrowserPreviewController" bundle:[NSBundle bundleForClass:[self class]]];
570 9f3a92de Miltiadis Vasilakis
    return sharedPreviewController;
571 9f3a92de Miltiadis Vasilakis
}
572 9f3a92de Miltiadis Vasilakis
573 155f0dfd Miltiadis Vasilakis
//- (CGFloat)browser:(NSBrowser *)browser shouldSizeColumn:(NSInteger)columnIndex forUserResize:(BOOL)forUserResize toWidth:(CGFloat)suggestedWidth  {
574 155f0dfd Miltiadis Vasilakis
//    if (!forUserResize) {
575 155f0dfd Miltiadis Vasilakis
//        id item = [browser parentForItemsInColumn:columnIndex]; 
576 155f0dfd Miltiadis Vasilakis
//        if ([self browser:browser isLeafItem:item]) {
577 155f0dfd Miltiadis Vasilakis
//            suggestedWidth = 200; 
578 155f0dfd Miltiadis Vasilakis
//        }
579 155f0dfd Miltiadis Vasilakis
//    }
580 155f0dfd Miltiadis Vasilakis
//    return suggestedWidth;
581 155f0dfd Miltiadis Vasilakis
//}
582 9f3a92de Miltiadis Vasilakis
583 605c8932 Miltiadis Vasilakis
- (BOOL)browser:(NSBrowser *)sender isColumnValid:(NSInteger)column {
584 605c8932 Miltiadis Vasilakis
    return NO;
585 605c8932 Miltiadis Vasilakis
}
586 605c8932 Miltiadis Vasilakis
587 19c353fe Miltiadis Vasilakis
#pragma mark Editing
588 19c353fe Miltiadis Vasilakis
589 19c353fe Miltiadis Vasilakis
- (BOOL)browser:(NSBrowser *)browser shouldEditItem:(id)item {
590 4ae10a2b Miltiadis Vasilakis
    PithosNode *node = (PithosNode *)item;
591 af3b9f06 Miltiadis Vasilakis
    if (node.shared || node.sharingAccount || 
592 af3b9f06 Miltiadis Vasilakis
        ([node class] == [PithosContainerNode class]) || ([node class] == [PithosAccountNode class]))
593 4ae10a2b Miltiadis Vasilakis
        return NO;
594 4e6acad7 Miltiadis Vasilakis
    editingItem = YES;
595 19c353fe Miltiadis Vasilakis
    return YES;
596 19c353fe Miltiadis Vasilakis
}
597 19c353fe Miltiadis Vasilakis
598 19c353fe Miltiadis Vasilakis
- (void)browser:(NSBrowser *)browser setObjectValue:(id)object forItem:(id)item {
599 4e6acad7 Miltiadis Vasilakis
    editingItem = NO;
600 19c353fe Miltiadis Vasilakis
    PithosNode *node = (PithosNode *)item;
601 19c353fe Miltiadis Vasilakis
    NSString *newName = (NSString *)object;
602 19c353fe Miltiadis Vasilakis
    NSUInteger newNameLength = [newName length];
603 19c353fe Miltiadis Vasilakis
    NSRange firstSlashRange = [newName rangeOfString:@"/"];
604 19c353fe Miltiadis Vasilakis
    if ((newNameLength == 0) || 
605 19c353fe Miltiadis Vasilakis
        ((firstSlashRange.length == 1) && (firstSlashRange.location != (newNameLength - 1))) || 
606 19c353fe Miltiadis Vasilakis
        ([newName isEqualToString:node.displayName])) {
607 19c353fe Miltiadis Vasilakis
        return;
608 19c353fe Miltiadis Vasilakis
    }
609 19c353fe Miltiadis Vasilakis
    if (([node class] == [PithosObjectNode class]) || 
610 1b1e6fa1 Miltiadis Vasilakis
        (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) {
611 d8426ffb Miltiadis Vasilakis
        // Operation: Rename (move) an object or subdir/ node
612 d8426ffb Miltiadis Vasilakis
        __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
613 b58ff732 Miltiadis Vasilakis
            @autoreleasepool {
614 b58ff732 Miltiadis Vasilakis
                if (operation.isCancelled)
615 b58ff732 Miltiadis Vasilakis
                    return;
616 b58ff732 Miltiadis Vasilakis
                NSString *destinationObjectName = [[node.pithosObject.name stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName];
617 b58ff732 Miltiadis Vasilakis
                if ([newName hasSuffix:@"/"])
618 b58ff732 Miltiadis Vasilakis
                    destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
619 b58ff732 Miltiadis Vasilakis
                NSError *error = nil;
620 b58ff732 Miltiadis Vasilakis
                BOOL isDirectory;
621 fb27f368 Miltiadis Vasilakis
                if ([PithosUtilities objectExistsAtPithos:pithosAccountManager.pithos
622 b58ff732 Miltiadis Vasilakis
                                            containerName:node.pithosContainer.name 
623 b58ff732 Miltiadis Vasilakis
                                               objectName:destinationObjectName 
624 b58ff732 Miltiadis Vasilakis
                                                    error:&error 
625 b58ff732 Miltiadis Vasilakis
                                              isDirectory:&isDirectory 
626 b58ff732 Miltiadis Vasilakis
                                           sharingAccount:nil]) {
627 b58ff732 Miltiadis Vasilakis
                    dispatch_async(dispatch_get_main_queue(), ^{
628 cb6abe72 Miltiadis Vasilakis
                        NSAlert *alert = [[NSAlert alloc] init];
629 b58ff732 Miltiadis Vasilakis
                        [alert setMessageText:@"Name Taken"];
630 b58ff732 Miltiadis Vasilakis
                        [alert setInformativeText:[NSString stringWithFormat:@"The name '%@' is already taken. Please choose a different name", newName]];
631 b58ff732 Miltiadis Vasilakis
                        [alert addButtonWithTitle:@"OK"];
632 b58ff732 Miltiadis Vasilakis
                        [alert runModal];
633 b58ff732 Miltiadis Vasilakis
                    });
634 b58ff732 Miltiadis Vasilakis
                    return;
635 b58ff732 Miltiadis Vasilakis
                } else if (error) {
636 b58ff732 Miltiadis Vasilakis
                    return;
637 b58ff732 Miltiadis Vasilakis
                }
638 b58ff732 Miltiadis Vasilakis
                if (operation.isCancelled)
639 b58ff732 Miltiadis Vasilakis
                    return;
640 fb27f368 Miltiadis Vasilakis
                ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithPithos:pithosAccountManager.pithos
641 b58ff732 Miltiadis Vasilakis
                                                                                       containerName:node.pithosContainer.name 
642 b58ff732 Miltiadis Vasilakis
                                                                                          objectName:node.pithosObject.name 
643 b58ff732 Miltiadis Vasilakis
                                                                            destinationContainerName:node.pithosContainer.name 
644 b58ff732 Miltiadis Vasilakis
                                                                               destinationObjectName:destinationObjectName 
645 b58ff732 Miltiadis Vasilakis
                                                                                       checkIfExists:NO];
646 b58ff732 Miltiadis Vasilakis
                if (!operation.isCancelled && objectRequest) {
647 19c353fe Miltiadis Vasilakis
                    objectRequest.delegate = self;
648 4c1c46fd Miltiadis Vasilakis
                    objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
649 4c1c46fd Miltiadis Vasilakis
                    objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
650 4c1c46fd Miltiadis Vasilakis
                    NSString *messagePrefix = [NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", 
651 4c1c46fd Miltiadis Vasilakis
                                               [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
652 4c1c46fd Miltiadis Vasilakis
                                               [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
653 4c1c46fd Miltiadis Vasilakis
                                               [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
654 4c1c46fd Miltiadis Vasilakis
                                               [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
655 1b1e6fa1 Miltiadis Vasilakis
                    PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove 
656 4c1c46fd Miltiadis Vasilakis
                                                                               message:messagePrefix];
657 1b1e6fa1 Miltiadis Vasilakis
                    [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
658 1b1e6fa1 Miltiadis Vasilakis
                     [NSDictionary dictionaryWithObjectsAndKeys:
659 1b1e6fa1 Miltiadis Vasilakis
                      [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", 
660 1b1e6fa1 Miltiadis Vasilakis
                      [NSNumber numberWithBool:YES], @"refresh", 
661 1b1e6fa1 Miltiadis Vasilakis
                      activity, @"activity", 
662 4c1c46fd Miltiadis Vasilakis
                      [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
663 4c1c46fd Miltiadis Vasilakis
                      [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
664 4c1c46fd Miltiadis Vasilakis
                      [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
665 4c1c46fd Miltiadis Vasilakis
                      [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
666 1b1e6fa1 Miltiadis Vasilakis
                      [NSNumber numberWithUnsignedInteger:10], @"retries", 
667 4c1c46fd Miltiadis Vasilakis
                      NSStringFromSelector(@selector(moveFinished:)), @"didFinishSelector", 
668 4c1c46fd Miltiadis Vasilakis
                      NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
669 4c1c46fd Miltiadis Vasilakis
                      moveNetworkQueue, @"networkQueue", 
670 d8426ffb Miltiadis Vasilakis
                      @"move", @"operationType", 
671 1b1e6fa1 Miltiadis Vasilakis
                      nil]];
672 4c1c46fd Miltiadis Vasilakis
                    [moveNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
673 19c353fe Miltiadis Vasilakis
                }
674 19c353fe Miltiadis Vasilakis
            }
675 b58ff732 Miltiadis Vasilakis
        }];
676 b58ff732 Miltiadis Vasilakis
        [moveQueue addOperation:operation];
677 b58ff732 Miltiadis Vasilakis
    } else if ([node class] == [PithosSubdirNode class]) {
678 b58ff732 Miltiadis Vasilakis
        if (firstSlashRange.length == 1)
679 b58ff732 Miltiadis Vasilakis
            return;
680 b58ff732 Miltiadis Vasilakis
        // Operation: Rename (move) a subdir node and its descendants
681 b58ff732 Miltiadis Vasilakis
        // The resulting ASIPithosObjectRequests are chained through dependencies
682 b58ff732 Miltiadis Vasilakis
        __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
683 b58ff732 Miltiadis Vasilakis
            @autoreleasepool {
684 b58ff732 Miltiadis Vasilakis
                if (operation.isCancelled)
685 b58ff732 Miltiadis Vasilakis
                    return;
686 b58ff732 Miltiadis Vasilakis
                NSString *destinationObjectName = [[node.pithosObject.name stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName];
687 b58ff732 Miltiadis Vasilakis
                NSError *error = nil;
688 b58ff732 Miltiadis Vasilakis
                BOOL isDirectory;
689 fb27f368 Miltiadis Vasilakis
                if ([PithosUtilities objectExistsAtPithos:pithosAccountManager.pithos
690 b58ff732 Miltiadis Vasilakis
                                            containerName:node.pithosContainer.name 
691 b58ff732 Miltiadis Vasilakis
                                               objectName:destinationObjectName 
692 b58ff732 Miltiadis Vasilakis
                                                    error:&error 
693 b58ff732 Miltiadis Vasilakis
                                              isDirectory:&isDirectory 
694 b58ff732 Miltiadis Vasilakis
                                           sharingAccount:nil]) {
695 b58ff732 Miltiadis Vasilakis
                    dispatch_async(dispatch_get_main_queue(), ^{
696 cb6abe72 Miltiadis Vasilakis
                        NSAlert *alert = [[NSAlert alloc] init];
697 b58ff732 Miltiadis Vasilakis
                        [alert setMessageText:@"Name Taken"];
698 b58ff732 Miltiadis Vasilakis
                        [alert setInformativeText:[NSString stringWithFormat:@"The name '%@' is already taken. Please choose a different name", newName]];
699 b58ff732 Miltiadis Vasilakis
                        [alert addButtonWithTitle:@"OK"];
700 b58ff732 Miltiadis Vasilakis
                        [alert runModal];
701 b58ff732 Miltiadis Vasilakis
                    });
702 b58ff732 Miltiadis Vasilakis
                    return;
703 b58ff732 Miltiadis Vasilakis
                } else if (error) {
704 b58ff732 Miltiadis Vasilakis
                    return;
705 b58ff732 Miltiadis Vasilakis
                }
706 b58ff732 Miltiadis Vasilakis
                if (operation.isCancelled)
707 b58ff732 Miltiadis Vasilakis
                    return;
708 b58ff732 Miltiadis Vasilakis
                if (node.pithosObject.subdir)
709 b58ff732 Miltiadis Vasilakis
                    destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
710 fb27f368 Miltiadis Vasilakis
                NSArray *objectRequests = [PithosUtilities moveObjectRequestsForSubdirWithPithos:pithosAccountManager.pithos
711 b58ff732 Miltiadis Vasilakis
                                                                                   containerName:node.pithosContainer.name 
712 b58ff732 Miltiadis Vasilakis
                                                                                      objectName:node.pithosObject.name 
713 b58ff732 Miltiadis Vasilakis
                                                                        destinationContainerName:node.pithosContainer.name 
714 b58ff732 Miltiadis Vasilakis
                                                                           destinationObjectName:destinationObjectName 
715 b58ff732 Miltiadis Vasilakis
                                                                                   checkIfExists:NO];
716 b58ff732 Miltiadis Vasilakis
                if (!operation.isCancelled && objectRequests) {
717 b58ff732 Miltiadis Vasilakis
                    ASIPithosObjectRequest *previousObjectRequest = nil;
718 b58ff732 Miltiadis Vasilakis
                    for (ASIPithosObjectRequest *objectRequest in objectRequests) {
719 b58ff732 Miltiadis Vasilakis
                        if (operation.isCancelled)
720 b58ff732 Miltiadis Vasilakis
                            return;
721 b58ff732 Miltiadis Vasilakis
                        objectRequest.delegate = self;
722 b58ff732 Miltiadis Vasilakis
                        objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
723 b58ff732 Miltiadis Vasilakis
                        objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
724 b58ff732 Miltiadis Vasilakis
                        NSString *messagePrefix = [NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", 
725 b58ff732 Miltiadis Vasilakis
                                                   [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
726 b58ff732 Miltiadis Vasilakis
                                                   [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
727 b58ff732 Miltiadis Vasilakis
                                                   [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
728 b58ff732 Miltiadis Vasilakis
                                                   [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
729 b58ff732 Miltiadis Vasilakis
                        PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove 
730 b58ff732 Miltiadis Vasilakis
                                                                                   message:messagePrefix];
731 b58ff732 Miltiadis Vasilakis
                        [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
732 b58ff732 Miltiadis Vasilakis
                         [NSDictionary dictionaryWithObjectsAndKeys:
733 b58ff732 Miltiadis Vasilakis
                          [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", 
734 b58ff732 Miltiadis Vasilakis
                          [NSNumber numberWithBool:YES], @"refresh", 
735 b58ff732 Miltiadis Vasilakis
                          activity, @"activity", 
736 b58ff732 Miltiadis Vasilakis
                          [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
737 b58ff732 Miltiadis Vasilakis
                          [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
738 b58ff732 Miltiadis Vasilakis
                          [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
739 b58ff732 Miltiadis Vasilakis
                          [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
740 b58ff732 Miltiadis Vasilakis
                          [NSNumber numberWithUnsignedInteger:10], @"retries", 
741 b58ff732 Miltiadis Vasilakis
                          NSStringFromSelector(@selector(moveFinished:)), @"didFinishSelector", 
742 b58ff732 Miltiadis Vasilakis
                          NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
743 b58ff732 Miltiadis Vasilakis
                          moveNetworkQueue, @"networkQueue", 
744 b58ff732 Miltiadis Vasilakis
                          @"move", @"operationType", 
745 b58ff732 Miltiadis Vasilakis
                          nil]];
746 b58ff732 Miltiadis Vasilakis
                        if (previousObjectRequest)
747 b58ff732 Miltiadis Vasilakis
                            [objectRequest addDependency:previousObjectRequest];
748 b58ff732 Miltiadis Vasilakis
                        previousObjectRequest = objectRequest;
749 b58ff732 Miltiadis Vasilakis
                        [moveNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
750 b58ff732 Miltiadis Vasilakis
                    }
751 b58ff732 Miltiadis Vasilakis
                }
752 b58ff732 Miltiadis Vasilakis
            }
753 d8426ffb Miltiadis Vasilakis
        }];
754 d8426ffb Miltiadis Vasilakis
        [moveQueue addOperation:operation];
755 19c353fe Miltiadis Vasilakis
    }
756 19c353fe Miltiadis Vasilakis
}
757 19c353fe Miltiadis Vasilakis
758 f2f50f78 Miltiadis Vasilakis
#pragma mark Drag and Drop source
759 6dc7e931 Miltiadis Vasilakis
760 4ae10a2b Miltiadis Vasilakis
- (BOOL)browser:(NSBrowser *)aBrowser canDragRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column 
761 4ae10a2b Miltiadis Vasilakis
      withEvent:(NSEvent *)event {
762 4ae10a2b Miltiadis Vasilakis
    NSIndexPath *baseIndexPath = [browser indexPathForColumn:column];
763 4ae10a2b Miltiadis Vasilakis
    __block BOOL result = YES;
764 4ae10a2b Miltiadis Vasilakis
    [rowIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop){
765 4ae10a2b Miltiadis Vasilakis
        PithosNode *node = [browser itemAtIndexPath:[baseIndexPath indexPathByAddingIndex:idx]];
766 3b22507d Miltiadis Vasilakis
        if (([node class] == [PithosContainerNode class]) || ([node class] == [PithosAccountNode class])) {
767 4ae10a2b Miltiadis Vasilakis
            result = NO;
768 4ae10a2b Miltiadis Vasilakis
            *stop = YES;
769 4ae10a2b Miltiadis Vasilakis
        }
770 4ae10a2b Miltiadis Vasilakis
    }];
771 4ae10a2b Miltiadis Vasilakis
    return result;
772 4ae10a2b Miltiadis Vasilakis
}
773 4ae10a2b Miltiadis Vasilakis
774 6dc7e931 Miltiadis Vasilakis
- (BOOL)browser:(NSBrowser *)aBrowser writeRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column 
775 6dc7e931 Miltiadis Vasilakis
   toPasteboard:(NSPasteboard *)pasteboard {
776 6dc7e931 Miltiadis Vasilakis
    NSMutableArray *propertyList = [NSMutableArray arrayWithCapacity:[rowIndexes count]];
777 d41b3577 Miltiadis Vasilakis
    NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:[rowIndexes count]];
778 133b1f2d Miltiadis Vasilakis
    NSIndexPath *baseIndexPath = [browser indexPathForColumn:column];
779 133b1f2d Miltiadis Vasilakis
    [rowIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop){
780 133b1f2d Miltiadis Vasilakis
        PithosNode *node = [browser itemAtIndexPath:[baseIndexPath indexPathByAddingIndex:idx]];
781 6dc7e931 Miltiadis Vasilakis
        [propertyList addObject:[node.pithosObject.name pathExtension]];
782 d41b3577 Miltiadis Vasilakis
        [nodes addObject:node];
783 133b1f2d Miltiadis Vasilakis
    }];
784 6dc7e931 Miltiadis Vasilakis
785 6dc7e931 Miltiadis Vasilakis
    [pasteboard declareTypes:[NSArray arrayWithObject:NSFilesPromisePboardType] owner:self];
786 6dc7e931 Miltiadis Vasilakis
    [pasteboard setPropertyList:propertyList forType:NSFilesPromisePboardType];
787 d41b3577 Miltiadis Vasilakis
    self.draggedNodes = nodes;
788 d41b3577 Miltiadis Vasilakis
    self.draggedParentNode = [browser parentForItemsInColumn:column];
789 6dc7e931 Miltiadis Vasilakis
    return YES;
790 6dc7e931 Miltiadis Vasilakis
}
791 6dc7e931 Miltiadis Vasilakis
792 6dc7e931 Miltiadis Vasilakis
- (NSArray *)browser:(NSBrowser *)aBrowser namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination 
793 6dc7e931 Miltiadis Vasilakis
forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column {
794 3b22507d Miltiadis Vasilakis
    NSMutableArray *names = [NSMutableArray arrayWithCapacity:[draggedNodes count]];
795 cfc17d33 Miltiadis Vasilakis
    for (PithosNode *node in draggedNodes) {
796 cfc17d33 Miltiadis Vasilakis
        [names addObject:node.displayName];
797 6dc7e931 Miltiadis Vasilakis
        // If the node is a subdir ask if the whole tree should be downloaded
798 d7c03491 Miltiadis Vasilakis
        if ([node class] == [PithosSubdirNode class]) {
799 cb6abe72 Miltiadis Vasilakis
            NSAlert *alert = [[NSAlert alloc] init];
800 6dc7e931 Miltiadis Vasilakis
            [alert setMessageText:@"Download directory"];
801 6dc7e931 Miltiadis Vasilakis
            [alert setInformativeText:[NSString stringWithFormat:@"'%@' is a directory, do you want to download its contents?", node.displayName]];
802 6dc7e931 Miltiadis Vasilakis
            [alert addButtonWithTitle:@"OK"];
803 6dc7e931 Miltiadis Vasilakis
            [alert addButtonWithTitle:@"Cancel"];
804 6dc7e931 Miltiadis Vasilakis
            NSInteger choice = [alert runModal];
805 cfc17d33 Miltiadis Vasilakis
            if (choice == NSAlertFirstButtonReturn)
806 de0873d4 Miltiadis Vasilakis
                [self downloadNode:node toDirectory:[dropDestination path] withNewFileName:nil version:nil checkIfExists:YES];
807 6dc7e931 Miltiadis Vasilakis
        } else {
808 de0873d4 Miltiadis Vasilakis
            [self downloadNode:node toDirectory:[dropDestination path] withNewFileName:nil version:nil checkIfExists:YES];
809 6dc7e931 Miltiadis Vasilakis
        }
810 3b22507d Miltiadis Vasilakis
    }
811 6dc7e931 Miltiadis Vasilakis
    return names;
812 6dc7e931 Miltiadis Vasilakis
}
813 6dc7e931 Miltiadis Vasilakis
814 f2f50f78 Miltiadis Vasilakis
#pragma mark Drag and Drop destination
815 f2f50f78 Miltiadis Vasilakis
816 f2f50f78 Miltiadis Vasilakis
- (NSDragOperation)browser:aBrowser 
817 f2f50f78 Miltiadis Vasilakis
              validateDrop:(id<NSDraggingInfo>)info 
818 f2f50f78 Miltiadis Vasilakis
               proposedRow:(NSInteger *)row 
819 f2f50f78 Miltiadis Vasilakis
                    column:(NSInteger *)column 
820 f2f50f78 Miltiadis Vasilakis
             dropOperation:(NSBrowserDropOperation *)dropOperation {
821 f2f50f78 Miltiadis Vasilakis
    NSDragOperation result = NSDragOperationNone;
822 6a9b9f40 Miltiadis Vasilakis
    if ([[[info draggingPasteboard] types] containsObject:NSFilenamesPboardType]) {
823 d41b3577 Miltiadis Vasilakis
        // For a drop above, the drop is redirected to the parent item
824 f2f50f78 Miltiadis Vasilakis
        if (*dropOperation == NSBrowserDropAbove)
825 f2f50f78 Miltiadis Vasilakis
            *row = -1;
826 f2f50f78 Miltiadis Vasilakis
        // Only allow dropping in folders
827 f2f50f78 Miltiadis Vasilakis
        if (*column != -1) {
828 af3b9f06 Miltiadis Vasilakis
            PithosNode *dropNode;
829 f2f50f78 Miltiadis Vasilakis
            if (*row != -1) {
830 d41b3577 Miltiadis Vasilakis
                // Check if the node is not a folder and if so redirect to the parent item
831 af3b9f06 Miltiadis Vasilakis
                dropNode = [browser itemAtRow:*row inColumn:*column];
832 6e5693f9 Miltiadis Vasilakis
                if ([dropNode class] == [PithosObjectNode class])
833 f2f50f78 Miltiadis Vasilakis
                    *row = -1;
834 33bf3856 Miltiadis Vasilakis
            }
835 af3b9f06 Miltiadis Vasilakis
            if (*row == -1)
836 af3b9f06 Miltiadis Vasilakis
                dropNode = [browser parentForItemsInColumn:*column];
837 af3b9f06 Miltiadis Vasilakis
            
838 6e5693f9 Miltiadis Vasilakis
            if (!dropNode.shared && 
839 6e5693f9 Miltiadis Vasilakis
                (!dropNode.sharingAccount || 
840 6e5693f9 Miltiadis Vasilakis
                 ([dropNode class] == [PithosSubdirNode class]) || 
841 6e5693f9 Miltiadis Vasilakis
                 ([dropNode class] == [PithosContainerNode class]))) {
842 af3b9f06 Miltiadis Vasilakis
                *dropOperation = NSBrowserDropOn;
843 af3b9f06 Miltiadis Vasilakis
                result = NSDragOperationCopy;
844 af3b9f06 Miltiadis Vasilakis
            }
845 f2f50f78 Miltiadis Vasilakis
        }
846 d41b3577 Miltiadis Vasilakis
    } else if ([[[info draggingPasteboard] types] containsObject:NSFilesPromisePboardType]) {
847 d41b3577 Miltiadis Vasilakis
        // For a drop above, the drop is redirected to the parent item
848 d41b3577 Miltiadis Vasilakis
        if (*dropOperation == NSBrowserDropAbove) 
849 d41b3577 Miltiadis Vasilakis
            *row = -1;
850 d41b3577 Miltiadis Vasilakis
        // Only allow dropping in folders
851 d41b3577 Miltiadis Vasilakis
        if (*column != -1) {
852 d41b3577 Miltiadis Vasilakis
            PithosNode *dropNode;
853 d41b3577 Miltiadis Vasilakis
            if (*row != -1) {
854 d41b3577 Miltiadis Vasilakis
                // Check if the node is not a folder and if so redirect to the parent item
855 d41b3577 Miltiadis Vasilakis
                dropNode = [browser itemAtRow:*row inColumn:*column];
856 6e5693f9 Miltiadis Vasilakis
                if ([dropNode class] == [PithosObjectNode class])
857 d41b3577 Miltiadis Vasilakis
                    *row = -1;
858 d41b3577 Miltiadis Vasilakis
            }
859 d41b3577 Miltiadis Vasilakis
            if (*row == -1)
860 d41b3577 Miltiadis Vasilakis
                dropNode = [browser parentForItemsInColumn:*column];
861 d41b3577 Miltiadis Vasilakis
            
862 af3b9f06 Miltiadis Vasilakis
            if (!dropNode.shared && !dropNode.sharingAccount) {
863 4ae10a2b Miltiadis Vasilakis
                if ([info draggingSourceOperationMask] & NSDragOperationMove) {
864 4ae10a2b Miltiadis Vasilakis
                    // NSDragOperationCopy | NSDragOperationMove -> NSDragOperationMove
865 4ae10a2b Miltiadis Vasilakis
                    if ((([dropNode class] == [PithosContainerNode class]) || 
866 4ae10a2b Miltiadis Vasilakis
                         dropNode.pithosObject.subdir || 
867 4ae10a2b Miltiadis Vasilakis
                         ![dropNode.pithosObject.name hasSuffix:@"/"]) && 
868 4ae10a2b Miltiadis Vasilakis
                        ![dropNode isEqualTo:draggedParentNode]) { 
869 4ae10a2b Miltiadis Vasilakis
    //                    ![dropNode isEqualTo:draggedParentNode] && 
870 4ae10a2b Miltiadis Vasilakis
    //                    ![draggedNodes containsObject:dropNode]) {                
871 4ae10a2b Miltiadis Vasilakis
                        result = NSDragOperationMove;
872 4ae10a2b Miltiadis Vasilakis
                    }
873 4ae10a2b Miltiadis Vasilakis
                } else if ([info draggingSourceOperationMask] & NSDragOperationCopy) {
874 4ae10a2b Miltiadis Vasilakis
                    // NSDragOperationCopy (Option modifier) -> NSDragOperationCopy
875 4ae10a2b Miltiadis Vasilakis
                    if (([dropNode class] == [PithosContainerNode class]) || 
876 4ae10a2b Miltiadis Vasilakis
                        dropNode.pithosObject.subdir || 
877 4ae10a2b Miltiadis Vasilakis
                        ![dropNode.pithosObject.name hasSuffix:@"/"]) { 
878 4ae10a2b Miltiadis Vasilakis
                        result = NSDragOperationCopy;
879 4ae10a2b Miltiadis Vasilakis
                    }
880 d41b3577 Miltiadis Vasilakis
                }
881 d41b3577 Miltiadis Vasilakis
            }
882 d41b3577 Miltiadis Vasilakis
        }
883 f2f50f78 Miltiadis Vasilakis
    }
884 f2f50f78 Miltiadis Vasilakis
    return result;
885 f2f50f78 Miltiadis Vasilakis
}
886 f2f50f78 Miltiadis Vasilakis
887 f2f50f78 Miltiadis Vasilakis
- (BOOL)browser:(NSBrowser *)aBrowser 
888 f2f50f78 Miltiadis Vasilakis
     acceptDrop:(id<NSDraggingInfo>)info 
889 f2f50f78 Miltiadis Vasilakis
          atRow:(NSInteger)row 
890 f2f50f78 Miltiadis Vasilakis
         column:(NSInteger)column 
891 f2f50f78 Miltiadis Vasilakis
  dropOperation:(NSBrowserDropOperation)dropOperation {
892 d41b3577 Miltiadis Vasilakis
    if ([[[info draggingPasteboard] types] containsObject:NSFilenamesPboardType]) {
893 d41b3577 Miltiadis Vasilakis
        NSArray *filenames = [[info draggingPasteboard] propertyListForType:NSFilenamesPboardType];
894 9990166e Miltiadis Vasilakis
        DLog(@"drag in operation: %lu filenames: %@", [info draggingSourceOperationMask], filenames);
895 d41b3577 Miltiadis Vasilakis
        if ((column != -1) && (filenames != nil)) {
896 1b1e6fa1 Miltiadis Vasilakis
            PithosNode *node;
897 d41b3577 Miltiadis Vasilakis
            if (row != -1)
898 d41b3577 Miltiadis Vasilakis
                node = [browser itemAtRow:row inColumn:column];
899 d41b3577 Miltiadis Vasilakis
            else
900 d41b3577 Miltiadis Vasilakis
                node = [browser parentForItemsInColumn:column];
901 9990166e Miltiadis Vasilakis
            DLog(@"drag in node: %@", node.url);
902 67e3336f Miltiadis Vasilakis
            return [self uploadFiles:filenames toNode:node];
903 67e3336f Miltiadis Vasilakis
        }
904 67e3336f Miltiadis Vasilakis
    } else if ([[[info draggingPasteboard] types] containsObject:NSFilesPromisePboardType]) {
905 9990166e Miltiadis Vasilakis
        DLog(@"drag local operation: %lu nodes: %@", [info draggingSourceOperationMask], draggedNodes);
906 67e3336f Miltiadis Vasilakis
        if ((column != -1) && (draggedNodes != nil)) {
907 1b1e6fa1 Miltiadis Vasilakis
            PithosNode *node;
908 67e3336f Miltiadis Vasilakis
            if (row != -1)
909 67e3336f Miltiadis Vasilakis
                node = [browser itemAtRow:row inColumn:column];
910 d41b3577 Miltiadis Vasilakis
            else
911 67e3336f Miltiadis Vasilakis
                node = [browser parentForItemsInColumn:column];
912 9990166e Miltiadis Vasilakis
            DLog(@"drag local node: %@", node.url);
913 67e3336f Miltiadis Vasilakis
            if ([info draggingSourceOperationMask] & NSDragOperationMove)
914 67e3336f Miltiadis Vasilakis
                return [self moveNodes:draggedNodes toNode:node];
915 67e3336f Miltiadis Vasilakis
            else if ([info draggingSourceOperationMask] & NSDragOperationCopy)
916 3f220848 Miltiadis Vasilakis
                return [self cpyNodes:draggedNodes toNode:node];
917 67e3336f Miltiadis Vasilakis
        }
918 67e3336f Miltiadis Vasilakis
    }
919 67e3336f Miltiadis Vasilakis
    return NO;
920 67e3336f Miltiadis Vasilakis
}
921 67e3336f Miltiadis Vasilakis
922 67e3336f Miltiadis Vasilakis
#pragma mark -
923 af9f2aee Miltiadis Vasilakis
#pragma mark NSBrowser Actions
924 af9f2aee Miltiadis Vasilakis
925 af9f2aee Miltiadis Vasilakis
- (void)browserDoubleAction:(id)sender {
926 af9f2aee Miltiadis Vasilakis
    NSInteger column = [browser clickedColumn];
927 af9f2aee Miltiadis Vasilakis
    NSInteger row = [browser clickedRow];
928 af9f2aee Miltiadis Vasilakis
    if ((column == -1) || (row == -1))
929 af9f2aee Miltiadis Vasilakis
        return;
930 af9f2aee Miltiadis Vasilakis
    NSIndexPath *clickedNodeIndexPath = [[browser indexPathForColumn:column] indexPathByAddingIndex:row];
931 af9f2aee Miltiadis Vasilakis
    NSArray *menuNodesIndexPaths = [browser selectionIndexPaths];
932 af9f2aee Miltiadis Vasilakis
    NSMutableArray *menuNodes = [NSMutableArray arrayWithCapacity:[menuNodesIndexPaths count]];
933 af9f2aee Miltiadis Vasilakis
    if ([menuNodesIndexPaths containsObject:clickedNodeIndexPath]) {
934 af9f2aee Miltiadis Vasilakis
        for (NSIndexPath *nodeIndexPath in menuNodesIndexPaths) {
935 af9f2aee Miltiadis Vasilakis
            [menuNodes addObject:[browser itemAtIndexPath:nodeIndexPath]];
936 af9f2aee Miltiadis Vasilakis
        }
937 af9f2aee Miltiadis Vasilakis
    } else {
938 af9f2aee Miltiadis Vasilakis
        [menuNodes addObject:[browser itemAtIndexPath:clickedNodeIndexPath]];
939 af9f2aee Miltiadis Vasilakis
    }
940 cb6abe72 Miltiadis Vasilakis
    NSMenuItem *menuItem = [[NSMenuItem alloc] init];
941 af9f2aee Miltiadis Vasilakis
    menuItem.representedObject = menuNodes;
942 af9f2aee Miltiadis Vasilakis
    [self menuDownload:menuItem];
943 af9f2aee Miltiadis Vasilakis
}
944 af9f2aee Miltiadis Vasilakis
945 af9f2aee Miltiadis Vasilakis
#pragma mark -
946 67e3336f Miltiadis Vasilakis
#pragma mark Drag and Drop methods
947 67e3336f Miltiadis Vasilakis
948 de0873d4 Miltiadis Vasilakis
- (void)downloadNode:(PithosNode *)node toDirectory:(NSString *)dirPath withNewFileName:(NSString *)newFileName 
949 de0873d4 Miltiadis Vasilakis
             version:(NSString *)version checkIfExists:(BOOL)checkIfExists {
950 cfc17d33 Miltiadis Vasilakis
    if ([node class] == [PithosSubdirNode class]) {
951 cfc17d33 Miltiadis Vasilakis
        // XXX newFilename and version are ignored in the case of a subdir node for now
952 cfc17d33 Miltiadis Vasilakis
        // Operation: Download a subdir node and its descendants
953 cfc17d33 Miltiadis Vasilakis
        // The resulting ASIPithosObjectRequests are chained through dependencies
954 cfc17d33 Miltiadis Vasilakis
        __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
955 b58ff732 Miltiadis Vasilakis
            @autoreleasepool {
956 b58ff732 Miltiadis Vasilakis
                if (operation.isCancelled)
957 b58ff732 Miltiadis Vasilakis
                    return;
958 fb27f368 Miltiadis Vasilakis
                NSArray *objectRequests = [PithosUtilities objectDataRequestsForSubdirWithPithos:pithosAccountManager.pithos
959 b58ff732 Miltiadis Vasilakis
                                                                                   containerName:node.pithosContainer.name 
960 b58ff732 Miltiadis Vasilakis
                                                                                      objectName:node.pithosObject.name 
961 b58ff732 Miltiadis Vasilakis
                                                                                     toDirectory:dirPath 
962 b58ff732 Miltiadis Vasilakis
                                                                                   checkIfExists:checkIfExists 
963 b58ff732 Miltiadis Vasilakis
                                                                                  sharingAccount:node.sharingAccount];
964 b58ff732 Miltiadis Vasilakis
                if (!operation.isCancelled && objectRequests) {
965 b58ff732 Miltiadis Vasilakis
                    ASIPithosObjectRequest *previousObjectRequest = nil;
966 b58ff732 Miltiadis Vasilakis
                    for (__block ASIPithosObjectRequest *objectRequest in objectRequests) {
967 b58ff732 Miltiadis Vasilakis
                        if (operation.isCancelled)
968 b58ff732 Miltiadis Vasilakis
                            return;
969 b58ff732 Miltiadis Vasilakis
                        objectRequest.delegate = self;
970 b58ff732 Miltiadis Vasilakis
                        objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
971 b58ff732 Miltiadis Vasilakis
                        objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
972 b58ff732 Miltiadis Vasilakis
                        NSString *messagePrefix = [NSString stringWithFormat:@"Downloading '%@'", [objectRequest.userInfo objectForKey:@"fileName"]];
973 b58ff732 Miltiadis Vasilakis
                        PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDownload 
974 b58ff732 Miltiadis Vasilakis
                                                                                   message:[messagePrefix stringByAppendingString:@" (0%)"]
975 b58ff732 Miltiadis Vasilakis
                                                                                totalBytes:[[objectRequest.userInfo objectForKey:@"bytes"] unsignedIntegerValue] 
976 b58ff732 Miltiadis Vasilakis
                                                                              currentBytes:0];
977 b58ff732 Miltiadis Vasilakis
                        dispatch_async(dispatch_get_main_queue(), ^{
978 b58ff732 Miltiadis Vasilakis
                            [activityFacility updateActivity:activity withMessage:activity.message];  
979 b58ff732 Miltiadis Vasilakis
                        });
980 b58ff732 Miltiadis Vasilakis
                        [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
981 b58ff732 Miltiadis Vasilakis
                         [NSDictionary dictionaryWithObjectsAndKeys:
982 b58ff732 Miltiadis Vasilakis
                          activity, @"activity", 
983 b58ff732 Miltiadis Vasilakis
                          [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
984 b58ff732 Miltiadis Vasilakis
                          [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
985 b58ff732 Miltiadis Vasilakis
                          [messagePrefix stringByAppendingString:@" (100%)"], @"finishedActivityMessage", 
986 b58ff732 Miltiadis Vasilakis
                          [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", 
987 b58ff732 Miltiadis Vasilakis
                          [NSNumber numberWithUnsignedInteger:10], @"retries", 
988 b58ff732 Miltiadis Vasilakis
                          NSStringFromSelector(@selector(downloadObjectFinished:)), @"didFinishSelector", 
989 b58ff732 Miltiadis Vasilakis
                          NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
990 b58ff732 Miltiadis Vasilakis
                          downloadNetworkQueue, @"networkQueue", 
991 b58ff732 Miltiadis Vasilakis
                          @"download", @"operationType", 
992 b58ff732 Miltiadis Vasilakis
                          nil]];
993 b58ff732 Miltiadis Vasilakis
                        [objectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){
994 b58ff732 Miltiadis Vasilakis
                            [activityFacility updateActivity:activity 
995 b58ff732 Miltiadis Vasilakis
                                                 withMessage:[messagePrefix stringByAppendingFormat:@" (%.0f%%)", (activity.totalBytes ? (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0)) : 100)] 
996 b58ff732 Miltiadis Vasilakis
                                                  totalBytes:activity.totalBytes 
997 b58ff732 Miltiadis Vasilakis
                                                currentBytes:(activity.currentBytes + size)];
998 b58ff732 Miltiadis Vasilakis
                        }];
999 b58ff732 Miltiadis Vasilakis
                        if (previousObjectRequest)
1000 b58ff732 Miltiadis Vasilakis
                            [objectRequest addDependency:previousObjectRequest];
1001 b58ff732 Miltiadis Vasilakis
                        previousObjectRequest = objectRequest;
1002 b58ff732 Miltiadis Vasilakis
                        [downloadNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest]];
1003 cfc17d33 Miltiadis Vasilakis
                    }
1004 b58ff732 Miltiadis Vasilakis
                }
1005 b58ff732 Miltiadis Vasilakis
            }
1006 b58ff732 Miltiadis Vasilakis
        }];
1007 b58ff732 Miltiadis Vasilakis
        [downloadQueue addOperation:operation];
1008 b58ff732 Miltiadis Vasilakis
    } else if ([node class] == [PithosObjectNode class]) {
1009 b58ff732 Miltiadis Vasilakis
        // Operation: Download an object node
1010 b58ff732 Miltiadis Vasilakis
        __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1011 b58ff732 Miltiadis Vasilakis
            @autoreleasepool {
1012 b58ff732 Miltiadis Vasilakis
                if (operation.isCancelled)
1013 b58ff732 Miltiadis Vasilakis
                    return;
1014 fb27f368 Miltiadis Vasilakis
                __block ASIPithosObjectRequest *objectRequest = [PithosUtilities objectDataRequestWithPithos:pithosAccountManager.pithos
1015 b58ff732 Miltiadis Vasilakis
                                                                                               containerName:node.pithosContainer.name 
1016 b58ff732 Miltiadis Vasilakis
                                                                                                  objectName:node.pithosObject.name 
1017 b58ff732 Miltiadis Vasilakis
                                                                                                     version:version 
1018 b58ff732 Miltiadis Vasilakis
                                                                                                toDirectory:dirPath 
1019 b58ff732 Miltiadis Vasilakis
                                                                                             withNewFileName:newFileName 
1020 b58ff732 Miltiadis Vasilakis
                                                                                               checkIfExists:checkIfExists 
1021 b58ff732 Miltiadis Vasilakis
                                                                                              sharingAccount:node.sharingAccount];
1022 b58ff732 Miltiadis Vasilakis
                if (!operation.isCancelled && objectRequest) {
1023 cfc17d33 Miltiadis Vasilakis
                    objectRequest.delegate = self;
1024 cfc17d33 Miltiadis Vasilakis
                    objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1025 cfc17d33 Miltiadis Vasilakis
                    objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1026 cfc17d33 Miltiadis Vasilakis
                    NSString *messagePrefix = [NSString stringWithFormat:@"Downloading '%@'", [objectRequest.userInfo objectForKey:@"fileName"]];
1027 cfc17d33 Miltiadis Vasilakis
                    PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDownload 
1028 cfc17d33 Miltiadis Vasilakis
                                                                               message:[messagePrefix stringByAppendingString:@" (0%)"]
1029 b58ff732 Miltiadis Vasilakis
                                                                            totalBytes:node.pithosObject.bytes 
1030 cfc17d33 Miltiadis Vasilakis
                                                                          currentBytes:0];
1031 cfc17d33 Miltiadis Vasilakis
                    dispatch_async(dispatch_get_main_queue(), ^{
1032 cfc17d33 Miltiadis Vasilakis
                        [activityFacility updateActivity:activity withMessage:activity.message];  
1033 cfc17d33 Miltiadis Vasilakis
                    });
1034 cfc17d33 Miltiadis Vasilakis
                    [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
1035 cfc17d33 Miltiadis Vasilakis
                     [NSDictionary dictionaryWithObjectsAndKeys:
1036 cfc17d33 Miltiadis Vasilakis
                      activity, @"activity", 
1037 cfc17d33 Miltiadis Vasilakis
                      [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1038 cfc17d33 Miltiadis Vasilakis
                      [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1039 cfc17d33 Miltiadis Vasilakis
                      [messagePrefix stringByAppendingString:@" (100%)"], @"finishedActivityMessage", 
1040 cfc17d33 Miltiadis Vasilakis
                      [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", 
1041 cfc17d33 Miltiadis Vasilakis
                      [NSNumber numberWithUnsignedInteger:10], @"retries", 
1042 cfc17d33 Miltiadis Vasilakis
                      NSStringFromSelector(@selector(downloadObjectFinished:)), @"didFinishSelector", 
1043 cfc17d33 Miltiadis Vasilakis
                      NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1044 cfc17d33 Miltiadis Vasilakis
                      downloadNetworkQueue, @"networkQueue", 
1045 cfc17d33 Miltiadis Vasilakis
                      @"download", @"operationType", 
1046 cfc17d33 Miltiadis Vasilakis
                      nil]];
1047 cfc17d33 Miltiadis Vasilakis
                    [objectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){
1048 cfc17d33 Miltiadis Vasilakis
                        [activityFacility updateActivity:activity 
1049 cfc17d33 Miltiadis Vasilakis
                                             withMessage:[messagePrefix stringByAppendingFormat:@" (%.0f%%)", (activity.totalBytes ? (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0)) : 100)] 
1050 cfc17d33 Miltiadis Vasilakis
                                              totalBytes:activity.totalBytes 
1051 cfc17d33 Miltiadis Vasilakis
                                            currentBytes:(activity.currentBytes + size)];
1052 cfc17d33 Miltiadis Vasilakis
                    }];
1053 cfc17d33 Miltiadis Vasilakis
                    [downloadNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest]];
1054 cfc17d33 Miltiadis Vasilakis
                }
1055 cfc17d33 Miltiadis Vasilakis
            }
1056 cfc17d33 Miltiadis Vasilakis
        }];
1057 cfc17d33 Miltiadis Vasilakis
        [downloadQueue addOperation:operation];
1058 cfc17d33 Miltiadis Vasilakis
    }
1059 cfc17d33 Miltiadis Vasilakis
}
1060 cfc17d33 Miltiadis Vasilakis
1061 67e3336f Miltiadis Vasilakis
- (BOOL)uploadFiles:(NSArray *)filenames toNode:(PithosNode *)destinationNode {
1062 67e3336f Miltiadis Vasilakis
    if (([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class]))
1063 67e3336f Miltiadis Vasilakis
        return NO;
1064 0224a49f Miltiadis Vasilakis
    NSFileManager *fileManager = [NSFileManager defaultManager];
1065 67e3336f Miltiadis Vasilakis
    NSString *containerName = [NSString stringWithString:destinationNode.pithosContainer.name];
1066 67e3336f Miltiadis Vasilakis
    NSString *objectNamePrefix;
1067 67e3336f Miltiadis Vasilakis
    if ([destinationNode class] == [PithosSubdirNode class])
1068 67e3336f Miltiadis Vasilakis
        objectNamePrefix = [NSString stringWithString:destinationNode.pithosObject.name];
1069 67e3336f Miltiadis Vasilakis
    else
1070 67e3336f Miltiadis Vasilakis
        objectNamePrefix = [NSString string];
1071 67e3336f Miltiadis Vasilakis
    if ((destinationNode.pithosContainer.blockHash == nil) || (destinationNode.pithosContainer.blockSize == 0)) {
1072 fb27f368 Miltiadis Vasilakis
        ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest containerMetadataRequestWithPithos:pithosAccountManager.pithos
1073 919cb043 Miltiadis Vasilakis
                                                                                                      containerName:containerName];
1074 8aa8e10c Miltiadis Vasilakis
        [PithosUtilities startAndWaitForRequest:containerRequest];
1075 67e3336f Miltiadis Vasilakis
        if ([containerRequest error]) {
1076 1b1e6fa1 Miltiadis Vasilakis
            [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest];
1077 67e3336f Miltiadis Vasilakis
            return NO;
1078 0224a49f Miltiadis Vasilakis
        } else if (containerRequest.responseStatusCode != 204) {
1079 1b1e6fa1 Miltiadis Vasilakis
            [PithosUtilities unexpectedResponseStatusAlertWithRequest:containerRequest];
1080 67e3336f Miltiadis Vasilakis
            return NO;
1081 67e3336f Miltiadis Vasilakis
        }
1082 67e3336f Miltiadis Vasilakis
        destinationNode.pithosContainer.blockHash = [containerRequest blockHash];
1083 67e3336f Miltiadis Vasilakis
        destinationNode.pithosContainer.blockSize = [containerRequest blockSize];
1084 67e3336f Miltiadis Vasilakis
    }    
1085 67e3336f Miltiadis Vasilakis
    NSUInteger blockSize = destinationNode.pithosContainer.blockSize;
1086 67e3336f Miltiadis Vasilakis
    NSString *blockHash = destinationNode.pithosContainer.blockHash;
1087 67e3336f Miltiadis Vasilakis
    
1088 67e3336f Miltiadis Vasilakis
    for (NSString *filePath in filenames) {
1089 67e3336f Miltiadis Vasilakis
        BOOL isDirectory;
1090 0224a49f Miltiadis Vasilakis
        if ([fileManager fileExistsAtPath:filePath isDirectory:&isDirectory]) {
1091 67e3336f Miltiadis Vasilakis
            if (!isDirectory) {
1092 67e3336f Miltiadis Vasilakis
                // Upload file
1093 5f0e5132 Miltiadis Vasilakis
                NSString *objectName = [[objectNamePrefix stringByAppendingPathComponent:[filePath lastPathComponent]] 
1094 5f0e5132 Miltiadis Vasilakis
                                        precomposedStringWithCanonicalMapping];
1095 d8426ffb Miltiadis Vasilakis
                // Operation: Upload a local file
1096 d8426ffb Miltiadis Vasilakis
                __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1097 b58ff732 Miltiadis Vasilakis
                    @autoreleasepool {
1098 b58ff732 Miltiadis Vasilakis
                        if (operation.isCancelled)
1099 d8426ffb Miltiadis Vasilakis
                            return;
1100 b58ff732 Miltiadis Vasilakis
                        NSError *error = nil;
1101 b58ff732 Miltiadis Vasilakis
                        NSString *contentType = [PithosUtilities contentTypeOfFile:filePath error:&error];
1102 b58ff732 Miltiadis Vasilakis
                        if (contentType == nil)
1103 b58ff732 Miltiadis Vasilakis
                            contentType = @"application/octet-stream";
1104 b58ff732 Miltiadis Vasilakis
                        #if DEBUG_PITHOS
1105 b58ff732 Miltiadis Vasilakis
                        if (error)
1106 b58ff732 Miltiadis Vasilakis
                            DLog(@"contentType detection error: %@", error);
1107 b58ff732 Miltiadis Vasilakis
                        #endif
1108 b58ff732 Miltiadis Vasilakis
                        NSArray *hashes = nil;
1109 b58ff732 Miltiadis Vasilakis
                        if (operation.isCancelled)
1110 d8426ffb Miltiadis Vasilakis
                            return;
1111 fb27f368 Miltiadis Vasilakis
                        ASIPithosObjectRequest *objectRequest = [PithosUtilities writeObjectDataRequestWithPithos:pithosAccountManager.pithos
1112 b58ff732 Miltiadis Vasilakis
                                                                                                    containerName:containerName 
1113 b58ff732 Miltiadis Vasilakis
                                                                                                       objectName:objectName 
1114 b58ff732 Miltiadis Vasilakis
                                                                                                      contentType:contentType 
1115 b58ff732 Miltiadis Vasilakis
                                                                                                        blockSize:blockSize 
1116 b58ff732 Miltiadis Vasilakis
                                                                                                        blockHash:blockHash 
1117 b58ff732 Miltiadis Vasilakis
                                                                                                          forFile:filePath 
1118 b58ff732 Miltiadis Vasilakis
                                                                                                    checkIfExists:YES 
1119 b58ff732 Miltiadis Vasilakis
                                                                                                           hashes:&hashes 
1120 b58ff732 Miltiadis Vasilakis
                                                                                                   sharingAccount:destinationNode.sharingAccount];
1121 b58ff732 Miltiadis Vasilakis
                        if (!operation.isCancelled && objectRequest) {
1122 67e3336f Miltiadis Vasilakis
                            objectRequest.delegate = self;
1123 4c1c46fd Miltiadis Vasilakis
                            objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1124 4c1c46fd Miltiadis Vasilakis
                            objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1125 b58ff732 Miltiadis Vasilakis
                            NSString *messagePrefix = [NSString stringWithFormat:@"Uploading '%@'", [objectRequest.userInfo objectForKey:@"fileName"]];
1126 b58ff732 Miltiadis Vasilakis
                            PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityUpload 
1127 b58ff732 Miltiadis Vasilakis
                                                                                       message:[messagePrefix stringByAppendingString:@" (0%)"]
1128 b58ff732 Miltiadis Vasilakis
                                                                                    totalBytes:[[objectRequest.userInfo objectForKey:@"bytes"] unsignedIntegerValue]
1129 b58ff732 Miltiadis Vasilakis
                                                                                  currentBytes:0];
1130 212a7d57 Miltiadis Vasilakis
                            [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
1131 212a7d57 Miltiadis Vasilakis
                             [NSDictionary dictionaryWithObjectsAndKeys:
1132 b58ff732 Miltiadis Vasilakis
                              containerName, @"containerName", 
1133 b58ff732 Miltiadis Vasilakis
                              objectName, @"objectName", 
1134 b58ff732 Miltiadis Vasilakis
                              contentType, @"contentType", 
1135 b58ff732 Miltiadis Vasilakis
                              [NSNumber numberWithUnsignedInteger:blockSize], @"blockSize", 
1136 b58ff732 Miltiadis Vasilakis
                              blockHash, @"blockHash", 
1137 b58ff732 Miltiadis Vasilakis
                              filePath, @"filePath", 
1138 b58ff732 Miltiadis Vasilakis
                              hashes, @"hashes", 
1139 b58ff732 Miltiadis Vasilakis
                              [NSArray arrayWithObject:destinationNode], @"refreshNodes", 
1140 212a7d57 Miltiadis Vasilakis
                              [NSNumber numberWithBool:YES], @"refresh", 
1141 b58ff732 Miltiadis Vasilakis
                              [NSNumber numberWithUnsignedInteger:10], @"iteration", 
1142 212a7d57 Miltiadis Vasilakis
                              activity, @"activity", 
1143 4c1c46fd Miltiadis Vasilakis
                              [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1144 4c1c46fd Miltiadis Vasilakis
                              [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1145 b58ff732 Miltiadis Vasilakis
                              [messagePrefix stringByAppendingString:@" (100%)"], @"finishedActivityMessage", 
1146 4c1c46fd Miltiadis Vasilakis
                              [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", 
1147 212a7d57 Miltiadis Vasilakis
                              [NSNumber numberWithUnsignedInteger:10], @"retries", 
1148 b58ff732 Miltiadis Vasilakis
                              NSStringFromSelector(@selector(uploadObjectUsingHashMapFinished:)), @"didFinishSelector", 
1149 4c1c46fd Miltiadis Vasilakis
                              NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1150 4c1c46fd Miltiadis Vasilakis
                              uploadNetworkQueue, @"networkQueue", 
1151 9bdd7a67 Miltiadis Vasilakis
                              @"upload", @"operationType", 
1152 212a7d57 Miltiadis Vasilakis
                              nil]];
1153 b58ff732 Miltiadis Vasilakis
                            if (destinationNode.sharingAccount)
1154 b58ff732 Miltiadis Vasilakis
                                [(NSMutableDictionary *)objectRequest.userInfo setObject:destinationNode.sharingAccount forKey:@"sharingAccount"];
1155 4c1c46fd Miltiadis Vasilakis
                            [uploadNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest]];
1156 67e3336f Miltiadis Vasilakis
                        }
1157 b58ff732 Miltiadis Vasilakis
                    }
1158 b58ff732 Miltiadis Vasilakis
                }];
1159 b58ff732 Miltiadis Vasilakis
                [uploadQueue addOperation:operation];
1160 b58ff732 Miltiadis Vasilakis
            } else {
1161 b58ff732 Miltiadis Vasilakis
                // Upload directory, confirm first
1162 cb6abe72 Miltiadis Vasilakis
                NSAlert *alert = [[NSAlert alloc] init];
1163 b58ff732 Miltiadis Vasilakis
                [alert setMessageText:@"Upload directory"];
1164 b58ff732 Miltiadis Vasilakis
                [alert setInformativeText:[NSString stringWithFormat:@"'%@' is a directory, do you want to upload it and its contents?", filePath]];
1165 b58ff732 Miltiadis Vasilakis
                [alert addButtonWithTitle:@"OK"];
1166 b58ff732 Miltiadis Vasilakis
                [alert addButtonWithTitle:@"Cancel"];
1167 b58ff732 Miltiadis Vasilakis
                NSInteger choice = [alert runModal];
1168 b58ff732 Miltiadis Vasilakis
                if (choice == NSAlertFirstButtonReturn) {
1169 b58ff732 Miltiadis Vasilakis
                    NSString *objectName = [[objectNamePrefix stringByAppendingPathComponent:[filePath lastPathComponent]] 
1170 b58ff732 Miltiadis Vasilakis
                                            precomposedStringWithCanonicalMapping];
1171 b58ff732 Miltiadis Vasilakis
                    // Operation: Upload a local directory and its descendants
1172 b58ff732 Miltiadis Vasilakis
                    // The resulting ASIPithosObjectRequests are chained through dependencies
1173 b58ff732 Miltiadis Vasilakis
                    __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1174 b58ff732 Miltiadis Vasilakis
                        @autoreleasepool {
1175 b58ff732 Miltiadis Vasilakis
                            if (operation.isCancelled)
1176 b58ff732 Miltiadis Vasilakis
                                return;
1177 b58ff732 Miltiadis Vasilakis
                            NSMutableArray *objectNames = nil;
1178 b58ff732 Miltiadis Vasilakis
                            NSMutableArray *contentTypes = nil;
1179 b58ff732 Miltiadis Vasilakis
                            NSMutableArray *filePaths = nil;
1180 b58ff732 Miltiadis Vasilakis
                            NSMutableArray *hashesArrays = nil;
1181 b58ff732 Miltiadis Vasilakis
                            NSMutableArray *directoryObjectRequests = nil;
1182 fb27f368 Miltiadis Vasilakis
                            NSArray *objectRequests = [PithosUtilities writeObjectDataRequestsWithPithos:pithosAccountManager.pithos
1183 b58ff732 Miltiadis Vasilakis
                                                                                           containerName:containerName 
1184 b58ff732 Miltiadis Vasilakis
                                                                                              objectName:objectName 
1185 b58ff732 Miltiadis Vasilakis
                                                                                               blockSize:blockSize 
1186 b58ff732 Miltiadis Vasilakis
                                                                                               blockHash:blockHash 
1187 b58ff732 Miltiadis Vasilakis
                                                                                            forDirectory:filePath 
1188 b58ff732 Miltiadis Vasilakis
                                                                                           checkIfExists:YES 
1189 b58ff732 Miltiadis Vasilakis
                                                                                             objectNames:&objectNames
1190 b58ff732 Miltiadis Vasilakis
                                                                                            contentTypes:&contentTypes
1191 b58ff732 Miltiadis Vasilakis
                                                                                               filePaths:&filePaths
1192 b58ff732 Miltiadis Vasilakis
                                                                                            hashesArrays:&hashesArrays 
1193 b58ff732 Miltiadis Vasilakis
                                                                                 directoryObjectRequests:&directoryObjectRequests 
1194 b58ff732 Miltiadis Vasilakis
                                                                                          sharingAccount:destinationNode.sharingAccount];
1195 b58ff732 Miltiadis Vasilakis
                            if (operation.isCancelled)
1196 b58ff732 Miltiadis Vasilakis
                                return;
1197 b58ff732 Miltiadis Vasilakis
                            ASIPithosObjectRequest *previousObjectRequest = nil;
1198 b58ff732 Miltiadis Vasilakis
                            for (ASIPithosObjectRequest *objectRequest in directoryObjectRequests) {
1199 b58ff732 Miltiadis Vasilakis
                                if (operation.isCancelled)
1200 d8426ffb Miltiadis Vasilakis
                                    return;
1201 d41b3577 Miltiadis Vasilakis
                                objectRequest.delegate = self;
1202 4c1c46fd Miltiadis Vasilakis
                                objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1203 4c1c46fd Miltiadis Vasilakis
                                objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1204 b58ff732 Miltiadis Vasilakis
                                NSString *messagePrefix = [NSString stringWithFormat:@"Creating directory '%@'", [objectRequest.userInfo objectForKey:@"fileName"]];
1205 b58ff732 Miltiadis Vasilakis
                                PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCreateDirectory 
1206 b58ff732 Miltiadis Vasilakis
                                                                                           message:messagePrefix];
1207 470e6f81 Miltiadis Vasilakis
                                [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
1208 470e6f81 Miltiadis Vasilakis
                                 [NSDictionary dictionaryWithObjectsAndKeys:
1209 1b1e6fa1 Miltiadis Vasilakis
                                  [NSNumber numberWithBool:YES], @"refresh", 
1210 470e6f81 Miltiadis Vasilakis
                                  activity, @"activity", 
1211 4c1c46fd Miltiadis Vasilakis
                                  [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1212 4c1c46fd Miltiadis Vasilakis
                                  [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1213 b58ff732 Miltiadis Vasilakis
                                  [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
1214 4c1c46fd Miltiadis Vasilakis
                                  [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", 
1215 1b1e6fa1 Miltiadis Vasilakis
                                  [NSNumber numberWithUnsignedInteger:10], @"retries", 
1216 b58ff732 Miltiadis Vasilakis
                                  NSStringFromSelector(@selector(uploadDirectoryObjectFinished:)), @"didFinishSelector", 
1217 4c1c46fd Miltiadis Vasilakis
                                  NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1218 4c1c46fd Miltiadis Vasilakis
                                  uploadNetworkQueue, @"networkQueue", 
1219 9bdd7a67 Miltiadis Vasilakis
                                  @"upload", @"operationType", 
1220 470e6f81 Miltiadis Vasilakis
                                  nil]];
1221 d8426ffb Miltiadis Vasilakis
                                if (previousObjectRequest)
1222 d8426ffb Miltiadis Vasilakis
                                    [objectRequest addDependency:previousObjectRequest];
1223 d8426ffb Miltiadis Vasilakis
                                previousObjectRequest = objectRequest;
1224 4c1c46fd Miltiadis Vasilakis
                                [uploadNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest]];
1225 d41b3577 Miltiadis Vasilakis
                            }
1226 b58ff732 Miltiadis Vasilakis
                            if (!operation.isCancelled && objectRequests) {
1227 b58ff732 Miltiadis Vasilakis
                                for (NSUInteger i = 0 ; i < [objectRequests count] ; i++) {
1228 b58ff732 Miltiadis Vasilakis
                                    if (operation.isCancelled)
1229 b58ff732 Miltiadis Vasilakis
                                        return;
1230 b58ff732 Miltiadis Vasilakis
                                    ASIPithosObjectRequest *objectRequest = [objectRequests objectAtIndex:i];
1231 b58ff732 Miltiadis Vasilakis
                                    objectRequest.delegate = self;
1232 b58ff732 Miltiadis Vasilakis
                                    objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1233 b58ff732 Miltiadis Vasilakis
                                    objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1234 b58ff732 Miltiadis Vasilakis
                                    NSString *messagePrefix = [NSString stringWithFormat:@"Uploading '%@'", [objectRequest.userInfo objectForKey:@"fileName"]];
1235 b58ff732 Miltiadis Vasilakis
                                    PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityUpload 
1236 b58ff732 Miltiadis Vasilakis
                                                                                               message:[messagePrefix stringByAppendingString:@" (0%)"]
1237 b58ff732 Miltiadis Vasilakis
                                                                                            totalBytes:[[objectRequest.userInfo objectForKey:@"bytes"] unsignedIntegerValue]
1238 b58ff732 Miltiadis Vasilakis
                                                                                          currentBytes:0];
1239 b58ff732 Miltiadis Vasilakis
                                    [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
1240 b58ff732 Miltiadis Vasilakis
                                     [NSDictionary dictionaryWithObjectsAndKeys:
1241 b58ff732 Miltiadis Vasilakis
                                      containerName, @"containerName", 
1242 b58ff732 Miltiadis Vasilakis
                                      [objectNames objectAtIndex:i], @"objectName", 
1243 b58ff732 Miltiadis Vasilakis
                                      [contentTypes objectAtIndex:i], @"contentType", 
1244 b58ff732 Miltiadis Vasilakis
                                      [NSNumber numberWithUnsignedInteger:blockSize], @"blockSize", 
1245 b58ff732 Miltiadis Vasilakis
                                      blockHash, @"blockHash", 
1246 b58ff732 Miltiadis Vasilakis
                                      [filePaths objectAtIndex:i], @"filePath", 
1247 b58ff732 Miltiadis Vasilakis
                                      [hashesArrays objectAtIndex:i], @"hashes", 
1248 b58ff732 Miltiadis Vasilakis
                                      [NSNumber numberWithBool:YES], @"refresh", 
1249 b58ff732 Miltiadis Vasilakis
                                      [NSNumber numberWithUnsignedInteger:10], @"iteration", 
1250 b58ff732 Miltiadis Vasilakis
                                      activity, @"activity", 
1251 b58ff732 Miltiadis Vasilakis
                                      [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1252 b58ff732 Miltiadis Vasilakis
                                      [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1253 b58ff732 Miltiadis Vasilakis
                                      [messagePrefix stringByAppendingString:@" (100%)"], @"finishedActivityMessage", 
1254 b58ff732 Miltiadis Vasilakis
                                      [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", 
1255 b58ff732 Miltiadis Vasilakis
                                      [NSNumber numberWithUnsignedInteger:10], @"retries", 
1256 b58ff732 Miltiadis Vasilakis
                                      NSStringFromSelector(@selector(uploadObjectUsingHashMapFinished:)), @"didFinishSelector", 
1257 b58ff732 Miltiadis Vasilakis
                                      NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1258 b58ff732 Miltiadis Vasilakis
                                      uploadNetworkQueue, @"networkQueue", 
1259 b58ff732 Miltiadis Vasilakis
                                      @"upload", @"operationType", 
1260 b58ff732 Miltiadis Vasilakis
                                      nil]];
1261 b58ff732 Miltiadis Vasilakis
                                    if (destinationNode.sharingAccount)
1262 b58ff732 Miltiadis Vasilakis
                                        [(NSMutableDictionary *)objectRequest.userInfo setObject:destinationNode.sharingAccount forKey:@"sharingAccount"];
1263 b58ff732 Miltiadis Vasilakis
                                    if (previousObjectRequest)
1264 b58ff732 Miltiadis Vasilakis
                                        [objectRequest addDependency:previousObjectRequest];
1265 b58ff732 Miltiadis Vasilakis
                                    previousObjectRequest = objectRequest;
1266 b58ff732 Miltiadis Vasilakis
                                    [uploadNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest]];
1267 b58ff732 Miltiadis Vasilakis
                                }
1268 b58ff732 Miltiadis Vasilakis
                            }
1269 b58ff732 Miltiadis Vasilakis
                        }
1270 b58ff732 Miltiadis Vasilakis
                    }];
1271 b58ff732 Miltiadis Vasilakis
                    [uploadQueue addOperation:operation];
1272 b58ff732 Miltiadis Vasilakis
                }
1273 b58ff732 Miltiadis Vasilakis
            }
1274 d41b3577 Miltiadis Vasilakis
        }
1275 67e3336f Miltiadis Vasilakis
    }
1276 67e3336f Miltiadis Vasilakis
    return YES;
1277 67e3336f Miltiadis Vasilakis
}
1278 67e3336f Miltiadis Vasilakis
1279 67e3336f Miltiadis Vasilakis
- (BOOL)moveNodes:(NSArray *)nodes toNode:(PithosNode *)destinationNode {
1280 1b1e6fa1 Miltiadis Vasilakis
    if ((([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class])) ||
1281 1b1e6fa1 Miltiadis Vasilakis
        (([destinationNode class] == [PithosSubdirNode class]) && !destinationNode.pithosObject.subdir && [destinationNode.pithosObject.name hasSuffix:@"/"])) 
1282 67e3336f Miltiadis Vasilakis
        return NO;
1283 67e3336f Miltiadis Vasilakis
    NSString *containerName = [NSString stringWithString:destinationNode.pithosContainer.name];
1284 67e3336f Miltiadis Vasilakis
    NSString *objectNamePrefix;
1285 67e3336f Miltiadis Vasilakis
    if ([destinationNode class] == [PithosSubdirNode class])
1286 67e3336f Miltiadis Vasilakis
        objectNamePrefix = [NSString stringWithString:destinationNode.pithosObject.name];
1287 67e3336f Miltiadis Vasilakis
    else
1288 67e3336f Miltiadis Vasilakis
        objectNamePrefix = [NSString string];
1289 67e3336f Miltiadis Vasilakis
1290 67e3336f Miltiadis Vasilakis
    for (PithosNode *node in nodes) {
1291 67e3336f Miltiadis Vasilakis
        if (([node class] == [PithosObjectNode class]) || 
1292 1b1e6fa1 Miltiadis Vasilakis
            (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) {
1293 d8426ffb Miltiadis Vasilakis
            // Operation: Move an object or subdir/ node
1294 d8426ffb Miltiadis Vasilakis
            __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1295 b58ff732 Miltiadis Vasilakis
                @autoreleasepool {
1296 b58ff732 Miltiadis Vasilakis
                    if (operation.isCancelled)
1297 b58ff732 Miltiadis Vasilakis
                        return;
1298 b58ff732 Miltiadis Vasilakis
                    NSString *destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
1299 b58ff732 Miltiadis Vasilakis
                    if ([node.pithosObject.name hasSuffix:@"/"])
1300 b58ff732 Miltiadis Vasilakis
                        destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
1301 fb27f368 Miltiadis Vasilakis
                    ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithPithos:pithosAccountManager.pithos
1302 b58ff732 Miltiadis Vasilakis
                                                                                           containerName:node.pithosContainer.name 
1303 b58ff732 Miltiadis Vasilakis
                                                                                              objectName:node.pithosObject.name 
1304 b58ff732 Miltiadis Vasilakis
                                                                                destinationContainerName:containerName 
1305 b58ff732 Miltiadis Vasilakis
                                                                                   destinationObjectName:destinationObjectName 
1306 b58ff732 Miltiadis Vasilakis
                                                                                           checkIfExists:YES];
1307 b58ff732 Miltiadis Vasilakis
                    if (!operation.isCancelled && objectRequest) {
1308 67e3336f Miltiadis Vasilakis
                        objectRequest.delegate = self;
1309 4c1c46fd Miltiadis Vasilakis
                        objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1310 4c1c46fd Miltiadis Vasilakis
                        objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1311 4c1c46fd Miltiadis Vasilakis
                        NSString *messagePrefix = [NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", 
1312 4c1c46fd Miltiadis Vasilakis
                                                   [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
1313 4c1c46fd Miltiadis Vasilakis
                                                   [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
1314 4c1c46fd Miltiadis Vasilakis
                                                   [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
1315 4c1c46fd Miltiadis Vasilakis
                                                   [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
1316 1b1e6fa1 Miltiadis Vasilakis
                        PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove 
1317 4c1c46fd Miltiadis Vasilakis
                                                                                   message:messagePrefix];
1318 1b1e6fa1 Miltiadis Vasilakis
                        [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
1319 1b1e6fa1 Miltiadis Vasilakis
                         [NSDictionary dictionaryWithObjectsAndKeys:
1320 1b1e6fa1 Miltiadis Vasilakis
                          [NSArray arrayWithObjects:node.parent, destinationNode, nil], @"forceRefreshNodes", 
1321 1b1e6fa1 Miltiadis Vasilakis
                          activity, @"activity", 
1322 4c1c46fd Miltiadis Vasilakis
                          [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1323 4c1c46fd Miltiadis Vasilakis
                          [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1324 4c1c46fd Miltiadis Vasilakis
                          [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
1325 4c1c46fd Miltiadis Vasilakis
                          [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
1326 1b1e6fa1 Miltiadis Vasilakis
                          [NSNumber numberWithUnsignedInteger:10], @"retries", 
1327 4c1c46fd Miltiadis Vasilakis
                          NSStringFromSelector(@selector(moveFinished:)), @"didFinishSelector", 
1328 4c1c46fd Miltiadis Vasilakis
                          NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1329 4c1c46fd Miltiadis Vasilakis
                          moveNetworkQueue, @"networkQueue", 
1330 d8426ffb Miltiadis Vasilakis
                          @"move", @"operationType", 
1331 1b1e6fa1 Miltiadis Vasilakis
                          nil]];
1332 4c1c46fd Miltiadis Vasilakis
                        [moveNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
1333 d41b3577 Miltiadis Vasilakis
                    }
1334 d41b3577 Miltiadis Vasilakis
                }
1335 b58ff732 Miltiadis Vasilakis
            }];
1336 b58ff732 Miltiadis Vasilakis
            [moveQueue addOperation:operation];
1337 b58ff732 Miltiadis Vasilakis
        } else if ([node class] == [PithosSubdirNode class]) {
1338 b58ff732 Miltiadis Vasilakis
            // Operation: Move a subdir node and its descendants
1339 b58ff732 Miltiadis Vasilakis
            // The resulting ASIPithosObjectRequests are chained through dependencies
1340 b58ff732 Miltiadis Vasilakis
            __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1341 b58ff732 Miltiadis Vasilakis
                @autoreleasepool {
1342 b58ff732 Miltiadis Vasilakis
                    if (operation.isCancelled)
1343 b58ff732 Miltiadis Vasilakis
                        return;
1344 b58ff732 Miltiadis Vasilakis
                    NSString *destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
1345 b58ff732 Miltiadis Vasilakis
                    if (node.pithosObject.subdir)
1346 b58ff732 Miltiadis Vasilakis
                        destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
1347 fb27f368 Miltiadis Vasilakis
                    NSArray *objectRequests = [PithosUtilities moveObjectRequestsForSubdirWithPithos:pithosAccountManager.pithos
1348 b58ff732 Miltiadis Vasilakis
                                                                                       containerName:node.pithosContainer.name 
1349 b58ff732 Miltiadis Vasilakis
                                                                                          objectName:node.pithosObject.name 
1350 b58ff732 Miltiadis Vasilakis
                                                                            destinationContainerName:containerName 
1351 b58ff732 Miltiadis Vasilakis
                                                                               destinationObjectName:destinationObjectName 
1352 b58ff732 Miltiadis Vasilakis
                                                                                       checkIfExists:YES];
1353 b58ff732 Miltiadis Vasilakis
                    if (!operation.isCancelled && objectRequests) {
1354 b58ff732 Miltiadis Vasilakis
                        ASIPithosObjectRequest *previousObjectRequest = nil;
1355 b58ff732 Miltiadis Vasilakis
                        for (ASIPithosObjectRequest *objectRequest in objectRequests) {
1356 b58ff732 Miltiadis Vasilakis
                            if (operation.isCancelled)
1357 b58ff732 Miltiadis Vasilakis
                                return;
1358 b58ff732 Miltiadis Vasilakis
                            objectRequest.delegate = self;
1359 b58ff732 Miltiadis Vasilakis
                            objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1360 b58ff732 Miltiadis Vasilakis
                            objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1361 b58ff732 Miltiadis Vasilakis
                            NSString *messagePrefix = [NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", 
1362 b58ff732 Miltiadis Vasilakis
                                                       [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
1363 b58ff732 Miltiadis Vasilakis
                                                       [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
1364 b58ff732 Miltiadis Vasilakis
                                                       [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
1365 b58ff732 Miltiadis Vasilakis
                                                       [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
1366 b58ff732 Miltiadis Vasilakis
                            PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove 
1367 b58ff732 Miltiadis Vasilakis
                                                                                       message:messagePrefix];
1368 b58ff732 Miltiadis Vasilakis
                            [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
1369 b58ff732 Miltiadis Vasilakis
                             [NSDictionary dictionaryWithObjectsAndKeys:
1370 b58ff732 Miltiadis Vasilakis
                              [NSArray arrayWithObjects:node.parent, destinationNode, nil], @"forceRefreshNodes", 
1371 b58ff732 Miltiadis Vasilakis
                              [NSNumber numberWithBool:YES], @"refresh", 
1372 b58ff732 Miltiadis Vasilakis
                              activity, @"activity", 
1373 b58ff732 Miltiadis Vasilakis
                              [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1374 b58ff732 Miltiadis Vasilakis
                              [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1375 b58ff732 Miltiadis Vasilakis
                              [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
1376 b58ff732 Miltiadis Vasilakis
                              [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
1377 b58ff732 Miltiadis Vasilakis
                              [NSNumber numberWithUnsignedInteger:10], @"retries", 
1378 b58ff732 Miltiadis Vasilakis
                              NSStringFromSelector(@selector(moveFinished:)), @"didFinishSelector", 
1379 b58ff732 Miltiadis Vasilakis
                              NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1380 b58ff732 Miltiadis Vasilakis
                              moveNetworkQueue, @"networkQueue", 
1381 b58ff732 Miltiadis Vasilakis
                              @"move", @"operationType", 
1382 b58ff732 Miltiadis Vasilakis
                              nil]];
1383 b58ff732 Miltiadis Vasilakis
                            if (previousObjectRequest)
1384 b58ff732 Miltiadis Vasilakis
                                [objectRequest addDependency:previousObjectRequest];
1385 b58ff732 Miltiadis Vasilakis
                            previousObjectRequest = objectRequest;
1386 b58ff732 Miltiadis Vasilakis
                            [moveNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
1387 b58ff732 Miltiadis Vasilakis
                        }
1388 b58ff732 Miltiadis Vasilakis
                    }
1389 b58ff732 Miltiadis Vasilakis
                }
1390 d8426ffb Miltiadis Vasilakis
            }];
1391 d8426ffb Miltiadis Vasilakis
            [moveQueue addOperation:operation];
1392 67e3336f Miltiadis Vasilakis
        }
1393 67e3336f Miltiadis Vasilakis
    }
1394 67e3336f Miltiadis Vasilakis
    return YES;
1395 67e3336f Miltiadis Vasilakis
}
1396 d41b3577 Miltiadis Vasilakis
1397 3f220848 Miltiadis Vasilakis
- (BOOL)cpyNodes:(NSArray *)nodes toNode:(PithosNode *)destinationNode {    
1398 1b1e6fa1 Miltiadis Vasilakis
    if ((([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class])) ||
1399 1b1e6fa1 Miltiadis Vasilakis
        (([destinationNode class] == [PithosSubdirNode class]) && !destinationNode.pithosObject.subdir && [destinationNode.pithosObject.name hasSuffix:@"/"])) 
1400 67e3336f Miltiadis Vasilakis
        return NO;
1401 67e3336f Miltiadis Vasilakis
    NSString *containerName = [NSString stringWithString:destinationNode.pithosContainer.name];
1402 67e3336f Miltiadis Vasilakis
    NSString *objectNamePrefix;
1403 67e3336f Miltiadis Vasilakis
    if ([destinationNode class] == [PithosSubdirNode class])
1404 67e3336f Miltiadis Vasilakis
        objectNamePrefix = [NSString stringWithString:destinationNode.pithosObject.name];
1405 67e3336f Miltiadis Vasilakis
    else
1406 67e3336f Miltiadis Vasilakis
        objectNamePrefix = [NSString string];
1407 67e3336f Miltiadis Vasilakis
    
1408 67e3336f Miltiadis Vasilakis
    for (PithosNode *node in nodes) {
1409 67e3336f Miltiadis Vasilakis
        if (([node class] == [PithosObjectNode class]) || 
1410 1b1e6fa1 Miltiadis Vasilakis
            (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) {
1411 d8426ffb Miltiadis Vasilakis
            // Operation: Copy an object or subdir/ node
1412 d8426ffb Miltiadis Vasilakis
            __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1413 b58ff732 Miltiadis Vasilakis
                @autoreleasepool {
1414 b58ff732 Miltiadis Vasilakis
                    if (operation.isCancelled)
1415 b58ff732 Miltiadis Vasilakis
                        return;
1416 b58ff732 Miltiadis Vasilakis
                    NSString *destinationObjectName;
1417 b58ff732 Miltiadis Vasilakis
                    if (![destinationNode isEqualTo:node.parent]) {
1418 b58ff732 Miltiadis Vasilakis
                        destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
1419 b58ff732 Miltiadis Vasilakis
                        if ([node.pithosObject.name hasSuffix:@"/"])
1420 b58ff732 Miltiadis Vasilakis
                            destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
1421 b58ff732 Miltiadis Vasilakis
                    } else {
1422 fb27f368 Miltiadis Vasilakis
                        destinationObjectName = [PithosUtilities safeObjectNameForPithos:pithosAccountManager.pithos
1423 b58ff732 Miltiadis Vasilakis
                                                                           containerName:containerName 
1424 b58ff732 Miltiadis Vasilakis
                                                                              objectName:node.pithosObject.name];
1425 b58ff732 Miltiadis Vasilakis
                    }
1426 b58ff732 Miltiadis Vasilakis
                    if (operation.isCancelled)
1427 b58ff732 Miltiadis Vasilakis
                        return;
1428 fb27f368 Miltiadis Vasilakis
                    ASIPithosObjectRequest *objectRequest = [PithosUtilities cpyObjectRequestWithPithos:pithosAccountManager.pithos
1429 b58ff732 Miltiadis Vasilakis
                                                                                           containerName:node.pithosContainer.name 
1430 b58ff732 Miltiadis Vasilakis
                                                                                              objectName:node.pithosObject.name 
1431 b58ff732 Miltiadis Vasilakis
                                                                                destinationContainerName:containerName 
1432 b58ff732 Miltiadis Vasilakis
                                                                                   destinationObjectName:destinationObjectName 
1433 b58ff732 Miltiadis Vasilakis
                                                                                           checkIfExists:YES 
1434 b58ff732 Miltiadis Vasilakis
                                                                                          sharingAccount:node.sharingAccount];
1435 b58ff732 Miltiadis Vasilakis
                    if (!operation.isCancelled && objectRequest) {
1436 67e3336f Miltiadis Vasilakis
                        objectRequest.delegate = self;
1437 4c1c46fd Miltiadis Vasilakis
                        objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1438 4c1c46fd Miltiadis Vasilakis
                        objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1439 4c1c46fd Miltiadis Vasilakis
                        NSString *messagePrefix = [NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@'", 
1440 4c1c46fd Miltiadis Vasilakis
                                                   [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
1441 4c1c46fd Miltiadis Vasilakis
                                                   [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
1442 4c1c46fd Miltiadis Vasilakis
                                                   [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
1443 4c1c46fd Miltiadis Vasilakis
                                                   [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
1444 1b1e6fa1 Miltiadis Vasilakis
                        PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCopy 
1445 4c1c46fd Miltiadis Vasilakis
                                                                                   message:messagePrefix];
1446 1b1e6fa1 Miltiadis Vasilakis
                        [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
1447 1b1e6fa1 Miltiadis Vasilakis
                         [NSDictionary dictionaryWithObjectsAndKeys:
1448 1b1e6fa1 Miltiadis Vasilakis
                          [NSArray arrayWithObject:destinationNode], @"forceRefreshNodes", 
1449 1b1e6fa1 Miltiadis Vasilakis
                          activity, @"activity", 
1450 4c1c46fd Miltiadis Vasilakis
                          [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1451 4c1c46fd Miltiadis Vasilakis
                          [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1452 4c1c46fd Miltiadis Vasilakis
                          [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
1453 4c1c46fd Miltiadis Vasilakis
                          [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
1454 1b1e6fa1 Miltiadis Vasilakis
                          [NSNumber numberWithUnsignedInteger:10], @"retries", 
1455 4c1c46fd Miltiadis Vasilakis
                          NSStringFromSelector(@selector(copyFinished:)), @"didFinishSelector", 
1456 4c1c46fd Miltiadis Vasilakis
                          NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1457 4c1c46fd Miltiadis Vasilakis
                          copyNetworkQueue, @"networkQueue", 
1458 d8426ffb Miltiadis Vasilakis
                          @"copy", @"operationType", 
1459 1b1e6fa1 Miltiadis Vasilakis
                          nil]];
1460 4c1c46fd Miltiadis Vasilakis
                        [copyNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
1461 33bf3856 Miltiadis Vasilakis
                    }
1462 f2f50f78 Miltiadis Vasilakis
                }
1463 b58ff732 Miltiadis Vasilakis
            }];
1464 b58ff732 Miltiadis Vasilakis
            [copyQueue addOperation:operation];
1465 b58ff732 Miltiadis Vasilakis
        } else if ([node class] == [PithosSubdirNode class]) {
1466 b58ff732 Miltiadis Vasilakis
            // Operation: Copy a subdir node and its descendants
1467 b58ff732 Miltiadis Vasilakis
            // The resulting ASIPithosObjectRequests are chained through dependencies
1468 b58ff732 Miltiadis Vasilakis
            __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1469 b58ff732 Miltiadis Vasilakis
                @autoreleasepool {
1470 b58ff732 Miltiadis Vasilakis
                    if (operation.isCancelled)
1471 b58ff732 Miltiadis Vasilakis
                        return;
1472 b58ff732 Miltiadis Vasilakis
                    NSString *destinationObjectName;
1473 b58ff732 Miltiadis Vasilakis
                    if (![destinationNode isEqualTo:node.parent]) {
1474 b58ff732 Miltiadis Vasilakis
                        destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
1475 b58ff732 Miltiadis Vasilakis
                        if (node.pithosObject.subdir)
1476 b58ff732 Miltiadis Vasilakis
                            destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
1477 b58ff732 Miltiadis Vasilakis
                    } else {
1478 fb27f368 Miltiadis Vasilakis
                        destinationObjectName = [PithosUtilities safeSubdirNameForPithos:pithosAccountManager.pithos 
1479 b58ff732 Miltiadis Vasilakis
                                                                           containerName:containerName 
1480 b58ff732 Miltiadis Vasilakis
                                                                              subdirName:node.pithosObject.name];
1481 b58ff732 Miltiadis Vasilakis
                    }
1482 b58ff732 Miltiadis Vasilakis
                    if (operation.isCancelled)
1483 b58ff732 Miltiadis Vasilakis
                        return;
1484 fb27f368 Miltiadis Vasilakis
                    NSArray *objectRequests = [PithosUtilities cpyObjectRequestsForSubdirWithPithos:pithosAccountManager.pithos
1485 b58ff732 Miltiadis Vasilakis
                                                                                       containerName:node.pithosContainer.name 
1486 b58ff732 Miltiadis Vasilakis
                                                                                          objectName:node.pithosObject.name 
1487 b58ff732 Miltiadis Vasilakis
                                                                            destinationContainerName:containerName 
1488 b58ff732 Miltiadis Vasilakis
                                                                               destinationObjectName:destinationObjectName 
1489 b58ff732 Miltiadis Vasilakis
                                                                                       checkIfExists:YES 
1490 b58ff732 Miltiadis Vasilakis
                                                                                      sharingAccount:node.sharingAccount];
1491 b58ff732 Miltiadis Vasilakis
                    if (!operation.isCancelled && objectRequests) {
1492 b58ff732 Miltiadis Vasilakis
                        ASIPithosObjectRequest *previousObjectRequest = nil;
1493 b58ff732 Miltiadis Vasilakis
                        for (ASIPithosObjectRequest *objectRequest in objectRequests) {
1494 b58ff732 Miltiadis Vasilakis
                            if (operation.isCancelled)
1495 b58ff732 Miltiadis Vasilakis
                                return;
1496 b58ff732 Miltiadis Vasilakis
                            objectRequest.delegate = self;
1497 b58ff732 Miltiadis Vasilakis
                            objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1498 b58ff732 Miltiadis Vasilakis
                            objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1499 b58ff732 Miltiadis Vasilakis
                            NSString *messagePrefix = [NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@'", 
1500 b58ff732 Miltiadis Vasilakis
                                                       [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
1501 b58ff732 Miltiadis Vasilakis
                                                       [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
1502 b58ff732 Miltiadis Vasilakis
                                                       [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
1503 b58ff732 Miltiadis Vasilakis
                                                       [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
1504 b58ff732 Miltiadis Vasilakis
                            PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCopy 
1505 b58ff732 Miltiadis Vasilakis
                                                                                       message:messagePrefix];
1506 b58ff732 Miltiadis Vasilakis
                            [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
1507 b58ff732 Miltiadis Vasilakis
                             [NSDictionary dictionaryWithObjectsAndKeys:
1508 b58ff732 Miltiadis Vasilakis
                              [NSArray arrayWithObject:destinationNode], @"forceRefreshNodes", 
1509 b58ff732 Miltiadis Vasilakis
                              activity, @"activity", 
1510 b58ff732 Miltiadis Vasilakis
                              [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1511 b58ff732 Miltiadis Vasilakis
                              [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1512 b58ff732 Miltiadis Vasilakis
                              [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
1513 b58ff732 Miltiadis Vasilakis
                              [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
1514 b58ff732 Miltiadis Vasilakis
                              [NSNumber numberWithUnsignedInteger:10], @"retries", 
1515 b58ff732 Miltiadis Vasilakis
                              NSStringFromSelector(@selector(copyFinished:)), @"didFinishSelector", 
1516 b58ff732 Miltiadis Vasilakis
                              NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1517 b58ff732 Miltiadis Vasilakis
                              copyNetworkQueue, @"networkQueue", 
1518 b58ff732 Miltiadis Vasilakis
                              @"copy", @"operationType", 
1519 b58ff732 Miltiadis Vasilakis
                              nil]];
1520 b58ff732 Miltiadis Vasilakis
                            if (previousObjectRequest)
1521 b58ff732 Miltiadis Vasilakis
                                [objectRequest addDependency:previousObjectRequest];
1522 b58ff732 Miltiadis Vasilakis
                            previousObjectRequest = objectRequest;
1523 b58ff732 Miltiadis Vasilakis
                            [copyNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
1524 b58ff732 Miltiadis Vasilakis
                        }
1525 b58ff732 Miltiadis Vasilakis
                    }
1526 b58ff732 Miltiadis Vasilakis
                }
1527 d8426ffb Miltiadis Vasilakis
            }];
1528 d8426ffb Miltiadis Vasilakis
            [copyQueue addOperation:operation];
1529 f2f50f78 Miltiadis Vasilakis
        }
1530 f2f50f78 Miltiadis Vasilakis
    }
1531 67e3336f Miltiadis Vasilakis
    return YES;
1532 f2f50f78 Miltiadis Vasilakis
}
1533 f2f50f78 Miltiadis Vasilakis
1534 f2f50f78 Miltiadis Vasilakis
#pragma mark -
1535 f2f50f78 Miltiadis Vasilakis
#pragma mark ASIHTTPRequestDelegate
1536 f2f50f78 Miltiadis Vasilakis
1537 4c1c46fd Miltiadis Vasilakis
- (void)performRequestFinishedDelegateInBackground:(ASIPithosRequest *)request {
1538 d8426ffb Miltiadis Vasilakis
    NSOperationQueue *callbackQueue;
1539 d8426ffb Miltiadis Vasilakis
    NSString *operationType = [request.userInfo objectForKey:@"operationType"];
1540 d8426ffb Miltiadis Vasilakis
    if ([operationType isEqualToString:@"move"])
1541 d8426ffb Miltiadis Vasilakis
        callbackQueue = moveCallbackQueue;
1542 d8426ffb Miltiadis Vasilakis
    else if ([operationType isEqualToString:@"copy"])
1543 d8426ffb Miltiadis Vasilakis
        callbackQueue = copyCallbackQueue;
1544 d8426ffb Miltiadis Vasilakis
    else if ([operationType isEqualToString:@"delete"])
1545 d8426ffb Miltiadis Vasilakis
        callbackQueue = deleteCallbackQueue;
1546 d8426ffb Miltiadis Vasilakis
    else if ([operationType isEqualToString:@"upload"])
1547 d8426ffb Miltiadis Vasilakis
        callbackQueue = uploadCallbackQueue;
1548 d8426ffb Miltiadis Vasilakis
    else if ([operationType isEqualToString:@"download"])
1549 d8426ffb Miltiadis Vasilakis
        callbackQueue = downloadCallbackQueue;
1550 363c618c Miltiadis Vasilakis
    else {
1551 d8426ffb Miltiadis Vasilakis
        dispatch_async(dispatch_get_main_queue(), ^{
1552 d8426ffb Miltiadis Vasilakis
            [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] 
1553 d8426ffb Miltiadis Vasilakis
                              withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
1554 d8426ffb Miltiadis Vasilakis
        });
1555 363c618c Miltiadis Vasilakis
        return;
1556 363c618c Miltiadis Vasilakis
    }
1557 d8426ffb Miltiadis Vasilakis
    // Add an operation to the callbackQueue with a completionBlock for the case of cancellation
1558 cb6abe72 Miltiadis Vasilakis
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self 
1559 d8426ffb Miltiadis Vasilakis
                                                                             selector:NSSelectorFromString([request.userInfo objectForKey:@"didFinishSelector"]) 
1560 cb6abe72 Miltiadis Vasilakis
                                                                               object:request];
1561 d8426ffb Miltiadis Vasilakis
    operation.completionBlock = ^{
1562 b58ff732 Miltiadis Vasilakis
        @autoreleasepool {
1563 b58ff732 Miltiadis Vasilakis
            if ([[request.userInfo objectForKey:@"operation"] isCancelled]) {
1564 b58ff732 Miltiadis Vasilakis
                dispatch_async(dispatch_get_main_queue(), ^{
1565 b58ff732 Miltiadis Vasilakis
                    [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] 
1566 b58ff732 Miltiadis Vasilakis
                                      withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
1567 b58ff732 Miltiadis Vasilakis
                });
1568 b58ff732 Miltiadis Vasilakis
            }
1569 d8426ffb Miltiadis Vasilakis
        }
1570 d8426ffb Miltiadis Vasilakis
    };
1571 d8426ffb Miltiadis Vasilakis
    [(NSMutableDictionary *)request.userInfo setObject:operation forKey:@"operation"];
1572 d8426ffb Miltiadis Vasilakis
    [callbackQueue addOperation:operation];
1573 4c1c46fd Miltiadis Vasilakis
}
1574 4c1c46fd Miltiadis Vasilakis
1575 4c1c46fd Miltiadis Vasilakis
- (void)performRequestFailedDelegateInBackground:(ASIPithosRequest *)request {
1576 d8426ffb Miltiadis Vasilakis
    if (request.isCancelled) {
1577 d8426ffb Miltiadis Vasilakis
        // Request has been cancelled 
1578 d8426ffb Miltiadis Vasilakis
        // The callbackQueue might be suspended so we call directly the callback method, since it does minimal work anyway
1579 d8426ffb Miltiadis Vasilakis
        [self performSelector:NSSelectorFromString([request.userInfo objectForKey:@"didFailSelector"]) 
1580 d8426ffb Miltiadis Vasilakis
                   withObject:request];
1581 d8426ffb Miltiadis Vasilakis
    } else {
1582 d8426ffb Miltiadis Vasilakis
        NSOperationQueue *callbackQueue;
1583 d8426ffb Miltiadis Vasilakis
        NSString *operationType = [request.userInfo objectForKey:@"operationType"];
1584 d8426ffb Miltiadis Vasilakis
        if ([operationType isEqualToString:@"move"])
1585 d8426ffb Miltiadis Vasilakis
            callbackQueue = moveCallbackQueue;
1586 d8426ffb Miltiadis Vasilakis
        else if ([operationType isEqualToString:@"copy"])
1587 d8426ffb Miltiadis Vasilakis
            callbackQueue = copyCallbackQueue;
1588 d8426ffb Miltiadis Vasilakis
        else if ([operationType isEqualToString:@"delete"])
1589 d8426ffb Miltiadis Vasilakis
            callbackQueue = deleteCallbackQueue;
1590 d8426ffb Miltiadis Vasilakis
        else if ([operationType isEqualToString:@"upload"])
1591 d8426ffb Miltiadis Vasilakis
            callbackQueue = uploadCallbackQueue;
1592 d8426ffb Miltiadis Vasilakis
        else if ([operationType isEqualToString:@"download"])
1593 d8426ffb Miltiadis Vasilakis
            callbackQueue = downloadCallbackQueue;
1594 363c618c Miltiadis Vasilakis
        else {
1595 d8426ffb Miltiadis Vasilakis
            dispatch_async(dispatch_get_main_queue(), ^{
1596 d8426ffb Miltiadis Vasilakis
                [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] 
1597 d8426ffb Miltiadis Vasilakis
                                  withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
1598 d8426ffb Miltiadis Vasilakis
            });
1599 363c618c Miltiadis Vasilakis
            return;
1600 363c618c Miltiadis Vasilakis
        }
1601 d8426ffb Miltiadis Vasilakis
        // Add an operation to the callbackQueue with a completionBlock for the case of cancellation
1602 cb6abe72 Miltiadis Vasilakis
        NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self 
1603 d8426ffb Miltiadis Vasilakis
                                                                                 selector:NSSelectorFromString([request.userInfo objectForKey:@"didFailSelector"]) 
1604 cb6abe72 Miltiadis Vasilakis
                                                                                   object:request];
1605 d8426ffb Miltiadis Vasilakis
        operation.completionBlock = ^{
1606 b58ff732 Miltiadis Vasilakis
            @autoreleasepool {
1607 b58ff732 Miltiadis Vasilakis
                if ([[request.userInfo objectForKey:@"operation"] isCancelled]) {
1608 b58ff732 Miltiadis Vasilakis
                    dispatch_async(dispatch_get_main_queue(), ^{
1609 b58ff732 Miltiadis Vasilakis
                        [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] 
1610 b58ff732 Miltiadis Vasilakis
                                          withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
1611 b58ff732 Miltiadis Vasilakis
                    });
1612 b58ff732 Miltiadis Vasilakis
                }
1613 d8426ffb Miltiadis Vasilakis
            }
1614 d8426ffb Miltiadis Vasilakis
        };
1615 d8426ffb Miltiadis Vasilakis
        [(NSMutableDictionary *)request.userInfo setObject:operation forKey:@"operation"];
1616 d8426ffb Miltiadis Vasilakis
        [callbackQueue addOperation:operation];
1617 d8426ffb Miltiadis Vasilakis
    }
1618 4c1c46fd Miltiadis Vasilakis
}
1619 4c1c46fd Miltiadis Vasilakis
1620 4c1c46fd Miltiadis Vasilakis
- (void)requestFailed:(ASIPithosRequest *)request {
1621 b58ff732 Miltiadis Vasilakis
    @autoreleasepool {
1622 b58ff732 Miltiadis Vasilakis
        NSOperation *operation = [request.userInfo objectForKey:@"operation"];
1623 b58ff732 Miltiadis Vasilakis
        DLog(@"Request failed: %@", request.url);
1624 b58ff732 Miltiadis Vasilakis
        if (operation.isCancelled)
1625 b58ff732 Miltiadis Vasilakis
            return;
1626 b58ff732 Miltiadis Vasilakis
        if (request.isCancelled) {
1627 b58ff732 Miltiadis Vasilakis
            dispatch_async(dispatch_get_main_queue(), ^{
1628 b58ff732 Miltiadis Vasilakis
                [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] 
1629 b58ff732 Miltiadis Vasilakis
                                  withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
1630 b58ff732 Miltiadis Vasilakis
            });
1631 b58ff732 Miltiadis Vasilakis
            return;
1632 b58ff732 Miltiadis Vasilakis
        }
1633 b58ff732 Miltiadis Vasilakis
        NSUInteger retries = [[request.userInfo objectForKey:@"retries"] unsignedIntegerValue];
1634 b58ff732 Miltiadis Vasilakis
        if (retries > 0) {
1635 6d9d5dce Miltiadis Vasilakis
            ASIPithosRequest *newRequest = (ASIPithosRequest *)[PithosUtilities retryWithUpdatedURLRequest:request
1636 6d9d5dce Miltiadis Vasilakis
                                                                                   andPithosAccountManager:pithosAccountManager];;
1637 b58ff732 Miltiadis Vasilakis
            [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
1638 b58ff732 Miltiadis Vasilakis
            [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithBool:NO] forKey:@"unexpectedResponseStatus"];
1639 b58ff732 Miltiadis Vasilakis
            [[newRequest.userInfo objectForKey:@"networkQueue"] addOperation:[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]]];
1640 b58ff732 Miltiadis Vasilakis
        } else {
1641 b58ff732 Miltiadis Vasilakis
            dispatch_async(dispatch_get_main_queue(), ^{
1642 b58ff732 Miltiadis Vasilakis
                [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] 
1643 b58ff732 Miltiadis Vasilakis
                                  withMessage:[request.userInfo objectForKey:@"failedActivityMessage"]];
1644 b58ff732 Miltiadis Vasilakis
            });
1645 b58ff732 Miltiadis Vasilakis
            if ([[request.userInfo objectForKey:@"unexpectedResponseStatus"] boolValue])
1646 b58ff732 Miltiadis Vasilakis
                [PithosUtilities unexpectedResponseStatusAlertWithRequest:request];
1647 b58ff732 Miltiadis Vasilakis
            else
1648 b58ff732 Miltiadis Vasilakis
                [PithosUtilities httpRequestErrorAlertWithRequest:request];
1649 b58ff732 Miltiadis Vasilakis
        }
1650 4c1c46fd Miltiadis Vasilakis
    }
1651 4c1c46fd Miltiadis Vasilakis
}
1652 4c1c46fd Miltiadis Vasilakis
1653 d7c03491 Miltiadis Vasilakis
- (void)downloadObjectFinished:(ASIPithosObjectRequest *)objectRequest {
1654 b58ff732 Miltiadis Vasilakis
    @autoreleasepool {
1655 b58ff732 Miltiadis Vasilakis
        NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
1656 b58ff732 Miltiadis Vasilakis
        DLog(@"Download finished: %@", objectRequest.url);
1657 b58ff732 Miltiadis Vasilakis
        if (operation.isCancelled) {
1658 b58ff732 Miltiadis Vasilakis
            [self requestFailed:objectRequest];
1659 b58ff732 Miltiadis Vasilakis
        } else if (objectRequest.responseStatusCode == 200) {
1660 b58ff732 Miltiadis Vasilakis
            NSString *filePath = [objectRequest.userInfo objectForKey:@"filePath"];
1661 b58ff732 Miltiadis Vasilakis
            PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
1662 b58ff732 Miltiadis Vasilakis
            NSUInteger totalBytes = activity.totalBytes;
1663 b58ff732 Miltiadis Vasilakis
            
1664 b58ff732 Miltiadis Vasilakis
            // XXX change contentLength to objectContentLength if it is fixed in the server
1665 b58ff732 Miltiadis Vasilakis
            if ([objectRequest contentLength] == 0) {
1666 b58ff732 Miltiadis Vasilakis
                // The check above was:
1667 b58ff732 Miltiadis Vasilakis
                // if (([objectRequest contentLength] == 0) && ![PithosUtilities isContentTypeDirectory:[objectRequest contentType]]) {
1668 b58ff732 Miltiadis Vasilakis
                // I checked for directory content types in order not to create a file in place of a directory,
1669 b58ff732 Miltiadis Vasilakis
                // but this callback method is not called in the case of a directory download.
1670 b58ff732 Miltiadis Vasilakis
                // It maybe the case though, when downloading an old version of an object, is of a directory content type.
1671 b58ff732 Miltiadis Vasilakis
                // In this case, a file should be created. This is actually a feature that allows you to hide data in a directory object.
1672 b58ff732 Miltiadis Vasilakis
                DLog(@"Downloaded  0 bytes");
1673 b58ff732 Miltiadis Vasilakis
                NSFileManager *fileManager = [NSFileManager defaultManager];
1674 b58ff732 Miltiadis Vasilakis
                if (![fileManager fileExistsAtPath:filePath]) {
1675 b58ff732 Miltiadis Vasilakis
                    if (![fileManager createFileAtPath:filePath contents:nil attributes:nil]) {
1676 b58ff732 Miltiadis Vasilakis
                        dispatch_async(dispatch_get_main_queue(), ^{
1677 cb6abe72 Miltiadis Vasilakis
                            NSAlert *alert = [[NSAlert alloc] init];
1678 b58ff732 Miltiadis Vasilakis
                            [alert setMessageText:@"Create File Error"];
1679 b58ff732 Miltiadis Vasilakis
                            [alert setInformativeText:[NSString stringWithFormat:@"Cannot create zero length file at %@", filePath]];
1680 b58ff732 Miltiadis Vasilakis
                            [alert addButtonWithTitle:@"OK"];
1681 b58ff732 Miltiadis Vasilakis
                            [alert runModal];
1682 b58ff732 Miltiadis Vasilakis
                        });
1683 b58ff732 Miltiadis Vasilakis
                    }
1684 4650cc63 Miltiadis Vasilakis
                }
1685 d7c03491 Miltiadis Vasilakis
            }
1686 b58ff732 Miltiadis Vasilakis
            
1687 b58ff732 Miltiadis Vasilakis
            NSUInteger currentBytes = [objectRequest objectContentLength];
1688 b58ff732 Miltiadis Vasilakis
            if (currentBytes == 0)
1689 b58ff732 Miltiadis Vasilakis
                currentBytes = totalBytes;
1690 b58ff732 Miltiadis Vasilakis
            dispatch_async(dispatch_get_main_queue(), ^{
1691 b58ff732 Miltiadis Vasilakis
                [activityFacility endActivity:activity 
1692 b58ff732 Miltiadis Vasilakis
                                  withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"] 
1693 b58ff732 Miltiadis Vasilakis
                                   totalBytes:totalBytes 
1694 b58ff732 Miltiadis Vasilakis
                                 currentBytes:currentBytes];
1695 b58ff732 Miltiadis Vasilakis
            });
1696 b58ff732 Miltiadis Vasilakis
        } else {
1697 b58ff732 Miltiadis Vasilakis
            [(NSMutableDictionary *)(objectRequest.userInfo)setObject:[NSNumber numberWithBool:YES] forKey:@"unexpectedResponseStatus"];
1698 b58ff732 Miltiadis Vasilakis
            [self requestFailed:objectRequest];
1699 d7c03491 Miltiadis Vasilakis
        }
1700 1b1e6fa1 Miltiadis Vasilakis
    }
1701 d7c03491 Miltiadis Vasilakis
}
1702 d7c03491 Miltiadis Vasilakis
1703 2ff5d98f Miltiadis Vasilakis
- (void)uploadDirectoryObjectFinished:(ASIPithosObjectRequest *)objectRequest {
1704 b58ff732 Miltiadis Vasilakis
    @autoreleasepool {
1705 b58ff732 Miltiadis Vasilakis
        NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
1706 b58ff732 Miltiadis Vasilakis
        DLog(@"Upload directory object finished: %@", objectRequest.url);
1707 b58ff732 Miltiadis Vasilakis
        if (operation.isCancelled) {
1708 b58ff732 Miltiadis Vasilakis
            [self requestFailed:objectRequest];
1709 b58ff732 Miltiadis Vasilakis
        } else if (objectRequest.responseStatusCode == 201) {
1710 b58ff732 Miltiadis Vasilakis
            DLog(@"Directory object created: %@", objectRequest.url);
1711 b58ff732 Miltiadis Vasilakis
            dispatch_async(dispatch_get_main_queue(), ^{
1712 b58ff732 Miltiadis Vasilakis
                [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
1713 b58ff732 Miltiadis Vasilakis
                                  withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]];
1714 b58ff732 Miltiadis Vasilakis
                for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) {
1715 b58ff732 Miltiadis Vasilakis
                    [node forceRefresh];
1716 b58ff732 Miltiadis Vasilakis
                }
1717 b58ff732 Miltiadis Vasilakis
                for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) {
1718 b58ff732 Miltiadis Vasilakis
                    [node refresh];
1719 b58ff732 Miltiadis Vasilakis
                }
1720 b58ff732 Miltiadis Vasilakis
                if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue])
1721 b58ff732 Miltiadis Vasilakis
                    [self forceRefresh:self];
1722 b58ff732 Miltiadis Vasilakis
                else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue])
1723 b58ff732 Miltiadis Vasilakis
                    [self refresh:self];
1724 b58ff732 Miltiadis Vasilakis
            });
1725 b58ff732 Miltiadis Vasilakis
        } else {
1726 b58ff732 Miltiadis Vasilakis
            [(NSMutableDictionary *)(objectRequest.userInfo)setObject:[NSNumber numberWithBool:YES] forKey:@"unexpectedResponseStatus"];
1727 b58ff732 Miltiadis Vasilakis
            [self requestFailed:objectRequest];
1728 b58ff732 Miltiadis Vasilakis
        }
1729 212a7d57 Miltiadis Vasilakis
    }
1730 2ff5d98f Miltiadis Vasilakis
}
1731 2ff5d98f Miltiadis Vasilakis
1732 d7c03491 Miltiadis Vasilakis
- (void)uploadObjectUsingHashMapFinished:(ASIPithosObjectRequest *)objectRequest {
1733 b58ff732 Miltiadis Vasilakis
    @autoreleasepool {
1734 b58ff732 Miltiadis Vasilakis
        NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
1735 b58ff732 Miltiadis Vasilakis
        DLog(@"Upload using hashmap finished: %@", objectRequest.url);
1736 b58ff732 Miltiadis Vasilakis
        NSString *fileName = [objectRequest.userInfo objectForKey:@"fileName"];
1737 b58ff732 Miltiadis Vasilakis
        PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
1738 b58ff732 Miltiadis Vasilakis
        NSUInteger totalBytes = activity.totalBytes;
1739 b58ff732 Miltiadis Vasilakis
        NSUInteger currentBytes = activity.currentBytes;
1740 b58ff732 Miltiadis Vasilakis
        if (operation.isCancelled) {
1741 b58ff732 Miltiadis Vasilakis
            [self requestFailed:objectRequest];
1742 b58ff732 Miltiadis Vasilakis
        } else if (objectRequest.responseStatusCode == 201) {
1743 b58ff732 Miltiadis Vasilakis
            DLog(@"Object created: %@", objectRequest.url);
1744 4c1c46fd Miltiadis Vasilakis
            dispatch_async(dispatch_get_main_queue(), ^{
1745 4c1c46fd Miltiadis Vasilakis
                [activityFacility endActivity:activity 
1746 b58ff732 Miltiadis Vasilakis
                                  withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"] 
1747 b58ff732 Miltiadis Vasilakis
                                   totalBytes:totalBytes 
1748 b58ff732 Miltiadis Vasilakis
                                 currentBytes:totalBytes];
1749 b58ff732 Miltiadis Vasilakis
                for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) {
1750 b58ff732 Miltiadis Vasilakis
                    [node forceRefresh];
1751 b58ff732 Miltiadis Vasilakis
                }
1752 b58ff732 Miltiadis Vasilakis
                for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) {
1753 b58ff732 Miltiadis Vasilakis
                    [node refresh];
1754 b58ff732 Miltiadis Vasilakis
                }
1755 b58ff732 Miltiadis Vasilakis
                if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue])
1756 b58ff732 Miltiadis Vasilakis
                    [self forceRefresh:self];
1757 b58ff732 Miltiadis Vasilakis
                else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue])
1758 b58ff732 Miltiadis Vasilakis
                    [self refresh:self];        
1759 4c1c46fd Miltiadis Vasilakis
            });
1760 b58ff732 Miltiadis Vasilakis
        } else if (objectRequest.responseStatusCode == 409) {
1761 b58ff732 Miltiadis Vasilakis
            NSUInteger iteration = [[objectRequest.userInfo objectForKey:@"iteration"] unsignedIntegerValue];
1762 b58ff732 Miltiadis Vasilakis
            if (iteration == 0) {
1763 b58ff732 Miltiadis Vasilakis
                DLog(@"Upload iteration limit reached: %@", objectRequest.url);
1764 b58ff732 Miltiadis Vasilakis
                dispatch_async(dispatch_get_main_queue(), ^{
1765 b58ff732 Miltiadis Vasilakis
                    [activityFacility endActivity:activity 
1766 b58ff732 Miltiadis Vasilakis
                                      withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; 
1767 cb6abe72 Miltiadis Vasilakis
                    NSAlert *alert = [[NSAlert alloc] init];
1768 b58ff732 Miltiadis Vasilakis
                    [alert setMessageText:@"Upload Timeout"];
1769 b58ff732 Miltiadis Vasilakis
                    [alert setInformativeText:[NSString stringWithFormat:@"Upload iteration limit reached for object with path '%@'", 
1770 b58ff732 Miltiadis Vasilakis
                                               [objectRequest.userInfo objectForKey:@"objectName"]]];
1771 b58ff732 Miltiadis Vasilakis
                    [alert addButtonWithTitle:@"OK"];
1772 b58ff732 Miltiadis Vasilakis
                    [alert runModal];
1773 b58ff732 Miltiadis Vasilakis
                });
1774 b58ff732 Miltiadis Vasilakis
                return;
1775 b58ff732 Miltiadis Vasilakis
            }
1776 b58ff732 Miltiadis Vasilakis
            DLog(@"object is missing hashes: %@", objectRequest.url);
1777 b58ff732 Miltiadis Vasilakis
            NSIndexSet *missingBlocks = [PithosUtilities missingBlocksForHashes:[objectRequest.userInfo objectForKey:@"hashes"]
1778 b58ff732 Miltiadis Vasilakis
                                                              withMissingHashes:[objectRequest hashes]];
1779 b58ff732 Miltiadis Vasilakis
            NSUInteger blockSize = [[objectRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue];
1780 b58ff732 Miltiadis Vasilakis
            if (totalBytes >= [missingBlocks count]*blockSize)
1781 b58ff732 Miltiadis Vasilakis
                currentBytes = totalBytes - [missingBlocks count]*blockSize;
1782 b58ff732 Miltiadis Vasilakis
            dispatch_async(dispatch_get_main_queue(), ^{
1783 b58ff732 Miltiadis Vasilakis
                [activityFacility updateActivity:activity 
1784 b58ff732 Miltiadis Vasilakis
                                     withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.0f%%)", fileName, (totalBytes ? (100*(currentBytes + 0.0)/(totalBytes + 0.0)) : 100)] 
1785 b58ff732 Miltiadis Vasilakis
                                      totalBytes:totalBytes 
1786 b58ff732 Miltiadis Vasilakis
                                    currentBytes:currentBytes];
1787 b58ff732 Miltiadis Vasilakis
            });
1788 b58ff732 Miltiadis Vasilakis
            NSUInteger missingBlockIndex = [missingBlocks firstIndex];
1789 fb27f368 Miltiadis Vasilakis
            __block ASIPithosContainerRequest *newContainerRequest = [PithosUtilities updateContainerDataRequestWithPithos:pithosAccountManager.pithos
1790 b58ff732 Miltiadis Vasilakis
                                                                                                             containerName:[objectRequest.userInfo objectForKey:@"containerName"] 
1791 b58ff732 Miltiadis Vasilakis
                                                                                                                 blockSize:blockSize 
1792 b58ff732 Miltiadis Vasilakis
                                                                                                                   forFile:[objectRequest.userInfo objectForKey:@"filePath"] 
1793 919cb043 Miltiadis Vasilakis
                                                                                                         missingBlockIndex:missingBlockIndex 
1794 b58ff732 Miltiadis Vasilakis
                                                                                                            sharingAccount:[objectRequest.userInfo objectForKey:@"sharingAccount"]];
1795 3b22507d Miltiadis Vasilakis
            newContainerRequest.delegate = self;
1796 4c1c46fd Miltiadis Vasilakis
            newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1797 4c1c46fd Miltiadis Vasilakis
            newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1798 b58ff732 Miltiadis Vasilakis
            newContainerRequest.userInfo = objectRequest.userInfo;
1799 b58ff732 Miltiadis Vasilakis
            [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:(--iteration)] forKey:@"iteration"];
1800 1b1e6fa1 Miltiadis Vasilakis
            [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
1801 b58ff732 Miltiadis Vasilakis
            [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:missingBlocks forKey:@"missingBlocks"];
1802 3b22507d Miltiadis Vasilakis
            [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
1803 b58ff732 Miltiadis Vasilakis
            [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:NSStringFromSelector(@selector(uploadMissingBlockFinished:)) forKey:@"didFinishSelector"];
1804 1b1e6fa1 Miltiadis Vasilakis
            [newContainerRequest setBytesSentBlock:^(unsigned long long size, unsigned long long total){
1805 1b1e6fa1 Miltiadis Vasilakis
                [activityFacility updateActivity:activity 
1806 4c1c46fd Miltiadis Vasilakis
                                     withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.0f%%)", fileName, (activity.totalBytes ? (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0)) : 100)] 
1807 1b1e6fa1 Miltiadis Vasilakis
                                      totalBytes:activity.totalBytes 
1808 1b1e6fa1 Miltiadis Vasilakis
                                    currentBytes:(activity.currentBytes + size)];
1809 1b1e6fa1 Miltiadis Vasilakis
            }];
1810 4c1c46fd Miltiadis Vasilakis
            [uploadNetworkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]];
1811 b58ff732 Miltiadis Vasilakis
        } else {
1812 b58ff732 Miltiadis Vasilakis
            [(NSMutableDictionary *)(objectRequest.userInfo)setObject:[NSNumber numberWithBool:YES] forKey:@"unexpectedResponseStatus"];
1813 b58ff732 Miltiadis Vasilakis
            [self requestFailed:objectRequest];
1814 b58ff732 Miltiadis Vasilakis
        }
1815 b58ff732 Miltiadis Vasilakis
    }
1816 b58ff732 Miltiadis Vasilakis
}
1817 b58ff732 Miltiadis Vasilakis
1818 b58ff732 Miltiadis Vasilakis
- (void)uploadMissingBlockFinished:(ASIPithosContainerRequest *)containerRequest {
1819 b58ff732 Miltiadis Vasilakis
    @autoreleasepool {
1820 b58ff732 Miltiadis Vasilakis
        NSOperation *operation = [containerRequest.userInfo objectForKey:@"operation"];
1821 b58ff732 Miltiadis Vasilakis
        DLog(@"Upload of missing block finished: %@", containerRequest.url);
1822 b58ff732 Miltiadis Vasilakis
        NSUInteger blockSize = [[containerRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue];
1823 b58ff732 Miltiadis Vasilakis
        NSString *fileName = [containerRequest.userInfo objectForKey:@"fileName"];
1824 b58ff732 Miltiadis Vasilakis
        PithosActivity *activity = [containerRequest.userInfo objectForKey:@"activity"];
1825 b58ff732 Miltiadis Vasilakis
        if (operation.isCancelled) {
1826 b58ff732 Miltiadis Vasilakis
            [self requestFailed:containerRequest];
1827 b58ff732 Miltiadis Vasilakis
        } else if (containerRequest.responseStatusCode == 202) {
1828 b58ff732 Miltiadis Vasilakis
            NSIndexSet *missingBlocks = [containerRequest.userInfo objectForKey:@"missingBlocks"];
1829 b58ff732 Miltiadis Vasilakis
            NSUInteger missingBlockIndex = [[containerRequest.userInfo objectForKey:@"missingBlockIndex"] unsignedIntegerValue];
1830 b58ff732 Miltiadis Vasilakis
            missingBlockIndex = [missingBlocks indexGreaterThanIndex:missingBlockIndex];
1831 b58ff732 Miltiadis Vasilakis
            if (missingBlockIndex == NSNotFound) {
1832 b58ff732 Miltiadis Vasilakis
                NSArray *hashes = [containerRequest.userInfo objectForKey:@"hashes"];
1833 fb27f368 Miltiadis Vasilakis
                ASIPithosObjectRequest *newObjectRequest = [PithosUtilities writeObjectDataRequestWithPithos:pithosAccountManager.pithos 
1834 b58ff732 Miltiadis Vasilakis
                                                                                               containerName:[containerRequest.userInfo objectForKey:@"containerName"] 
1835 b58ff732 Miltiadis Vasilakis
                                                                                                  objectName:[containerRequest.userInfo objectForKey:@"objectName"] 
1836 b58ff732 Miltiadis Vasilakis
                                                                                                 contentType:[containerRequest.userInfo objectForKey:@"contentType"] 
1837 b58ff732 Miltiadis Vasilakis
                                                                                                   blockSize:blockSize 
1838 b58ff732 Miltiadis Vasilakis
                                                                                                   blockHash:[containerRequest.userInfo objectForKey:@"blockHash"]
1839 b58ff732 Miltiadis Vasilakis
                                                                                                     forFile:[containerRequest.userInfo objectForKey:@"filePath"] 
1840 b58ff732 Miltiadis Vasilakis
                                                                                               checkIfExists:NO 
1841 b58ff732 Miltiadis Vasilakis
                                                                                                      hashes:&hashes 
1842 b58ff732 Miltiadis Vasilakis
                                                                                              sharingAccount:[containerRequest.userInfo objectForKey:@"sharingAccount"]];
1843 b58ff732 Miltiadis Vasilakis
                newObjectRequest.delegate = self;
1844 b58ff732 Miltiadis Vasilakis
                newObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1845 b58ff732 Miltiadis Vasilakis
                newObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1846 b58ff732 Miltiadis Vasilakis
                newObjectRequest.userInfo = containerRequest.userInfo;
1847 b58ff732 Miltiadis Vasilakis
                [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
1848 b58ff732 Miltiadis Vasilakis
                [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlocks"];
1849 b58ff732 Miltiadis Vasilakis
                [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlockIndex"];
1850 b58ff732 Miltiadis Vasilakis
                [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:NSStringFromSelector(@selector(uploadObjectUsingHashMapFinished:)) forKey:@"didFinishSelector"];
1851 b58ff732 Miltiadis Vasilakis
                [uploadNetworkQueue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]]];
1852 b58ff732 Miltiadis Vasilakis
            } else {
1853 fb27f368 Miltiadis Vasilakis
                __block ASIPithosContainerRequest *newContainerRequest = [PithosUtilities updateContainerDataRequestWithPithos:pithosAccountManager.pithos 
1854 b58ff732 Miltiadis Vasilakis
                                                                                                                 containerName:[containerRequest.userInfo objectForKey:@"containerName"]
1855 b58ff732 Miltiadis Vasilakis
                                                                                                                     blockSize:[[containerRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue]
1856 b58ff732 Miltiadis Vasilakis
                                                                                                                       forFile:[containerRequest.userInfo objectForKey:@"filePath"] 
1857 b58ff732 Miltiadis Vasilakis
                                                                                                             missingBlockIndex:missingBlockIndex 
1858 b58ff732 Miltiadis Vasilakis
                                                                                                                sharingAccount:[containerRequest.userInfo objectForKey:@"sharingAccount"]];
1859 b58ff732 Miltiadis Vasilakis
                newContainerRequest.delegate = self;
1860 b58ff732 Miltiadis Vasilakis
                newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1861 b58ff732 Miltiadis Vasilakis
                newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1862 b58ff732 Miltiadis Vasilakis
                newContainerRequest.userInfo = containerRequest.userInfo;
1863 b58ff732 Miltiadis Vasilakis
                [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
1864 b58ff732 Miltiadis Vasilakis
                [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
1865 b58ff732 Miltiadis Vasilakis
                [newContainerRequest setBytesSentBlock:^(unsigned long long size, unsigned long long total){
1866 b58ff732 Miltiadis Vasilakis
                    [activityFacility updateActivity:activity 
1867 b58ff732 Miltiadis Vasilakis
                                         withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.0f%%)", fileName, (activity.totalBytes ? (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0)) : 100)] 
1868 b58ff732 Miltiadis Vasilakis
                                          totalBytes:activity.totalBytes 
1869 b58ff732 Miltiadis Vasilakis
                                        currentBytes:(activity.currentBytes + size)];
1870 b58ff732 Miltiadis Vasilakis
                }];
1871 b58ff732 Miltiadis Vasilakis
                [uploadNetworkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]];
1872 b58ff732 Miltiadis Vasilakis
            }
1873 b58ff732 Miltiadis Vasilakis
        } else {
1874 b58ff732 Miltiadis Vasilakis
            [(NSMutableDictionary *)(containerRequest.userInfo)setObject:[NSNumber numberWithBool:YES] forKey:@"unexpectedResponseStatus"];
1875 b58ff732 Miltiadis Vasilakis
            [self requestFailed:containerRequest];
1876 cab8f227 Miltiadis Vasilakis
        }
1877 1b1e6fa1 Miltiadis Vasilakis
    }
1878 f2f50f78 Miltiadis Vasilakis
}
1879 f2f50f78 Miltiadis Vasilakis
1880 d41b3577 Miltiadis Vasilakis
- (void)moveFinished:(ASIPithosObjectRequest *)objectRequest {
1881 b58ff732 Miltiadis Vasilakis
    @autoreleasepool {
1882 b58ff732 Miltiadis Vasilakis
        NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
1883 b58ff732 Miltiadis Vasilakis
        DLog(@"Move object finished: %@", objectRequest.url);
1884 b58ff732 Miltiadis Vasilakis
        if (operation.isCancelled) {
1885 b58ff732 Miltiadis Vasilakis
            [self requestFailed:objectRequest];
1886 b58ff732 Miltiadis Vasilakis
        } else if (objectRequest.responseStatusCode == 201) {
1887 b58ff732 Miltiadis Vasilakis
            dispatch_async(dispatch_get_main_queue(), ^{
1888 b58ff732 Miltiadis Vasilakis
                [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
1889 b58ff732 Miltiadis Vasilakis
                                  withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]];
1890 b58ff732 Miltiadis Vasilakis
                for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) {
1891 b58ff732 Miltiadis Vasilakis
                    [node forceRefresh];
1892 b58ff732 Miltiadis Vasilakis
                }
1893 b58ff732 Miltiadis Vasilakis
                for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) {
1894 b58ff732 Miltiadis Vasilakis
                    [node refresh];
1895 b58ff732 Miltiadis Vasilakis
                }
1896 b58ff732 Miltiadis Vasilakis
                if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue])
1897 b58ff732 Miltiadis Vasilakis
                    [self forceRefresh:self];
1898 b58ff732 Miltiadis Vasilakis
                else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue])
1899 b58ff732 Miltiadis Vasilakis
                    [self refresh:self];
1900 b58ff732 Miltiadis Vasilakis
            });
1901 b58ff732 Miltiadis Vasilakis
        } else {
1902 b58ff732 Miltiadis Vasilakis
            [(NSMutableDictionary *)(objectRequest.userInfo)setObject:[NSNumber numberWithBool:YES] forKey:@"unexpectedResponseStatus"];
1903 b58ff732 Miltiadis Vasilakis
            [self requestFailed:objectRequest];
1904 b58ff732 Miltiadis Vasilakis
        }
1905 1b1e6fa1 Miltiadis Vasilakis
    }
1906 d41b3577 Miltiadis Vasilakis
}
1907 d41b3577 Miltiadis Vasilakis
1908 d41b3577 Miltiadis Vasilakis
- (void)copyFinished:(ASIPithosObjectRequest *)objectRequest {
1909 b58ff732 Miltiadis Vasilakis
    @autoreleasepool {
1910 b58ff732 Miltiadis Vasilakis
        NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
1911 b58ff732 Miltiadis Vasilakis
        DLog(@"Copy object finished: %@", objectRequest.url);
1912 b58ff732 Miltiadis Vasilakis
        if (operation.isCancelled) {
1913 b58ff732 Miltiadis Vasilakis
            [self requestFailed:objectRequest];
1914 b58ff732 Miltiadis Vasilakis
        } else if (objectRequest.responseStatusCode == 201) {
1915 b58ff732 Miltiadis Vasilakis
            dispatch_async(dispatch_get_main_queue(), ^{
1916 b58ff732 Miltiadis Vasilakis
                [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
1917 b58ff732 Miltiadis Vasilakis
                                  withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]];
1918 b58ff732 Miltiadis Vasilakis
                for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) {
1919 b58ff732 Miltiadis Vasilakis
                    [node forceRefresh];
1920 b58ff732 Miltiadis Vasilakis
                }
1921 b58ff732 Miltiadis Vasilakis
                for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) {
1922 b58ff732 Miltiadis Vasilakis
                    [node refresh];
1923 b58ff732 Miltiadis Vasilakis
                }
1924 b58ff732 Miltiadis Vasilakis
                if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue])
1925 b58ff732 Miltiadis Vasilakis
                    [self forceRefresh:self];
1926 b58ff732 Miltiadis Vasilakis
                else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue])
1927 b58ff732 Miltiadis Vasilakis
                    [self refresh:self];
1928 b58ff732 Miltiadis Vasilakis
            });
1929 b58ff732 Miltiadis Vasilakis
        } else {
1930 b58ff732 Miltiadis Vasilakis
            [(NSMutableDictionary *)(objectRequest.userInfo)setObject:[NSNumber numberWithBool:YES] forKey:@"unexpectedResponseStatus"];
1931 b58ff732 Miltiadis Vasilakis
            [self requestFailed:objectRequest];
1932 b58ff732 Miltiadis Vasilakis
        }
1933 1b1e6fa1 Miltiadis Vasilakis
    }
1934 d41b3577 Miltiadis Vasilakis
}
1935 d41b3577 Miltiadis Vasilakis
1936 212a7d57 Miltiadis Vasilakis
- (void)deleteObjectFinished:(ASIPithosObjectRequest *)objectRequest {
1937 b58ff732 Miltiadis Vasilakis
    @autoreleasepool {
1938 b58ff732 Miltiadis Vasilakis
        NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
1939 b58ff732 Miltiadis Vasilakis
        DLog(@"Delete object finished: %@", objectRequest.url);
1940 b58ff732 Miltiadis Vasilakis
        if (operation.isCancelled) {
1941 b58ff732 Miltiadis Vasilakis
            [self requestFailed:objectRequest];
1942 b58ff732 Miltiadis Vasilakis
        } else if (objectRequest.responseStatusCode == 204) {
1943 b58ff732 Miltiadis Vasilakis
            dispatch_async(dispatch_get_main_queue(), ^{
1944 b58ff732 Miltiadis Vasilakis
                [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
1945 b58ff732 Miltiadis Vasilakis
                                  withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]];
1946 b58ff732 Miltiadis Vasilakis
                for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) {
1947 b58ff732 Miltiadis Vasilakis
                    [node forceRefresh];
1948 b58ff732 Miltiadis Vasilakis
                }
1949 b58ff732 Miltiadis Vasilakis
                for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) {
1950 b58ff732 Miltiadis Vasilakis
                    [node refresh];
1951 b58ff732 Miltiadis Vasilakis
                }
1952 b58ff732 Miltiadis Vasilakis
                if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue])
1953 b58ff732 Miltiadis Vasilakis
                    [self forceRefresh:self];
1954 b58ff732 Miltiadis Vasilakis
                else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue])
1955 b58ff732 Miltiadis Vasilakis
                    [self refresh:self];
1956 b58ff732 Miltiadis Vasilakis
            });
1957 b58ff732 Miltiadis Vasilakis
        } else {
1958 b58ff732 Miltiadis Vasilakis
            [(NSMutableDictionary *)(objectRequest.userInfo)setObject:[NSNumber numberWithBool:YES] forKey:@"unexpectedResponseStatus"];
1959 b58ff732 Miltiadis Vasilakis
            [self requestFailed:objectRequest];
1960 b58ff732 Miltiadis Vasilakis
        }
1961 212a7d57 Miltiadis Vasilakis
    }
1962 212a7d57 Miltiadis Vasilakis
}
1963 212a7d57 Miltiadis Vasilakis
1964 e5fdf4d9 Miltiadis Vasilakis
#pragma mark -
1965 6dc7e931 Miltiadis Vasilakis
#pragma mark NSSplitViewDelegate
1966 e5fdf4d9 Miltiadis Vasilakis
1967 e5fdf4d9 Miltiadis Vasilakis
- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
1968 3b5f0a19 Miltiadis Vasilakis
    if (splitView == verticalSplitView)
1969 32d958dc Miltiadis Vasilakis
        return 140;
1970 3b5f0a19 Miltiadis Vasilakis
    else
1971 32d958dc Miltiadis Vasilakis
        return ([horizontalSplitView bounds].size.height - 142);
1972 e5fdf4d9 Miltiadis Vasilakis
}
1973 e5fdf4d9 Miltiadis Vasilakis
1974 e5fdf4d9 Miltiadis Vasilakis
- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex {
1975 3b5f0a19 Miltiadis Vasilakis
    if (splitView == verticalSplitView)
1976 3b5f0a19 Miltiadis Vasilakis
        return 220;
1977 3b5f0a19 Miltiadis Vasilakis
    else
1978 1b1e6fa1 Miltiadis Vasilakis
        return ([horizontalSplitView bounds].size.height - 108);
1979 e5fdf4d9 Miltiadis Vasilakis
}
1980 e5fdf4d9 Miltiadis Vasilakis
1981 32d958dc Miltiadis Vasilakis
- (BOOL)splitView:(NSSplitView *)splitView shouldAdjustSizeOfSubview:(NSView *)view {
1982 32d958dc Miltiadis Vasilakis
    if (((splitView == verticalSplitView) && (view == leftView)) ||
1983 32d958dc Miltiadis Vasilakis
        ((splitView == horizontalSplitView) && (view == leftBottomView))) {
1984 32d958dc Miltiadis Vasilakis
        return NO;
1985 3b5f0a19 Miltiadis Vasilakis
    }
1986 32d958dc Miltiadis Vasilakis
    return YES;
1987 133b1f2d Miltiadis Vasilakis
}
1988 133b1f2d Miltiadis Vasilakis
1989 e5fdf4d9 Miltiadis Vasilakis
#pragma mark -
1990 20f54e18 Miltiadis Vasilakis
#pragma mark NSOutlineViewDataSource
1991 20f54e18 Miltiadis Vasilakis
1992 20f54e18 Miltiadis Vasilakis
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
1993 ef8f82df Miltiadis Vasilakis
    if (!browserInitialized)
1994 ef8f82df Miltiadis Vasilakis
        return 0;
1995 20f54e18 Miltiadis Vasilakis
    if (item == nil)
1996 20f54e18 Miltiadis Vasilakis
        return 2;
1997 20f54e18 Miltiadis Vasilakis
    if (item == containersNode)
1998 20f54e18 Miltiadis Vasilakis
        return containersNodeChildren.count;
1999 20f54e18 Miltiadis Vasilakis
    if (item == sharedNode)
2000 20f54e18 Miltiadis Vasilakis
        return 2;
2001 20f54e18 Miltiadis Vasilakis
    return 0;
2002 20f54e18 Miltiadis Vasilakis
}
2003 20f54e18 Miltiadis Vasilakis
2004 20f54e18 Miltiadis Vasilakis
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
2005 ef8f82df Miltiadis Vasilakis
    if (!browserInitialized)
2006 ef8f82df Miltiadis Vasilakis
        return nil;
2007 20f54e18 Miltiadis Vasilakis
    if (item == nil)
2008 20f54e18 Miltiadis Vasilakis
        return (!index ? containersNode : sharedNode);
2009 20f54e18 Miltiadis Vasilakis
    if (item == sharedNode)
2010 20f54e18 Miltiadis Vasilakis
        return (!index ? mySharedNode : othersSharedNode);
2011 20f54e18 Miltiadis Vasilakis
    return [containersNodeChildren objectAtIndex:index];
2012 20f54e18 Miltiadis Vasilakis
}
2013 20f54e18 Miltiadis Vasilakis
2014 20f54e18 Miltiadis Vasilakis
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
2015 20f54e18 Miltiadis Vasilakis
    if ((item == containersNode) || (item == sharedNode))
2016 20f54e18 Miltiadis Vasilakis
        return YES;
2017 20f54e18 Miltiadis Vasilakis
    return NO;
2018 20f54e18 Miltiadis Vasilakis
}
2019 20f54e18 Miltiadis Vasilakis
2020 20f54e18 Miltiadis Vasilakis
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
2021 20f54e18 Miltiadis Vasilakis
    PithosNode *node = (PithosNode *)item;
2022 20f54e18 Miltiadis Vasilakis
    return node;    
2023 20f54e18 Miltiadis Vasilakis
}
2024 20f54e18 Miltiadis Vasilakis
2025 67e3336f Miltiadis Vasilakis
#pragma mark Drag and Drop destination
2026 67e3336f Miltiadis Vasilakis
2027 67e3336f Miltiadis Vasilakis
- (NSDragOperation)outlineView:(NSOutlineView *)anOutlineView 
2028 67e3336f Miltiadis Vasilakis
                  validateDrop:(id<NSDraggingInfo>)info 
2029 67e3336f Miltiadis Vasilakis
                  proposedItem:(id)item 
2030 67e3336f Miltiadis Vasilakis
            proposedChildIndex:(NSInteger)index {
2031 67e3336f Miltiadis Vasilakis
    NSDragOperation result = NSDragOperationNone;
2032 67e3336f Miltiadis Vasilakis
    if ((item == nil) || (index != NSOutlineViewDropOnItemIndex))
2033 67e3336f Miltiadis Vasilakis
        return result;
2034 67e3336f Miltiadis Vasilakis
    PithosNode *dropNode = (PithosNode *)item;
2035 67e3336f Miltiadis Vasilakis
    if ([dropNode class] != [PithosContainerNode class])
2036 67e3336f Miltiadis Vasilakis
        return result;
2037 67e3336f Miltiadis Vasilakis
    if ([[[info draggingPasteboard] types] containsObject:NSFilenamesPboardType]) {
2038 67e3336f Miltiadis Vasilakis
        result = NSDragOperationCopy;
2039 67e3336f Miltiadis Vasilakis
    } else if ([[[info draggingPasteboard] types] containsObject:NSFilesPromisePboardType]) {
2040 32ae06f7 Miltiadis Vasilakis
        if (![[draggedNodes objectAtIndex:0] shared] && ![[draggedNodes objectAtIndex:0] sharingAccount] && 
2041 32ae06f7 Miltiadis Vasilakis
            ([info draggingSourceOperationMask] & NSDragOperationMove)) {
2042 67e3336f Miltiadis Vasilakis
            // NSDragOperationCopy | NSDragOperationMove -> NSDragOperationMove
2043 67e3336f Miltiadis Vasilakis
            if (![dropNode isEqualTo:draggedParentNode])
2044 67e3336f Miltiadis Vasilakis
                result = NSDragOperationMove;
2045 67e3336f Miltiadis Vasilakis
        } else if ([info draggingSourceOperationMask] & NSDragOperationCopy) {
2046 67e3336f Miltiadis Vasilakis
            // NSDragOperationCopy (Option modifier) -> NSDragOperationCopy
2047 67e3336f Miltiadis Vasilakis
            result = NSDragOperationCopy;
2048 67e3336f Miltiadis Vasilakis
        }
2049 67e3336f Miltiadis Vasilakis
    }
2050 67e3336f Miltiadis Vasilakis
   return result;
2051 67e3336f Miltiadis Vasilakis
}
2052 67e3336f Miltiadis Vasilakis
2053 67e3336f Miltiadis Vasilakis
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id<NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index {
2054 67e3336f Miltiadis Vasilakis
    if ([[[info draggingPasteboard] types] containsObject:NSFilenamesPboardType]) {
2055 67e3336f Miltiadis Vasilakis
        NSArray *filenames = [[info draggingPasteboard] propertyListForType:NSFilenamesPboardType];
2056 9990166e Miltiadis Vasilakis
        DLog(@"drag in operation: %lu filenames: %@", [info draggingSourceOperationMask], filenames);
2057 67e3336f Miltiadis Vasilakis
        if (item && (index == NSOutlineViewDropOnItemIndex) && (filenames != nil)) {
2058 67e3336f Miltiadis Vasilakis
            PithosNode *node = (PithosNode *)item;
2059 9990166e Miltiadis Vasilakis
            DLog(@"drag in node: %@", node.url);
2060 67e3336f Miltiadis Vasilakis
            return [self uploadFiles:filenames toNode:node];
2061 67e3336f Miltiadis Vasilakis
        }
2062 67e3336f Miltiadis Vasilakis
    } else if ([[[info draggingPasteboard] types] containsObject:NSFilesPromisePboardType]) {
2063 9990166e Miltiadis Vasilakis
        DLog(@"drag local operation: %lu nodes: %@", [info draggingSourceOperationMask], draggedNodes);
2064 67e3336f Miltiadis Vasilakis
        if (item && (index == NSOutlineViewDropOnItemIndex) && (draggedNodes != nil)) {
2065 67e3336f Miltiadis Vasilakis
            PithosNode *node = (PithosNode *)item;
2066 9990166e Miltiadis Vasilakis
            DLog(@"drag local node: %@", node.url);
2067 32ae06f7 Miltiadis Vasilakis
            if (![[draggedNodes objectAtIndex:0] shared] && ![[draggedNodes objectAtIndex:0] sharingAccount] && 
2068 32ae06f7 Miltiadis Vasilakis
                ([info draggingSourceOperationMask] & NSDragOperationMove))
2069 67e3336f Miltiadis Vasilakis
                return [self moveNodes:draggedNodes toNode:node];
2070 67e3336f Miltiadis Vasilakis
            else if ([info draggingSourceOperationMask] & NSDragOperationCopy)
2071 3f220848 Miltiadis Vasilakis
                return [self cpyNodes:draggedNodes toNode:node];
2072 67e3336f Miltiadis Vasilakis
        }
2073 67e3336f Miltiadis Vasilakis
    }
2074 67e3336f Miltiadis Vasilakis
    return NO;
2075 67e3336f Miltiadis Vasilakis
}
2076 67e3336f Miltiadis Vasilakis
2077 20f54e18 Miltiadis Vasilakis
#pragma mark -
2078 e5fdf4d9 Miltiadis Vasilakis
#pragma mark NSOutlineViewDelegate
2079 e5fdf4d9 Miltiadis Vasilakis
2080 e5fdf4d9 Miltiadis Vasilakis
- (BOOL)outlineView:outlineView shouldSelectItem:(id)item {
2081 20f54e18 Miltiadis Vasilakis
    if ((item == containersNode) || (item == sharedNode))
2082 20f54e18 Miltiadis Vasilakis
        return NO;
2083 20f54e18 Miltiadis Vasilakis
    return YES;
2084 e5fdf4d9 Miltiadis Vasilakis
}
2085 e5fdf4d9 Miltiadis Vasilakis
2086 e5fdf4d9 Miltiadis Vasilakis
- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item {
2087 20f54e18 Miltiadis Vasilakis
    if ((item == containersNode) || (item == sharedNode))
2088 20f54e18 Miltiadis Vasilakis
        return YES;
2089 20f54e18 Miltiadis Vasilakis
    return NO;
2090 e5fdf4d9 Miltiadis Vasilakis
}
2091 e5fdf4d9 Miltiadis Vasilakis
2092 e5fdf4d9 Miltiadis Vasilakis
- (void)outlineViewSelectionDidChange:(NSNotification *)notification {
2093 20f54e18 Miltiadis Vasilakis
    PithosNode *node = (PithosNode *)[outlineView itemAtRow:[outlineView selectedRow]];
2094 e5fdf4d9 Miltiadis Vasilakis
    if (node) {
2095 e5fdf4d9 Miltiadis Vasilakis
        rootNode = node;
2096 e5fdf4d9 Miltiadis Vasilakis
        [browser loadColumnZero];
2097 20f54e18 Miltiadis Vasilakis
        [self refresh:nil];
2098 e5fdf4d9 Miltiadis Vasilakis
    }
2099 e5fdf4d9 Miltiadis Vasilakis
}
2100 e5fdf4d9 Miltiadis Vasilakis
2101 857217b0 Miltiadis Vasilakis
#pragma mark -
2102 857217b0 Miltiadis Vasilakis
#pragma mark NSMenuDelegate
2103 857217b0 Miltiadis Vasilakis
2104 857217b0 Miltiadis Vasilakis
- (void)menuNeedsUpdate:(NSMenu *)menu {
2105 857217b0 Miltiadis Vasilakis
    [menu removeAllItems];
2106 6a9b9f40 Miltiadis Vasilakis
    NSMenuItem *menuItem;
2107 c950a94d Miltiadis Vasilakis
    NSString *menuItemTitle;
2108 8f62f46a Miltiadis Vasilakis
    BOOL nodeContextMenu = NO;
2109 f059e0e6 Miltiadis Vasilakis
    PithosNode *menuNode = nil;
2110 8f62f46a Miltiadis Vasilakis
    NSMutableArray *menuNodes;
2111 8f62f46a Miltiadis Vasilakis
    if (menu == browserMenu) {
2112 8f62f46a Miltiadis Vasilakis
        NSInteger column = [browser clickedColumn];
2113 8f62f46a Miltiadis Vasilakis
        NSInteger row = [browser clickedRow];
2114 8f62f46a Miltiadis Vasilakis
        if ((column == -1) || (row == -1)) {
2115 d37431ce Miltiadis Vasilakis
            if (column == -1) {
2116 d37431ce Miltiadis Vasilakis
                // General context menu
2117 d37431ce Miltiadis Vasilakis
                NSArray *menuNodesIndexPaths = [browser selectionIndexPaths];
2118 d37431ce Miltiadis Vasilakis
                if ([menuNodesIndexPaths count] == 0) {
2119 d37431ce Miltiadis Vasilakis
                    menuNode = [browser parentForItemsInColumn:0];
2120 d37431ce Miltiadis Vasilakis
                } else if (([menuNodesIndexPaths count] != 1) || 
2121 d37431ce Miltiadis Vasilakis
                           ([[browser itemAtIndexPath:[menuNodesIndexPaths objectAtIndex:0]] class] == [PithosObjectNode class])) {
2122 d37431ce Miltiadis Vasilakis
                    menuNode = [browser parentForItemsInColumn:([[menuNodesIndexPaths objectAtIndex:0] length] - 1)];
2123 d37431ce Miltiadis Vasilakis
                } else {
2124 d37431ce Miltiadis Vasilakis
                    menuNode = [browser itemAtIndexPath:[menuNodesIndexPaths objectAtIndex:0]];
2125 d37431ce Miltiadis Vasilakis
                }
2126 8f62f46a Miltiadis Vasilakis
            } else {
2127 d37431ce Miltiadis Vasilakis
                menuNode = [browser parentForItemsInColumn:column];
2128 d37431ce Miltiadis Vasilakis
                if ([menuNode class] == [PithosObjectNode class]) {
2129 d37431ce Miltiadis Vasilakis
                    // Node context menu
2130 d37431ce Miltiadis Vasilakis
                    menuNodes = [NSMutableArray arrayWithObject:menuNode];
2131 d37431ce Miltiadis Vasilakis
                    nodeContextMenu = YES;
2132 d37431ce Miltiadis Vasilakis
                }
2133 d37431ce Miltiadis Vasilakis
                // else 
2134 d37431ce Miltiadis Vasilakis
                // General context menu
2135 8f62f46a Miltiadis Vasilakis
            }
2136 1ca8da38 Miltiadis Vasilakis
        } else {
2137 8f62f46a Miltiadis Vasilakis
            // Node context menu
2138 8f62f46a Miltiadis Vasilakis
            NSIndexPath *clickedNodeIndexPath = [[browser indexPathForColumn:column] indexPathByAddingIndex:row];
2139 8f62f46a Miltiadis Vasilakis
            NSArray *menuNodesIndexPaths = [browser selectionIndexPaths];
2140 8f62f46a Miltiadis Vasilakis
            menuNodes = [NSMutableArray arrayWithCapacity:[menuNodesIndexPaths count]];
2141 8f62f46a Miltiadis Vasilakis
            if ([menuNodesIndexPaths containsObject:clickedNodeIndexPath]) {
2142 8f62f46a Miltiadis Vasilakis
                for (NSIndexPath *nodeIndexPath in menuNodesIndexPaths) {
2143 8f62f46a Miltiadis Vasilakis
                    [menuNodes addObject:[browser itemAtIndexPath:nodeIndexPath]];
2144 8f62f46a Miltiadis Vasilakis
                }
2145 8f62f46a Miltiadis Vasilakis
            } else {
2146 8f62f46a Miltiadis Vasilakis
                [menuNodes addObject:[browser itemAtIndexPath:clickedNodeIndexPath]];
2147 8f62f46a Miltiadis Vasilakis
            }
2148 8f62f46a Miltiadis Vasilakis
            nodeContextMenu = YES;
2149 1ca8da38 Miltiadis Vasilakis
        }
2150 8f62f46a Miltiadis Vasilakis
    } else if (menu == outlineViewMenu) {
2151 8f62f46a Miltiadis Vasilakis
        NSInteger row = [outlineView clickedRow];
2152 8f62f46a Miltiadis Vasilakis
        if (row == -1)
2153 8f62f46a Miltiadis Vasilakis
            row = [outlineView selectedRow];
2154 8f62f46a Miltiadis Vasilakis
        if (row == -1)
2155 8f62f46a Miltiadis Vasilakis
            return;
2156 8f62f46a Miltiadis Vasilakis
        menuNode = [outlineView itemAtRow:row];
2157 8f62f46a Miltiadis Vasilakis
    }
2158 8f62f46a Miltiadis Vasilakis
2159 8f62f46a Miltiadis Vasilakis
    if (!nodeContextMenu) {
2160 8f62f46a Miltiadis Vasilakis
        // General context menu
2161 8f62f46a Miltiadis Vasilakis
        if (([menuNode class] == [PithosAccountNode class]) || 
2162 8f62f46a Miltiadis Vasilakis
            ([menuNode class] == [PithosSharingAccountsNode class]) ||
2163 8f62f46a Miltiadis Vasilakis
            ([menuNode class] == [PithosEmptyNode class]))
2164 4ae10a2b Miltiadis Vasilakis
            return;
2165 8f62f46a Miltiadis Vasilakis
        // New Folder
2166 c2896649 Miltiadis Vasilakis
        if (!menuNode.shared && !menuNode.sharingAccount) {
2167 cb6abe72 Miltiadis Vasilakis
            menuItem = [[NSMenuItem alloc] initWithTitle:@"New Folder" action:@selector(menuNewFolder:) keyEquivalent:@""];
2168 4ae10a2b Miltiadis Vasilakis
            [menuItem setRepresentedObject:menuNode];
2169 4ae10a2b Miltiadis Vasilakis
            [menu addItem:menuItem];
2170 4ae10a2b Miltiadis Vasilakis
            [menu addItem:[NSMenuItem separatorItem]];
2171 4ae10a2b Miltiadis Vasilakis
        }
2172 544b6f52 Miltiadis Vasilakis
        // Refresh
2173 cb6abe72 Miltiadis Vasilakis
        menuItem = [[NSMenuItem alloc] initWithTitle:@"Refresh" action:@selector(refresh:) keyEquivalent:@""];
2174 544b6f52 Miltiadis Vasilakis
        [menu addItem:menuItem];
2175 544b6f52 Miltiadis Vasilakis
        [menu addItem:[NSMenuItem separatorItem]];
2176 515cd8db Miltiadis Vasilakis
        // Get Info
2177 cb6abe72 Miltiadis Vasilakis
        menuItem = [[NSMenuItem alloc] initWithTitle:(([menuNode class] == [PithosContainerNode class]) ? @"Info" : @"Info and Sharing") 
2178 928b3094 Miltiadis Vasilakis
                                               action:@selector(menuGetInfo:) 
2179 cb6abe72 Miltiadis Vasilakis
                                        keyEquivalent:@""];
2180 c950a94d Miltiadis Vasilakis
        [menuItem setRepresentedObject:[NSArray arrayWithObject:menuNode]];
2181 515cd8db Miltiadis Vasilakis
        [menu addItem:menuItem];
2182 8f62f46a Miltiadis Vasilakis
        // Paste
2183 c2896649 Miltiadis Vasilakis
        if (clipboardNodes && !menuNode.shared && !menuNode.sharingAccount && 
2184 c2896649 Miltiadis Vasilakis
            (([menuNode class] == [PithosContainerNode class]) || 
2185 c2896649 Miltiadis Vasilakis
             (([menuNode class] == [PithosSubdirNode class]) && 
2186 c2896649 Miltiadis Vasilakis
              (menuNode.pithosObject.subdir || ![menuNode.pithosObject.name hasSuffix:@"/"])))) {
2187 c2896649 Miltiadis Vasilakis
            NSUInteger clipboardNodesCount = [clipboardNodes count];
2188 c2896649 Miltiadis Vasilakis
            if (clipboardNodesCount == 0) {
2189 c2896649 Miltiadis Vasilakis
                self.clipboardNodes = nil;
2190 c2896649 Miltiadis Vasilakis
            } else if (clipboardCopy || ![menuNode isEqualTo:clipboardParentNode]) {
2191 c2896649 Miltiadis Vasilakis
                if (clipboardNodesCount == 1)
2192 b58ff732 Miltiadis Vasilakis
                    menuItemTitle = @"Paste Item";
2193 c2896649 Miltiadis Vasilakis
                else
2194 b58ff732 Miltiadis Vasilakis
                    menuItemTitle = @"Paste Items";
2195 c2896649 Miltiadis Vasilakis
                [menu addItem:[NSMenuItem separatorItem]];
2196 cb6abe72 Miltiadis Vasilakis
                menuItem = [[NSMenuItem alloc] initWithTitle:menuItemTitle action:@selector(menuPaste:) keyEquivalent:@""];
2197 c2896649 Miltiadis Vasilakis
                [menuItem setRepresentedObject:menuNode];
2198 c2896649 Miltiadis Vasilakis
                [menu addItem:menuItem];
2199 c950a94d Miltiadis Vasilakis
            }
2200 c950a94d Miltiadis Vasilakis
        }
2201 857217b0 Miltiadis Vasilakis
    } else {
2202 1ca8da38 Miltiadis Vasilakis
        // Node context menu
2203 c950a94d Miltiadis Vasilakis
        NSUInteger menuNodesCount = [menuNodes count];
2204 c2896649 Miltiadis Vasilakis
        PithosNode *firstMenuNode = [menuNodes objectAtIndex:0];
2205 de0873d4 Miltiadis Vasilakis
        // Download
2206 de0873d4 Miltiadis Vasilakis
        if (([firstMenuNode class] != [PithosContainerNode class]) && ([firstMenuNode class] != [PithosAccountNode class])) {
2207 cb6abe72 Miltiadis Vasilakis
            menuItem = [[NSMenuItem alloc] initWithTitle:@"Download" action:@selector(menuDownload:) keyEquivalent:@""];
2208 de0873d4 Miltiadis Vasilakis
            [menuItem setRepresentedObject:menuNodes];
2209 de0873d4 Miltiadis Vasilakis
            [menu addItem:menuItem];
2210 de0873d4 Miltiadis Vasilakis
            [menu addItem:[NSMenuItem separatorItem]];
2211 de0873d4 Miltiadis Vasilakis
        }
2212 8f62f46a Miltiadis Vasilakis
        // Move to Trash (pithos container only)
2213 8f62f46a Miltiadis Vasilakis
        // Delete
2214 c2896649 Miltiadis Vasilakis
        if (!firstMenuNode.shared && !firstMenuNode.sharingAccount && ([rootNode class] == [PithosContainerNode class])) {
2215 c2896649 Miltiadis Vasilakis
            if ([rootNode.pithosContainer.name isEqualToString:@"pithos"]) {
2216 cb6abe72 Miltiadis Vasilakis
                menuItem = [[NSMenuItem alloc] initWithTitle:@"Move to Trash" 
2217 c2896649 Miltiadis Vasilakis
                                                       action:@selector(menuMoveToTrash:) 
2218 cb6abe72 Miltiadis Vasilakis
                                                keyEquivalent:@""];
2219 1ca8da38 Miltiadis Vasilakis
                [menuItem setRepresentedObject:menuNodes];
2220 6a9b9f40 Miltiadis Vasilakis
                [menu addItem:menuItem];
2221 6a9b9f40 Miltiadis Vasilakis
            }
2222 cb6abe72 Miltiadis Vasilakis
            menuItem = [[NSMenuItem alloc] initWithTitle:@"Delete" action:@selector(menuDelete:) keyEquivalent:@""];
2223 c2896649 Miltiadis Vasilakis
            [menuItem setRepresentedObject:menuNodes];
2224 c2896649 Miltiadis Vasilakis
            [menu addItem:menuItem];
2225 c2896649 Miltiadis Vasilakis
            [menu addItem:[NSMenuItem separatorItem]];
2226 6a9b9f40 Miltiadis Vasilakis
        }
2227 544b6f52 Miltiadis Vasilakis
        // Refresh
2228 cb6abe72 Miltiadis Vasilakis
        menuItem = [[NSMenuItem alloc] initWithTitle:@"Refresh" action:@selector(refresh:) keyEquivalent:@""];
2229 544b6f52 Miltiadis Vasilakis
        [menu addItem:menuItem];
2230 8f62f46a Miltiadis Vasilakis
        // Get Info
2231 c2896649 Miltiadis Vasilakis
        if (!firstMenuNode.sharingAccount || ([firstMenuNode class] != [PithosAccountNode class])) {
2232 ce2e0bdf Miltiadis Vasilakis
            [menu addItem:[NSMenuItem separatorItem]];
2233 cb6abe72 Miltiadis Vasilakis
            menuItem = [[NSMenuItem alloc] initWithTitle:(([firstMenuNode class] == [PithosContainerNode class]) ? @"Info" : @"Info and Sharing") 
2234 928b3094 Miltiadis Vasilakis
                                                   action:@selector(menuGetInfo:) 
2235 cb6abe72 Miltiadis Vasilakis
                                            keyEquivalent:@""];
2236 af3b9f06 Miltiadis Vasilakis
            [menuItem setRepresentedObject:menuNodes];
2237 af3b9f06 Miltiadis Vasilakis
            [menu addItem:menuItem];
2238 af3b9f06 Miltiadis Vasilakis
            
2239 c2896649 Miltiadis Vasilakis
            if ((!firstMenuNode.shared && !firstMenuNode.sharingAccount) || ([firstMenuNode class] != [PithosContainerNode class]))
2240 af3b9f06 Miltiadis Vasilakis
                [menu addItem:[NSMenuItem separatorItem]];
2241 af3b9f06 Miltiadis Vasilakis
        }
2242 8f62f46a Miltiadis Vasilakis
        // Cut
2243 c2896649 Miltiadis Vasilakis
        if (!firstMenuNode.shared && !firstMenuNode.sharingAccount) {
2244 4ae10a2b Miltiadis Vasilakis
            if (menuNodesCount == 1)
2245 4ae10a2b Miltiadis Vasilakis
                menuItemTitle = [NSString stringWithFormat:@"Cut \"%@\"", ((PithosNode *)[menuNodes objectAtIndex:0]).displayName];
2246 4ae10a2b Miltiadis Vasilakis
            else 
2247 4ae10a2b Miltiadis Vasilakis
                menuItemTitle = [NSString stringWithFormat:@"Cut %lu Items", menuNodesCount];
2248 cb6abe72 Miltiadis Vasilakis
            menuItem = [[NSMenuItem alloc] initWithTitle:menuItemTitle action:@selector(menuCut:) keyEquivalent:@""];
2249 4ae10a2b Miltiadis Vasilakis
            [menuItem setRepresentedObject:menuNodes];
2250 4ae10a2b Miltiadis Vasilakis
            [menu addItem:menuItem];
2251 20f54e18 Miltiadis Vasilakis
        }
2252 8f62f46a Miltiadis Vasilakis
        // Copy
2253 c2896649 Miltiadis Vasilakis
        if ((!firstMenuNode.shared && !firstMenuNode.sharingAccount) || 
2254 af3b9f06 Miltiadis Vasilakis
            (([firstMenuNode class] != [PithosContainerNode class]) && ([firstMenuNode class] != [PithosAccountNode class]))) {
2255 4ae10a2b Miltiadis Vasilakis
            if (menuNodesCount == 1)
2256 4ae10a2b Miltiadis Vasilakis
                menuItemTitle = [NSString stringWithFormat:@"Copy \"%@\"", ((PithosNode *)[menuNodes objectAtIndex:0]).displayName];
2257 4ae10a2b Miltiadis Vasilakis
            else 
2258 4ae10a2b Miltiadis Vasilakis
                menuItemTitle = [NSString stringWithFormat:@"Copy %lu Items", menuNodesCount];
2259 cb6abe72 Miltiadis Vasilakis
            menuItem = [[NSMenuItem alloc] initWithTitle:menuItemTitle action:@selector(menuCopy:) keyEquivalent:@""];
2260 4ae10a2b Miltiadis Vasilakis
            [menuItem setRepresentedObject:menuNodes];
2261 4ae10a2b Miltiadis Vasilakis
            [menu addItem:menuItem];
2262 20f54e18 Miltiadis Vasilakis
        }
2263 8f62f46a Miltiadis Vasilakis
        // Paste
2264 c2896649 Miltiadis Vasilakis
        if (clipboardNodes && !firstMenuNode.shared && !firstMenuNode.sharingAccount && (menuNodesCount == 1) && 
2265 c2896649 Miltiadis Vasilakis
            ([firstMenuNode class] == [PithosSubdirNode class]) && 
2266 c2896649 Miltiadis Vasilakis
            (firstMenuNode.pithosObject.subdir || ![firstMenuNode.pithosObject.name hasSuffix:@"/"])) {
2267 c2896649 Miltiadis Vasilakis
            NSUInteger clipboardNodesCount = [clipboardNodes count];
2268 c2896649 Miltiadis Vasilakis
            if (clipboardNodesCount == 0) {
2269 c2896649 Miltiadis Vasilakis
                self.clipboardNodes = nil;
2270 c2896649 Miltiadis Vasilakis
            } else if (clipboardCopy || ![firstMenuNode isEqualTo:clipboardParentNode]) {
2271 c2896649 Miltiadis Vasilakis
                if (clipboardNodesCount == 1)
2272 b58ff732 Miltiadis Vasilakis
                    menuItemTitle = @"Paste Item";
2273 c2896649 Miltiadis Vasilakis
                else
2274 b58ff732 Miltiadis Vasilakis
                    menuItemTitle = @"Paste Items";
2275 cb6abe72 Miltiadis Vasilakis
                menuItem = [[NSMenuItem alloc] initWithTitle:menuItemTitle action:@selector(menuPaste:) keyEquivalent:@""];
2276 c2896649 Miltiadis Vasilakis
                [menuItem setRepresentedObject:firstMenuNode];
2277 c2896649 Miltiadis Vasilakis
                [menu addItem:menuItem];
2278 c950a94d Miltiadis Vasilakis
            }
2279 c950a94d Miltiadis Vasilakis
        }
2280 857217b0 Miltiadis Vasilakis
    }
2281 857217b0 Miltiadis Vasilakis
}
2282 857217b0 Miltiadis Vasilakis
2283 857217b0 Miltiadis Vasilakis
#pragma mark -
2284 c2896649 Miltiadis Vasilakis
#pragma mark NSMenuValidation
2285 c2896649 Miltiadis Vasilakis
2286 c2896649 Miltiadis Vasilakis
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
2287 c2896649 Miltiadis Vasilakis
    if ((menuItem.action == @selector(cut:)) || (menuItem.action == @selector(copy:)) || (menuItem.action == @selector(delete:))) {
2288 c2896649 Miltiadis Vasilakis
        NSArray *menuNodesIndexPaths = [browser selectionIndexPaths];
2289 c2896649 Miltiadis Vasilakis
        if ([menuNodesIndexPaths count] == 0)
2290 c2896649 Miltiadis Vasilakis
            return NO;
2291 c2896649 Miltiadis Vasilakis
        
2292 c2896649 Miltiadis Vasilakis
        PithosNode *firstMenuNode = [browser itemAtIndexPath:[menuNodesIndexPaths objectAtIndex:0]];
2293 c2896649 Miltiadis Vasilakis
        if (((menuItem.action == @selector(cut:)) && (firstMenuNode.shared || firstMenuNode.sharingAccount)) || 
2294 c2896649 Miltiadis Vasilakis
            ((menuItem.action == @selector(copy:)) && (firstMenuNode.shared || firstMenuNode.sharingAccount) && 
2295 c2896649 Miltiadis Vasilakis
             (([firstMenuNode class] == [PithosContainerNode class]) || ([firstMenuNode class] == [PithosAccountNode class]))) ||
2296 c2896649 Miltiadis Vasilakis
            ((menuItem.action == @selector(delete:)) && 
2297 c2896649 Miltiadis Vasilakis
             (firstMenuNode.shared || firstMenuNode.sharingAccount || ([rootNode class] != [PithosContainerNode class]) || 
2298 c2896649 Miltiadis Vasilakis
              ((menuItem.tag == 0) && ![rootNode.pithosContainer.name isEqualToString:@"pithos"]))))
2299 c2896649 Miltiadis Vasilakis
            return NO;
2300 c2896649 Miltiadis Vasilakis
        
2301 c2896649 Miltiadis Vasilakis
        NSMutableArray *menuNodes = [NSMutableArray arrayWithCapacity:[menuNodesIndexPaths count]];
2302 c2896649 Miltiadis Vasilakis
        for (NSIndexPath *nodeIndexPath in menuNodesIndexPaths) {
2303 c2896649 Miltiadis Vasilakis
            [menuNodes addObject:[browser itemAtIndexPath:nodeIndexPath]];
2304 c2896649 Miltiadis Vasilakis
        }
2305 c2896649 Miltiadis Vasilakis
        menuItem.representedObject = menuNodes;
2306 c2896649 Miltiadis Vasilakis
    } else if (menuItem.action == @selector(paste:)) {
2307 c2896649 Miltiadis Vasilakis
        if (!clipboardNodes || ![clipboardNodes count])
2308 c2896649 Miltiadis Vasilakis
            return NO;
2309 c2896649 Miltiadis Vasilakis
        
2310 c2896649 Miltiadis Vasilakis
        NSArray *menuNodesIndexPaths = [browser selectionIndexPaths];
2311 c2896649 Miltiadis Vasilakis
        PithosNode *menuNode;
2312 c2896649 Miltiadis Vasilakis
        if ([menuNodesIndexPaths count] == 0)
2313 c2896649 Miltiadis Vasilakis
            menuNode = [browser parentForItemsInColumn:0];
2314 c2896649 Miltiadis Vasilakis
        else if (([menuNodesIndexPaths count] != 1) || 
2315 c2896649 Miltiadis Vasilakis
                 ([[browser itemAtIndexPath:[menuNodesIndexPaths objectAtIndex:0]] class] == [PithosObjectNode class]))
2316 c2896649 Miltiadis Vasilakis
            menuNode = [browser parentForItemsInColumn:([[menuNodesIndexPaths objectAtIndex:0] length] - 1)];
2317 c2896649 Miltiadis Vasilakis
        else
2318 c2896649 Miltiadis Vasilakis
            menuNode = [browser itemAtIndexPath:[menuNodesIndexPaths objectAtIndex:0]];
2319 c2896649 Miltiadis Vasilakis
        
2320 c2896649 Miltiadis Vasilakis
        if (menuNode.shared || menuNode.sharingAccount || 
2321 c2896649 Miltiadis Vasilakis
            (([menuNode class] != [PithosContainerNode class]) && 
2322 c2896649 Miltiadis Vasilakis
             (([menuNode class] != [PithosSubdirNode class]) || 
2323 c2896649 Miltiadis Vasilakis
              (!menuNode.pithosObject.subdir && [menuNode.pithosObject.name hasSuffix:@"/"]))) || 
2324 c2896649 Miltiadis Vasilakis
            (!clipboardCopy && [menuNode isEqualTo:clipboardParentNode]))
2325 c2896649 Miltiadis Vasilakis
            return NO;
2326 c2896649 Miltiadis Vasilakis
2327 c2896649 Miltiadis Vasilakis
        menuItem.representedObject = menuNode;
2328 c2896649 Miltiadis Vasilakis
    }
2329 c2896649 Miltiadis Vasilakis
    return YES;
2330 c2896649 Miltiadis Vasilakis
}
2331 c2896649 Miltiadis Vasilakis
2332 c2896649 Miltiadis Vasilakis
- (void)cut:(NSMenuItem *)sender {
2333 c2896649 Miltiadis Vasilakis
    [self menuCut:sender];
2334 c2896649 Miltiadis Vasilakis
}
2335 c2896649 Miltiadis Vasilakis
2336 c2896649 Miltiadis Vasilakis
- (void)copy:(NSMenuItem *)sender {
2337 c2896649 Miltiadis Vasilakis
    [self menuCopy:sender];
2338 c2896649 Miltiadis Vasilakis
}
2339 c2896649 Miltiadis Vasilakis
2340 c2896649 Miltiadis Vasilakis
- (void)paste:(NSMenuItem *)sender {
2341 c2896649 Miltiadis Vasilakis
    [self menuPaste:sender];
2342 c2896649 Miltiadis Vasilakis
}
2343 c2896649 Miltiadis Vasilakis
2344 c2896649 Miltiadis Vasilakis
- (void)delete:(NSMenuItem *)sender {
2345 c2896649 Miltiadis Vasilakis
    if (sender.tag == 0)
2346 c2896649 Miltiadis Vasilakis
        [self menuMoveToTrash:sender];
2347 c2896649 Miltiadis Vasilakis
    else
2348 c2896649 Miltiadis Vasilakis
        [self menuDelete:sender];
2349 c2896649 Miltiadis Vasilakis
}
2350 c2896649 Miltiadis Vasilakis
2351 c2896649 Miltiadis Vasilakis
#pragma mark -
2352 857217b0 Miltiadis Vasilakis
#pragma mark Menu Actions
2353 857217b0 Miltiadis Vasilakis
2354 c950a94d Miltiadis Vasilakis
- (void)menuNewFolder:(NSMenuItem *)sender {
2355 c950a94d Miltiadis Vasilakis
    PithosNode *node = (PithosNode *)[sender representedObject];
2356 c950a94d Miltiadis Vasilakis
    if ([node class] == [PithosContainerNode class]) {
2357 d8426ffb Miltiadis Vasilakis
        // Operation: Create (upload) a new root application/directory object
2358 d8426ffb Miltiadis Vasilakis
        __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
2359 b58ff732 Miltiadis Vasilakis
            @autoreleasepool {
2360 b58ff732 Miltiadis Vasilakis
                if (operation.isCancelled)
2361 b58ff732 Miltiadis Vasilakis
                    return;
2362 fb27f368 Miltiadis Vasilakis
                NSString *safeObjectName = [PithosUtilities safeSubdirNameForPithos:pithosAccountManager.pithos
2363 b58ff732 Miltiadis Vasilakis
                                                                      containerName:node.pithosContainer.name 
2364 b58ff732 Miltiadis Vasilakis
                                                                         subdirName:@"untitled folder"];
2365 b58ff732 Miltiadis Vasilakis
                NSString *fileName = [safeObjectName lastPathComponent];
2366 b58ff732 Miltiadis Vasilakis
                if (operation.isCancelled)
2367 b58ff732 Miltiadis Vasilakis
                    return;
2368 fb27f368 Miltiadis Vasilakis
                ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithPithos:pithosAccountManager.pithos
2369 b58ff732 Miltiadis Vasilakis
                                                                                                   containerName:node.pithosContainer.name 
2370 b58ff732 Miltiadis Vasilakis
                                                                                                      objectName:safeObjectName 
2371 b58ff732 Miltiadis Vasilakis
                                                                                                            eTag:nil 
2372 b58ff732 Miltiadis Vasilakis
                                                                                                     contentType:@"application/directory" 
2373 b58ff732 Miltiadis Vasilakis
                                                                                                 contentEncoding:nil 
2374 b58ff732 Miltiadis Vasilakis
                                                                                              contentDisposition:nil 
2375 b58ff732 Miltiadis Vasilakis
                                                                                                        manifest:nil 
2376 b58ff732 Miltiadis Vasilakis
                                                                                                         sharing:nil 
2377 b58ff732 Miltiadis Vasilakis
                                                                                                        isPublic:ASIPithosObjectRequestPublicIgnore 
2378 b58ff732 Miltiadis Vasilakis
                                                                                                        metadata:nil 
2379 b58ff732 Miltiadis Vasilakis
                                                                                                            data:[NSData data]];
2380 b58ff732 Miltiadis Vasilakis
                objectRequest.delegate = self;
2381 b58ff732 Miltiadis Vasilakis
                objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
2382 b58ff732 Miltiadis Vasilakis
                objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
2383 b58ff732 Miltiadis Vasilakis
                NSString *messagePrefix = [NSString stringWithFormat:@"Creating directory '%@'", fileName];
2384 b58ff732 Miltiadis Vasilakis
                PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCreateDirectory 
2385 b58ff732 Miltiadis Vasilakis
                                                                           message:messagePrefix];
2386 b58ff732 Miltiadis Vasilakis
                objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
2387 b58ff732 Miltiadis Vasilakis
                                          fileName, @"fileName", 
2388 b58ff732 Miltiadis Vasilakis
                                          [NSArray arrayWithObject:node], @"refreshNodes", 
2389 b58ff732 Miltiadis Vasilakis
                                          [NSNumber numberWithBool:YES], @"refresh", 
2390 b58ff732 Miltiadis Vasilakis
                                          activity, @"activity", 
2391 b58ff732 Miltiadis Vasilakis
                                          [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
2392 b58ff732 Miltiadis Vasilakis
                                          [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
2393 b58ff732 Miltiadis Vasilakis
                                          [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
2394 b58ff732 Miltiadis Vasilakis
                                          [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
2395 b58ff732 Miltiadis Vasilakis
                                          [NSNumber numberWithUnsignedInteger:10], @"retries", 
2396 b58ff732 Miltiadis Vasilakis
                                          NSStringFromSelector(@selector(uploadDirectoryObjectFinished:)), @"didFinishSelector", 
2397 b58ff732 Miltiadis Vasilakis
                                          NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
2398 b58ff732 Miltiadis Vasilakis
                                          uploadNetworkQueue, @"networkQueue", 
2399 b58ff732 Miltiadis Vasilakis
                                          @"upload", @"operationType", 
2400 b58ff732 Miltiadis Vasilakis
                                          nil];
2401 b58ff732 Miltiadis Vasilakis
                [uploadNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
2402 d8426ffb Miltiadis Vasilakis
            }
2403 d8426ffb Miltiadis Vasilakis
        }];
2404 d8426ffb Miltiadis Vasilakis
        [uploadQueue addOperation:operation];
2405 c950a94d Miltiadis Vasilakis
    } else if (([node class] == [PithosSubdirNode class]) && 
2406 212a7d57 Miltiadis Vasilakis
               (node.pithosObject.subdir || ![node.pithosObject.name hasSuffix:@"/"])) {
2407 d8426ffb Miltiadis Vasilakis
        // Operation: Create (upload) a new aplication/directory object
2408 d8426ffb Miltiadis Vasilakis
        __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
2409 b58ff732 Miltiadis Vasilakis
            @autoreleasepool {
2410 b58ff732 Miltiadis Vasilakis
                if (operation.isCancelled)
2411 b58ff732 Miltiadis Vasilakis
                    return;
2412 fb27f368 Miltiadis Vasilakis
                NSString *safeObjectName = [PithosUtilities safeSubdirNameForPithos:pithosAccountManager.pithos
2413 b58ff732 Miltiadis Vasilakis
                                                                      containerName:node.pithosContainer.name 
2414 b58ff732 Miltiadis Vasilakis
                                                                         subdirName:[node.pithosObject.name stringByAppendingPathComponent:@"untitled folder"]];
2415 b58ff732 Miltiadis Vasilakis
                NSString *fileName = [safeObjectName lastPathComponent];
2416 b58ff732 Miltiadis Vasilakis
                if (operation.isCancelled)
2417 b58ff732 Miltiadis Vasilakis
                    return;
2418 fb27f368 Miltiadis Vasilakis
                ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithPithos:pithosAccountManager.pithos
2419 b58ff732 Miltiadis Vasilakis
                                                                                                   containerName:node.pithosContainer.name 
2420 b58ff732 Miltiadis Vasilakis
                                                                                                      objectName:safeObjectName 
2421 b58ff732 Miltiadis Vasilakis
                                                                                                            eTag:nil
2422 b58ff732 Miltiadis Vasilakis
                                                                                                     contentType:@"application/directory" 
2423 b58ff732 Miltiadis Vasilakis
                                                                                                 contentEncoding:nil 
2424 b58ff732 Miltiadis Vasilakis
                                                                                              contentDisposition:nil 
2425 b58ff732 Miltiadis Vasilakis
                                                                                                        manifest:nil 
2426 b58ff732 Miltiadis Vasilakis
                                                                                                         sharing:nil 
2427 b58ff732 Miltiadis Vasilakis
                                                                                                        isPublic:ASIPithosObjectRequestPublicIgnore 
2428 b58ff732 Miltiadis Vasilakis
                                                                                                        metadata:nil 
2429 b58ff732 Miltiadis Vasilakis
                                                                                                            data:[NSData data]];
2430 b58ff732 Miltiadis Vasilakis
                objectRequest.delegate = self;
2431 b58ff732 Miltiadis Vasilakis
                objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
2432 b58ff732 Miltiadis Vasilakis
                objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
2433 b58ff732 Miltiadis Vasilakis
                NSString *messagePrefix = [NSString stringWithFormat:@"Creating directory '%@'", fileName];
2434 b58ff732 Miltiadis Vasilakis
                PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCreateDirectory 
2435 b58ff732 Miltiadis Vasilakis
                                                                           message:messagePrefix];
2436 b58ff732 Miltiadis Vasilakis
                objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
2437 b58ff732 Miltiadis Vasilakis
                                          fileName, @"fileName", 
2438 b58ff732 Miltiadis Vasilakis
                                          [NSArray arrayWithObject:node], @"refreshNodes", 
2439 b58ff732 Miltiadis Vasilakis
                                          [NSNumber numberWithBool:YES], @"refresh", 
2440 b58ff732 Miltiadis Vasilakis
                                          activity, @"activity", 
2441 b58ff732 Miltiadis Vasilakis
                                          [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
2442 b58ff732 Miltiadis Vasilakis
                                          [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
2443 b58ff732 Miltiadis Vasilakis
                                          [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
2444 b58ff732 Miltiadis Vasilakis
                                          [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
2445 b58ff732 Miltiadis Vasilakis
                                          [NSNumber numberWithUnsignedInteger:10], @"retries", 
2446 b58ff732 Miltiadis Vasilakis
                                          NSStringFromSelector(@selector(uploadDirectoryObjectFinished:)), @"didFinishSelector", 
2447 b58ff732 Miltiadis Vasilakis
                                          NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
2448 b58ff732 Miltiadis Vasilakis
                                          uploadNetworkQueue, @"networkQueue", 
2449 b58ff732 Miltiadis Vasilakis
                                          @"upload", @"operationType", 
2450 b58ff732 Miltiadis Vasilakis
                                          nil];
2451 b58ff732 Miltiadis Vasilakis
                [uploadNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
2452 d8426ffb Miltiadis Vasilakis
            }
2453 d8426ffb Miltiadis Vasilakis
        }];
2454 d8426ffb Miltiadis Vasilakis
        [uploadQueue addOperation:operation];
2455 1ca8da38 Miltiadis Vasilakis
    }
2456 1ca8da38 Miltiadis Vasilakis
}
2457 1ca8da38 Miltiadis Vasilakis
2458 c950a94d Miltiadis Vasilakis
- (void)menuGetInfo:(NSMenuItem *)sender {
2459 1ca8da38 Miltiadis Vasilakis
    for (PithosNode *node in ((NSArray *)[sender representedObject])) {
2460 133b1f2d Miltiadis Vasilakis
        [node showPithosNodeInfo:sender];
2461 133b1f2d Miltiadis Vasilakis
    }
2462 857217b0 Miltiadis Vasilakis
}
2463 857217b0 Miltiadis Vasilakis
2464 de0873d4 Miltiadis Vasilakis
- (void)menuDownload:(NSMenuItem *)sender {
2465 de0873d4 Miltiadis Vasilakis
    NSArray *nodes = (NSArray *)[sender representedObject];
2466 de0873d4 Miltiadis Vasilakis
    PithosNode *firstNode = [nodes objectAtIndex:0];
2467 de0873d4 Miltiadis Vasilakis
    if (([nodes count] == 1) && ([firstNode class] == [PithosObjectNode class])) {
2468 de0873d4 Miltiadis Vasilakis
        NSSavePanel *save = [NSSavePanel savePanel];
2469 de0873d4 Miltiadis Vasilakis
        save.nameFieldStringValue = firstNode.displayName;
2470 b58ff732 Miltiadis Vasilakis
        NSInteger result = [save runModal];
2471 de0873d4 Miltiadis Vasilakis
        if (result == NSOKButton) {
2472 de0873d4 Miltiadis Vasilakis
            NSString *destinationPath = save.URL.path;
2473 de0873d4 Miltiadis Vasilakis
            NSString *directoryPath = [destinationPath stringByDeletingLastPathComponent];
2474 de0873d4 Miltiadis Vasilakis
            NSString *newFileName = [destinationPath lastPathComponent];
2475 de0873d4 Miltiadis Vasilakis
            if ([destinationPath hasSuffix:@"/"])
2476 de0873d4 Miltiadis Vasilakis
                newFileName = [newFileName stringByAppendingString:@"/"];
2477 de0873d4 Miltiadis Vasilakis
            if ([firstNode.displayName isEqualToString:newFileName])
2478 de0873d4 Miltiadis Vasilakis
                newFileName = nil;
2479 de0873d4 Miltiadis Vasilakis
            [self downloadNode:firstNode toDirectory:directoryPath withNewFileName:newFileName version:nil checkIfExists:NO];
2480 de0873d4 Miltiadis Vasilakis
        }
2481 de0873d4 Miltiadis Vasilakis
    } else {
2482 de0873d4 Miltiadis Vasilakis
        NSOpenPanel *open = [NSOpenPanel openPanel];
2483 de0873d4 Miltiadis Vasilakis
        open.canChooseFiles = NO;
2484 de0873d4 Miltiadis Vasilakis
        open.canChooseDirectories = YES;
2485 de0873d4 Miltiadis Vasilakis
        open.canCreateDirectories = YES;
2486 b58ff732 Miltiadis Vasilakis
        NSInteger result = [open runModal];
2487 de0873d4 Miltiadis Vasilakis
        if (result == NSOKButton) {
2488 de0873d4 Miltiadis Vasilakis
            NSString *directoryPath = open.URL.path;
2489 de0873d4 Miltiadis Vasilakis
            for (PithosNode *node in nodes) {
2490 de0873d4 Miltiadis Vasilakis
                [self downloadNode:node toDirectory:directoryPath withNewFileName:nil version:nil checkIfExists:YES];
2491 de0873d4 Miltiadis Vasilakis
            }
2492 de0873d4 Miltiadis Vasilakis
        }
2493 de0873d4 Miltiadis Vasilakis
    }
2494 de0873d4 Miltiadis Vasilakis
}
2495 de0873d4 Miltiadis Vasilakis
2496 c950a94d Miltiadis Vasilakis
- (void)menuDelete:(NSMenuItem *)sender {
2497 1ca8da38 Miltiadis Vasilakis
    for (PithosNode *node in ((NSArray *)[sender representedObject])) {
2498 133b1f2d Miltiadis Vasilakis
        if (([node class] == [PithosObjectNode class]) || 
2499 212a7d57 Miltiadis Vasilakis
            (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) {
2500 d8426ffb Miltiadis Vasilakis
            // Operation: Delete an object or subdir/ node
2501 d8426ffb Miltiadis Vasilakis
            __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
2502 b58ff732 Miltiadis Vasilakis
                @autoreleasepool {
2503 b58ff732 Miltiadis Vasilakis
                    if (operation.isCancelled)
2504 b58ff732 Miltiadis Vasilakis
                        return;
2505 b58ff732 Miltiadis Vasilakis
                    NSString *fileName = [node.pithosObject.name lastPathComponent];
2506 b58ff732 Miltiadis Vasilakis
                    if ([node.pithosObject.name hasSuffix:@"/"])
2507 b58ff732 Miltiadis Vasilakis
                        fileName = [fileName stringByAppendingString:@"/"];
2508 fb27f368 Miltiadis Vasilakis
                    ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest deleteObjectRequestWithPithos:pithosAccountManager.pithos
2509 b58ff732 Miltiadis Vasilakis
                                                                                                    containerName:node.pithosContainer.name 
2510 b58ff732 Miltiadis Vasilakis
                                                                                                       objectName:node.pithosObject.name];
2511 b58ff732 Miltiadis Vasilakis
                    if (operation.isCancelled)
2512 b58ff732 Miltiadis Vasilakis
                        return;
2513 b58ff732 Miltiadis Vasilakis
                    objectRequest.delegate = self;
2514 b58ff732 Miltiadis Vasilakis
                    objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
2515 b58ff732 Miltiadis Vasilakis
                    objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
2516 b58ff732 Miltiadis Vasilakis
                    NSString *messagePrefix = [NSString stringWithFormat:@"Deleting '%@'", fileName];
2517 b58ff732 Miltiadis Vasilakis
                    PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDelete 
2518 b58ff732 Miltiadis Vasilakis
                                                                               message:messagePrefix];
2519 b58ff732 Miltiadis Vasilakis
                    objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
2520 b58ff732 Miltiadis Vasilakis
                                              fileName, @"fileName", 
2521 b58ff732 Miltiadis Vasilakis
                                              [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", 
2522 b58ff732 Miltiadis Vasilakis
                                              activity, @"activity", 
2523 b58ff732 Miltiadis Vasilakis
                                              [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
2524 b58ff732 Miltiadis Vasilakis
                                              [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
2525 b58ff732 Miltiadis Vasilakis
                                              [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
2526 b58ff732 Miltiadis Vasilakis
                                              [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
2527 b58ff732 Miltiadis Vasilakis
                                              [NSNumber numberWithUnsignedInteger:10], @"retries", 
2528 b58ff732 Miltiadis Vasilakis
                                              NSStringFromSelector(@selector(deleteObjectFinished:)), @"didFinishSelector", 
2529 b58ff732 Miltiadis Vasilakis
                                              NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
2530 b58ff732 Miltiadis Vasilakis
                                              deleteNetworkQueue, @"networkQueue", 
2531 b58ff732 Miltiadis Vasilakis
                                              @"delete", @"operationType", 
2532 b58ff732 Miltiadis Vasilakis
                                              nil];
2533 b58ff732 Miltiadis Vasilakis
                    [deleteNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
2534 d8426ffb Miltiadis Vasilakis
                }
2535 d8426ffb Miltiadis Vasilakis
            }];
2536 d8426ffb Miltiadis Vasilakis
            [deleteQueue addOperation:operation];
2537 133b1f2d Miltiadis Vasilakis
        } else if ([node class] == [PithosSubdirNode class]) {
2538 d8426ffb Miltiadis Vasilakis
            // Operation: Delete a subdir node and its descendants
2539 d8426ffb Miltiadis Vasilakis
            // The resulting ASIPithosObjectRequests are chained through dependencies
2540 d8426ffb Miltiadis Vasilakis
            __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
2541 b58ff732 Miltiadis Vasilakis
                @autoreleasepool {
2542 b58ff732 Miltiadis Vasilakis
                    if (operation.isCancelled)
2543 b58ff732 Miltiadis Vasilakis
                        return;
2544 fb27f368 Miltiadis Vasilakis
                    NSArray *objectRequests = [PithosUtilities deleteObjectRequestsForSubdirWithPithos:pithosAccountManager.pithos
2545 b58ff732 Miltiadis Vasilakis
                                                                                         containerName:node.pithosContainer.name 
2546 b58ff732 Miltiadis Vasilakis
                                                                                            objectName:node.pithosObject.name];
2547 b58ff732 Miltiadis Vasilakis
                    if (!operation.isCancelled && objectRequests) {
2548 b58ff732 Miltiadis Vasilakis
                        ASIPithosObjectRequest *previousObjectRequest = nil;
2549 b58ff732 Miltiadis Vasilakis
                        for (ASIPithosObjectRequest *objectRequest in objectRequests) {
2550 b58ff732 Miltiadis Vasilakis
                            if (operation.isCancelled)
2551 b58ff732 Miltiadis Vasilakis
                                return;
2552 b58ff732 Miltiadis Vasilakis
                            objectRequest.delegate = self;
2553 b58ff732 Miltiadis Vasilakis
                            objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
2554 b58ff732 Miltiadis Vasilakis
                            objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
2555 b58ff732 Miltiadis Vasilakis
                            NSString *messagePrefix = [NSString stringWithFormat:@"Deleting '%@'", [objectRequest.userInfo objectForKey:@"fileName"]];
2556 b58ff732 Miltiadis Vasilakis
                            PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDelete 
2557 b58ff732 Miltiadis Vasilakis
                                                                                       message:messagePrefix];
2558 b58ff732 Miltiadis Vasilakis
                            [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
2559 b58ff732 Miltiadis Vasilakis
                             [NSDictionary dictionaryWithObjectsAndKeys:
2560 b58ff732 Miltiadis Vasilakis
                              [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", 
2561 b58ff732 Miltiadis Vasilakis
                              activity, @"activity", 
2562 b58ff732 Miltiadis Vasilakis
                              [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
2563 b58ff732 Miltiadis Vasilakis
                              [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
2564 b58ff732 Miltiadis Vasilakis
                              [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
2565 b58ff732 Miltiadis Vasilakis
                              [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
2566 b58ff732 Miltiadis Vasilakis
                              [NSNumber numberWithUnsignedInteger:10], @"retries", 
2567 b58ff732 Miltiadis Vasilakis
                              NSStringFromSelector(@selector(deleteObjectFinished:)), @"didFinishSelector", 
2568 b58ff732 Miltiadis Vasilakis
                              NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
2569 b58ff732 Miltiadis Vasilakis
                              deleteNetworkQueue, @"networkQueue", 
2570 b58ff732 Miltiadis Vasilakis
                              @"delete", @"operationType", 
2571 b58ff732 Miltiadis Vasilakis
                              nil]];
2572 b58ff732 Miltiadis Vasilakis
                            if (previousObjectRequest)
2573 b58ff732 Miltiadis Vasilakis
                                [objectRequest addDependency:previousObjectRequest];
2574 b58ff732 Miltiadis Vasilakis
                            previousObjectRequest = objectRequest;
2575 b58ff732 Miltiadis Vasilakis
                            [deleteNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
2576 d8426ffb Miltiadis Vasilakis
                        }
2577 1ca8da38 Miltiadis Vasilakis
                    }
2578 6a9b9f40 Miltiadis Vasilakis
                }
2579 d8426ffb Miltiadis Vasilakis
            }];
2580 d8426ffb Miltiadis Vasilakis
            [deleteQueue addOperation:operation];
2581 133b1f2d Miltiadis Vasilakis
        }
2582 133b1f2d Miltiadis Vasilakis
    }
2583 133b1f2d Miltiadis Vasilakis
}
2584 133b1f2d Miltiadis Vasilakis
2585 c950a94d Miltiadis Vasilakis
- (void)menuMoveToTrash:(NSMenuItem *)sender {
2586 1ca8da38 Miltiadis Vasilakis
    for (PithosNode *node in ((NSArray *)[sender representedObject])) {
2587 133b1f2d Miltiadis Vasilakis
        if (([node class] == [PithosObjectNode class]) || 
2588 133b1f2d Miltiadis Vasilakis
            (([node class] == [PithosSubdirNode class]) && 
2589 133b1f2d Miltiadis Vasilakis
             !node.pithosObject.subdir &&
2590 133b1f2d Miltiadis Vasilakis
             [node.pithosObject.name hasSuffix:@"/"])) {
2591 d8426ffb Miltiadis Vasilakis
            // Operation: Move to trash an object or subdir/ node
2592 d8426ffb Miltiadis Vasilakis
            __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
2593 b58ff732 Miltiadis Vasilakis
                @autoreleasepool {
2594 b58ff732 Miltiadis Vasilakis
                    if (operation.isCancelled)
2595 b58ff732 Miltiadis Vasilakis
                        return;
2596 fb27f368 Miltiadis Vasilakis
                    NSString *safeObjectName = [PithosUtilities safeObjectNameForPithos:pithosAccountManager.pithos
2597 b58ff732 Miltiadis Vasilakis
                                                                          containerName:@"trash" 
2598 b58ff732 Miltiadis Vasilakis
                                                                             objectName:node.pithosObject.name];
2599 b58ff732 Miltiadis Vasilakis
                    if (!operation.isCancelled && safeObjectName) {
2600 fb27f368 Miltiadis Vasilakis
                        ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithPithos:pithosAccountManager.pithos
2601 b58ff732 Miltiadis Vasilakis
                                                                                               containerName:node.pithosContainer.name 
2602 b58ff732 Miltiadis Vasilakis
                                                                                                  objectName:node.pithosObject.name 
2603 b58ff732 Miltiadis Vasilakis
                                                                                    destinationContainerName:@"trash" 
2604 b58ff732 Miltiadis Vasilakis
                                                                                       destinationObjectName:safeObjectName 
2605 b58ff732 Miltiadis Vasilakis
                                                                                               checkIfExists:NO];
2606 b58ff732 Miltiadis Vasilakis
                        if (!operation.isCancelled && objectRequest) {
2607 1ca8da38 Miltiadis Vasilakis
                            objectRequest.delegate = self;
2608 4c1c46fd Miltiadis Vasilakis
                            objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
2609 4c1c46fd Miltiadis Vasilakis
                            objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
2610 4c1c46fd Miltiadis Vasilakis
                            NSString *messagePrefix = [NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", 
2611 4c1c46fd Miltiadis Vasilakis
                                                       [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
2612 4c1c46fd Miltiadis Vasilakis
                                                       [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
2613 4c1c46fd Miltiadis Vasilakis
                                                       [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
2614 4c1c46fd Miltiadis Vasilakis
                                                       [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
2615 212a7d57 Miltiadis Vasilakis
                            PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove 
2616 4c1c46fd Miltiadis Vasilakis
                                                                                       message:messagePrefix];
2617 212a7d57 Miltiadis Vasilakis
                            [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
2618 212a7d57 Miltiadis Vasilakis
                             [NSDictionary dictionaryWithObjectsAndKeys:
2619 212a7d57 Miltiadis Vasilakis
                              [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", 
2620 212a7d57 Miltiadis Vasilakis
                              activity, @"activity", 
2621 4c1c46fd Miltiadis Vasilakis
                              [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
2622 4c1c46fd Miltiadis Vasilakis
                              [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
2623 4c1c46fd Miltiadis Vasilakis
                              [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
2624 4c1c46fd Miltiadis Vasilakis
                              [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
2625 212a7d57 Miltiadis Vasilakis
                              [NSNumber numberWithUnsignedInteger:10], @"retries", 
2626 4c1c46fd Miltiadis Vasilakis
                              NSStringFromSelector(@selector(moveFinished:)), @"didFinishSelector", 
2627 4c1c46fd Miltiadis Vasilakis
                              NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
2628 4c1c46fd Miltiadis Vasilakis
                              moveNetworkQueue, @"networkQueue", 
2629 d8426ffb Miltiadis Vasilakis
                              @"move", @"operationType", 
2630 212a7d57 Miltiadis Vasilakis
                              nil]];
2631 4c1c46fd Miltiadis Vasilakis
                            [moveNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
2632 1ca8da38 Miltiadis Vasilakis
                        }
2633 133b1f2d Miltiadis Vasilakis
                    }
2634 133b1f2d Miltiadis Vasilakis
                }
2635 b58ff732 Miltiadis Vasilakis
            }];
2636 b58ff732 Miltiadis Vasilakis
            [moveQueue addOperation:operation];
2637 b58ff732 Miltiadis Vasilakis
        } else if ([node class] == [PithosSubdirNode class]) {
2638 b58ff732 Miltiadis Vasilakis
            // Operation: Move to trash a subdir node and its descendants
2639 b58ff732 Miltiadis Vasilakis
            // The resulting ASIPithosObjectRequests are chained through dependencies
2640 b58ff732 Miltiadis Vasilakis
            __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
2641 b58ff732 Miltiadis Vasilakis
                @autoreleasepool {
2642 b58ff732 Miltiadis Vasilakis
                    if (operation.isCancelled)
2643 b58ff732 Miltiadis Vasilakis
                        return;
2644 fb27f368 Miltiadis Vasilakis
                    NSString *safeObjectName = [PithosUtilities safeSubdirNameForPithos:pithosAccountManager.pithos
2645 b58ff732 Miltiadis Vasilakis
                                                                          containerName:@"trash" 
2646 b58ff732 Miltiadis Vasilakis
                                                                             subdirName:node.pithosObject.name];
2647 b58ff732 Miltiadis Vasilakis
                    if (!operation.isCancelled && safeObjectName) {
2648 fb27f368 Miltiadis Vasilakis
                        NSArray *objectRequests = [PithosUtilities moveObjectRequestsForSubdirWithPithos:pithosAccountManager.pithos
2649 b58ff732 Miltiadis Vasilakis
                                                                                           containerName:node.pithosContainer.name 
2650 b58ff732 Miltiadis Vasilakis
                                                                                              objectName:node.pithosObject.name 
2651 b58ff732 Miltiadis Vasilakis
                                                                                destinationContainerName:@"trash" 
2652 b58ff732 Miltiadis Vasilakis
                                                                                   destinationObjectName:safeObjectName 
2653 b58ff732 Miltiadis Vasilakis
                                                                                           checkIfExists:NO];
2654 b58ff732 Miltiadis Vasilakis
                        if (!operation.isCancelled && objectRequests) {
2655 b58ff732 Miltiadis Vasilakis
                            ASIPithosObjectRequest *previousObjectRequest = nil;
2656 b58ff732 Miltiadis Vasilakis
                            for (ASIPithosObjectRequest *objectRequest in objectRequests) {
2657 b58ff732 Miltiadis Vasilakis
                                if (operation.isCancelled)
2658 b58ff732 Miltiadis Vasilakis
                                    return;
2659 b58ff732 Miltiadis Vasilakis
                                objectRequest.delegate = self;
2660 b58ff732 Miltiadis Vasilakis
                                objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
2661 b58ff732 Miltiadis Vasilakis
                                objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
2662 b58ff732 Miltiadis Vasilakis
                                NSString *messagePrefix = [NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", 
2663 b58ff732 Miltiadis Vasilakis
                                                           [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
2664 b58ff732 Miltiadis Vasilakis
                                                           [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
2665 b58ff732 Miltiadis Vasilakis
                                                           [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
2666 b58ff732 Miltiadis Vasilakis
                                                           [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
2667 b58ff732 Miltiadis Vasilakis
                                PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove 
2668 b58ff732 Miltiadis Vasilakis
                                                                                           message:messagePrefix];
2669 b58ff732 Miltiadis Vasilakis
                                [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
2670 b58ff732 Miltiadis Vasilakis
                                 [NSDictionary dictionaryWithObjectsAndKeys:
2671 b58ff732 Miltiadis Vasilakis
                                  [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", 
2672 b58ff732 Miltiadis Vasilakis
                                  activity, @"activity", 
2673 b58ff732 Miltiadis Vasilakis
                                  [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
2674 b58ff732 Miltiadis Vasilakis
                                  [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
2675 b58ff732 Miltiadis Vasilakis
                                  [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
2676 b58ff732 Miltiadis Vasilakis
                                  [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
2677 b58ff732 Miltiadis Vasilakis
                                  [NSNumber numberWithUnsignedInteger:10], @"retries", 
2678 b58ff732 Miltiadis Vasilakis
                                  NSStringFromSelector(@selector(moveFinished:)), @"didFinishSelector", 
2679 b58ff732 Miltiadis Vasilakis
                                  NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
2680 b58ff732 Miltiadis Vasilakis
                                  moveNetworkQueue, @"networkQueue", 
2681 b58ff732 Miltiadis Vasilakis
                                  @"move", @"operationType", 
2682 b58ff732 Miltiadis Vasilakis
                                  nil]];
2683 b58ff732 Miltiadis Vasilakis
                                if (previousObjectRequest)
2684 b58ff732 Miltiadis Vasilakis
                                    [objectRequest addDependency:previousObjectRequest];
2685 b58ff732 Miltiadis Vasilakis
                                previousObjectRequest = objectRequest;
2686 b58ff732 Miltiadis Vasilakis
                                [moveNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
2687 b58ff732 Miltiadis Vasilakis
                            }
2688 b58ff732 Miltiadis Vasilakis
                        }
2689 b58ff732 Miltiadis Vasilakis
                    }
2690 b58ff732 Miltiadis Vasilakis
                }
2691 d8426ffb Miltiadis Vasilakis
            }];
2692 d8426ffb Miltiadis Vasilakis
            [moveQueue addOperation:operation];
2693 133b1f2d Miltiadis Vasilakis
        }
2694 6a9b9f40 Miltiadis Vasilakis
    }
2695 6a9b9f40 Miltiadis Vasilakis
}
2696 6a9b9f40 Miltiadis Vasilakis
2697 c950a94d Miltiadis Vasilakis
- (void)menuCut:(NSMenuItem *)sender {
2698 c950a94d Miltiadis Vasilakis
    self.clipboardNodes = (NSArray *)[sender representedObject];
2699 c950a94d Miltiadis Vasilakis
    self.clipboardParentNode = ((PithosNode *)[clipboardNodes objectAtIndex:0]).parent;
2700 c950a94d Miltiadis Vasilakis
    self.clipboardCopy = NO;
2701 c950a94d Miltiadis Vasilakis
}
2702 c950a94d Miltiadis Vasilakis
2703 c950a94d Miltiadis Vasilakis
- (void)menuCopy:(NSMenuItem *)sender {
2704 c950a94d Miltiadis Vasilakis
    self.clipboardNodes = (NSArray *)[sender representedObject];
2705 c950a94d Miltiadis Vasilakis
    self.clipboardParentNode = ((PithosNode *)[clipboardNodes objectAtIndex:0]).parent;
2706 c950a94d Miltiadis Vasilakis
    self.clipboardCopy = YES;
2707 c950a94d Miltiadis Vasilakis
}
2708 c950a94d Miltiadis Vasilakis
2709 c950a94d Miltiadis Vasilakis
- (void)menuPaste:(NSMenuItem *)sender {
2710 c950a94d Miltiadis Vasilakis
    if (!clipboardNodes || ![clipboardNodes count])
2711 c950a94d Miltiadis Vasilakis
        return;
2712 c950a94d Miltiadis Vasilakis
    PithosNode *dropNode = (PithosNode *)[sender representedObject];
2713 c950a94d Miltiadis Vasilakis
    NSArray *localClipboardNodes = [NSArray arrayWithArray:clipboardNodes];
2714 c2896649 Miltiadis Vasilakis
    if (clipboardCopy) {
2715 3f220848 Miltiadis Vasilakis
        [self cpyNodes:localClipboardNodes toNode:dropNode];
2716 c2896649 Miltiadis Vasilakis
    } else if (![dropNode isEqualTo:clipboardParentNode]) {
2717 c950a94d Miltiadis Vasilakis
        self.clipboardNodes = nil;
2718 c950a94d Miltiadis Vasilakis
        self.clipboardParentNode = nil;
2719 1b1e6fa1 Miltiadis Vasilakis
        [self moveNodes:localClipboardNodes toNode:dropNode];
2720 c950a94d Miltiadis Vasilakis
    }
2721 c950a94d Miltiadis Vasilakis
}
2722 c950a94d Miltiadis Vasilakis
    
2723 6a9b9f40 Miltiadis Vasilakis
#pragma mark -
2724 470e6f81 Miltiadis Vasilakis
#pragma mark PithosActivityFacilityDelegate
2725 470e6f81 Miltiadis Vasilakis
2726 470e6f81 Miltiadis Vasilakis
- (void)activityUpdate:(NSDictionary *)info {
2727 470e6f81 Miltiadis Vasilakis
    NSString *message = [info objectForKey:@"message"];
2728 470e6f81 Miltiadis Vasilakis
    NSUInteger runningActivitiesCount = [[info objectForKey:@"runningActivitiesCount"] unsignedIntegerValue];
2729 470e6f81 Miltiadis Vasilakis
//    NSUInteger endingActivitiesCount = [[info objectForKey:@"endingActivitiesCount"] unsignedIntegerValue];
2730 470e6f81 Miltiadis Vasilakis
    NSUInteger totalUploadBytes = [[info objectForKey:@"totalUploadBytes"] unsignedIntegerValue];
2731 470e6f81 Miltiadis Vasilakis
    NSUInteger currentUploadBytes = [[info objectForKey:@"currentUploadBytes"] unsignedIntegerValue];
2732 470e6f81 Miltiadis Vasilakis
    NSUInteger totalDownloadBytes = [[info objectForKey:@"totalDownloadBytes"] unsignedIntegerValue];
2733 470e6f81 Miltiadis Vasilakis
    NSUInteger currentDownloadBytes = [[info objectForKey:@"currentDownloadBytes"] unsignedIntegerValue];
2734 470e6f81 Miltiadis Vasilakis
    NSUInteger totalBytes = totalUploadBytes + totalDownloadBytes;
2735 470e6f81 Miltiadis Vasilakis
    if (runningActivitiesCount && totalBytes) {
2736 470e6f81 Miltiadis Vasilakis
        [activityProgressIndicator setDoubleValue:((currentUploadBytes + currentDownloadBytes + 0.0)/(totalBytes + 0.0))];
2737 470e6f81 Miltiadis Vasilakis
        [activityProgressIndicator startAnimation:self];
2738 470e6f81 Miltiadis Vasilakis
    } else {
2739 470e6f81 Miltiadis Vasilakis
        [activityProgressIndicator setDoubleValue:1.0];
2740 470e6f81 Miltiadis Vasilakis
        [activityProgressIndicator stopAnimation:self];
2741 470e6f81 Miltiadis Vasilakis
    }
2742 470e6f81 Miltiadis Vasilakis
    
2743 470e6f81 Miltiadis Vasilakis
    if (!message)
2744 cb6abe72 Miltiadis Vasilakis
        message = [[[UsingSizeTransformer alloc] init] transformedValue:accountNode.pithosAccount];
2745 470e6f81 Miltiadis Vasilakis
    [activityTextField setStringValue:message];
2746 470e6f81 Miltiadis Vasilakis
}
2747 6a9b9f40 Miltiadis Vasilakis
2748 e5fdf4d9 Miltiadis Vasilakis
@end