Statistics
| Branch: | Tag: | Revision:

root / Classes / FolderViewController.m @ aa2cf4d7

History | View | Annotate | Download (21.3 kB)

1
//
2
//  FolderViewController.m
3
//  OpenStack
4
//
5
//  Created by Mike Mayo on 12/15/10.
6
//  The OpenStack project is provided under the Apache 2.0 license.
7
//
8

    
9
#import "FolderViewController.h"
10
#import "OpenStackAccount.h"
11
#import "Container.h"
12
#import "Folder.h"
13
#import "StorageObject.h"
14
#import "StorageObjectViewController.h"
15
#import "ContainerDetailViewController.h"
16
#import "AccountManager.h"
17
#import "ActivityIndicatorView.h"
18
#import "ContainersViewController.h"
19
#import "UIViewController+Conveniences.h"
20
#import "AddObjectViewController.h"
21
#import "OpenStackAppDelegate.h"
22
#import "RootViewController.h"
23
#import "FolderDetailViewController.h"
24
#import "AccountHomeViewController.h"
25
#import "PithosImageViewController.h"
26
#import "OpenStackRequest.h"
27
#import "JSON.h"
28
#import "APICallback.h"
29
#import "OpenStackAppDelegate.h"
30
#import <MobileCoreServices/MobileCoreServices.h>
31
#import "ComputeModel.h"
32

    
33
@implementation FolderViewController
34

    
35
@synthesize account, container, folder, containersViewController, selectedContainerIndexPath, contentsLoaded, parentFolderViewController, selectedFolderIndexPath, tableView, needsRefreshing, folderHasBeenRemoved, refreshWhenAppeared, folderDetailVC, selectedObjectViewController, refreshButton;
36

    
37
#pragma mark - View lifecycle
38

    
39
- (void)viewDidLoad {
40
    [super viewDidLoad];
41
    [self addAddButton];
42
    [self addHomeButton];
43
}
44

    
45
- (void)viewWillAppear:(BOOL)animated {
46
    [super viewWillAppear:animated];
47
    if (folder.name && ![@"" isEqualToString:folder.name]) {
48
        self.navigationItem.title = self.folder.name;
49
    } else {
50
        self.navigationItem.title = self.container.name;
51
    }
52
    self.selectedObjectViewController = nil;
53
}
54

    
55
- (void)viewDidAppear:(BOOL)animated {
56
    [super viewDidAppear:animated];
57
    if (!self.folder) {
58
        if (folderHasBeenRemoved) {
59
            if (needsRefreshing) 
60
                self.parentFolderViewController.needsRefreshing = YES;
61
            [self.navigationController popViewControllerAnimated:YES];
62
        } else {
63
            [self refreshButtonPressed:nil];
64
        }
65
    } else if (self.needsRefreshing) {
66
        self.parentFolderViewController.needsRefreshing = YES;
67
        if (refreshWhenAppeared) {
68
            [self refreshButtonPressed:nil];
69
            refreshWhenAppeared = NO;
70
        }
71
        if (account.shared && ([folder.folders count] + [folder.objects count] == 0)) {
72
            [self.navigationController popViewControllerAnimated:YES];
73
        }
74
    }
75
}
76

    
77
- (void)viewWillDisappear:(BOOL)animated {
78
    [super viewWillDisappear:animated];
79
    if (![self.navigationController.viewControllers containsObject:self] &&
80
        self.parentViewController &&
81
        (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)) {
82
        [parentFolderViewController setDetailViewController];
83
    }
84
}
85

    
86
#pragma mark - Memory management
87

    
88
- (void)dealloc {
89
    [account release];
90
    [container release];
91
    [folder release];
92
    [containersViewController release];
93
    [selectedContainerIndexPath release];
94
    [parentFolderViewController release];
95
    [selectedFolderIndexPath release];
96
    [refreshButton release];
97
    [super dealloc];
98
}
99

    
100
#pragma mark - Internal
101

    
102
- (void)reloadFolderViewControllers {
103
    NSArray *viewControllers = [self.navigationController viewControllers];
104
    
105
    int rootFolderControllerIndex = [viewControllers indexOfObject:self.containersViewController] + 1;
106
    FolderViewController *rootFolderViewController = [viewControllers objectAtIndex:rootFolderControllerIndex];
107
    rootFolderViewController.folder = self.container.rootFolder;
108
    [rootFolderViewController.tableView reloadData];
109
    
110
    for (int i = rootFolderControllerIndex + 1; i < [viewControllers count]; i++) {
111
        FolderViewController *folderViewController = [viewControllers objectAtIndex:i];
112
        Folder *parentFolder = folderViewController.parentFolderViewController.folder;
113
        
114
        folderViewController.folder = [parentFolder.folders objectForKey:folderViewController.folder.name];
115
        if (folderViewController.folder) {
116
            [folderViewController.tableView reloadData];
117
        } else {
118
            folderViewController.folderHasBeenRemoved = YES;
119
        }
120
    }
121
    if (!self.folder || (account.shared && [folder.folders count] + [folder.objects count] == 0)) {
122
        if (needsRefreshing && self.parentFolderViewController) {
123
            self.parentFolderViewController.needsRefreshing = YES;
124
        }
125
        [self.navigationController popViewControllerAnimated:YES];
126
    } else if ((UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) && account.shared) {
127
        [self setDetailViewController];
128
    }
129
}
130

    
131
#pragma mark - Actions
132

    
133
- (void)setDetailViewController {
134
    if ([self.folder isEqual:self.container.rootFolder]) {
135
        ContainerDetailViewController *vc = [[ContainerDetailViewController alloc] initWithNibName:@"ContainerDetailViewController" bundle:nil];
136
        vc.account = self.account;
137
        vc.container = self.container;
138
        vc.containersViewController = self.containersViewController;
139
        vc.rootFolderViewController = self;
140
        vc.selectedContainerIndexPath = self.selectedContainerIndexPath;
141
        [self presentPrimaryViewController:vc];
142
        self.containersViewController.containerDetailViewController = vc;
143
        [vc release];
144
    } else {
145
        FolderDetailViewController *vc = [[FolderDetailViewController alloc] initWithNibName:@"FolderDetailViewController" bundle:nil];
146
        vc.account = self.account;
147
        vc.container = self.container;
148
        vc.folder = self.folder;
149
        vc.folderViewController = self.parentFolderViewController;
150
        [self presentPrimaryViewController:vc];
151
        self.parentFolderViewController.folderDetailVC = vc;
152
        [vc release];
153
    }
154
}
155

    
156
#pragma mark - UITableViewDataSource
157

    
158
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
159
    return MAX(contentsLoaded ? 1 : 0, [folder.objects count] + [folder.folders count]);
160
}
161

    
162
- (CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
163
    if ([folder.objects count] + [folder.folders count] == 0) {
164
        aTableView.scrollEnabled = NO;
165
        aTableView.allowsSelection = NO;
166
        return aTableView.frame.size.height;
167
    } else {
168
        aTableView.scrollEnabled = YES;
169
        aTableView.allowsSelection = YES;
170
        return aTableView.rowHeight;
171
    }
172
}
173

    
174
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
175
    if ([folder.objects count] + [folder.folders count] == 0) {
176
        NSString *noFoldersTitle = (self.account.shared || self.account.sharingAccount) ?
177
        @"No shared Files or Folders" : @"No Files or Folders";
178
        NSString *noFoldersSubtitle = (self.account.shared || self.account.sharingAccount || [self.folder.name hasSuffix:@"/"]) ?
179
        @"" : @"Tap the + button to create a new one";
180
        NSString *deleteFolderButtonTitle = (self.account.shared || self.account.sharingAccount) ?
181
        nil : @"Delete Folder";
182
        SEL deleteButtonSelector = (self.account.shared || self.account.sharingAccount) ? nil : @selector(deleteButtonPressed:);
183
        self.navigationItem.rightBarButtonItem.enabled = (self.account.shared || [self.folder.name hasSuffix:@"/"]) ? NO : YES;
184
        
185
        if ([self.container.rootFolder isEqual:self.folder]) {
186
            return [self tableView:aTableView
187
                emptyCellWithImage:[UIImage imageNamed:@"empty-files.png"]
188
                             title:noFoldersTitle
189
                          subtitle:noFoldersSubtitle];
190
        } else {
191
            return [self tableView:aTableView
192
                emptyCellWithImage:[UIImage imageNamed:@"empty-files.png"]
193
                             title:noFoldersTitle
194
                          subtitle:noFoldersSubtitle
195
                 deleteButtonTitle:deleteFolderButtonTitle
196
              deleteButtonSelector:deleteButtonSelector];
197
        }
198
    } else {
199
        static NSString *CellIdentifier = @"Cell";
200
        
201
        UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
202
        if (cell == nil) {
203
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
204
        }
205
        
206
        id item = [[self.folder sortedContents] objectAtIndex:indexPath.row];
207
        [cell.textLabel setLineBreakMode:UILineBreakModeTailTruncation];
208
        cell.textLabel.text = [item name];
209
        
210
        if ([[item class] isEqual:[Folder class]]) {
211
            if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
212
                cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
213
            } else {
214
                cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
215
            }
216
            cell.imageView.image = [UIImage imageNamed:@"folder-icon.png"];
217
            
218
            NSString *folderString = @"";
219
            NSString *objectString = @"";
220
            if ([[item folders] count] > 1) {
221
                folderString = [NSString stringWithFormat:@"%i folders, ", [[item folders] count]];
222
            } else if ([[item folders] count] > 0) {
223
                folderString = @"1 folder, ";
224
            }
225
            if ([[item objects] count] != 1) {
226
                objectString = [NSString stringWithFormat:@"%i objects", [[item objects] count]];
227
            } else if ([[item objects] count]) {
228
                objectString = @"1 object";
229
            }
230
            cell.detailTextLabel.text = [NSString stringWithFormat:@"%@%@", folderString, objectString];
231
        } else if ([[item class] isEqual:[StorageObject class]]) {
232
            [cell.textLabel setLineBreakMode:UILineBreakModeMiddleTruncation];
233
            cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
234
            
235
            StorageObject *object = item;
236
            CFStringRef mimeType = (CFStringRef)object.contentType;
237
            CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
238
            NSString *emptyPath = [[NSBundle mainBundle] pathForResource:@"empty-file" ofType:@""];
239
            UIDocumentInteractionController *udic = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:emptyPath]];
240
            if (((NSString *)uti).length > 0)
241
                udic.UTI = (NSString *)uti;
242
            if ([udic.icons count] > 0) 
243
                cell.imageView.image = [udic.icons objectAtIndex:0];
244
            if ([item lastModifiedString])
245
                cell.detailTextLabel.text = [NSString stringWithFormat:@"%@, %@", [item humanizedBytes], [item lastModifiedString]];
246
            else
247
                cell.detailTextLabel.text = [item humanizedBytes];
248
        }
249
        
250
        return cell;
251
    }        
252
}
253

    
254
#pragma mark - UITableViewDelegate
255

    
256
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
257
    if ([folder.objects count] + [folder.folders count] > 0) {
258
        id item = [self.folder.sortedContents objectAtIndex:indexPath.row];        
259
        if ([[item class] isEqual:[Folder class]]) {
260
            FolderViewController *vc = [[FolderViewController alloc] initWithNibName:@"FolderViewController" bundle:nil];
261
            vc.account = self.account;
262
            vc.container = self.container;
263
            vc.folder = item;
264
            vc.contentsLoaded = YES;
265
            vc.selectedFolderIndexPath = indexPath;
266
            vc.parentFolderViewController = self;
267
            vc.containersViewController = self.containersViewController;
268
            [self.navigationController pushViewController:vc animated:YES];
269
            [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
270
            if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
271
                Folder *folderForDetailView;
272
                if ([folder.sortedContents count] > 0) {
273
                    folderForDetailView = [self.folder.sortedContents objectAtIndex:indexPath.row];
274
                } else {
275
                    folderForDetailView = nil;
276
                }
277
                FolderDetailViewController *folderDetailViewController = [[FolderDetailViewController alloc] initWithNibName:@"FolderDetailViewController" bundle:nil];
278
                folderDetailViewController.account = account;
279
                folderDetailViewController.container = container;
280
                folderDetailViewController.folder = folderForDetailView;
281
                folderDetailViewController.folderViewController = vc;
282
                [self presentPrimaryViewController:folderDetailViewController];
283
                self.folderDetailVC = folderDetailViewController;
284
                [folderDetailViewController release];
285
            }
286
            [vc release];
287
        } else if ([[item class] isEqual:[StorageObject class]]) {
288
            StorageObjectViewController *vc = [[StorageObjectViewController alloc] initWithNibName:@"StorageObjectViewController" bundle:nil];
289
            vc.account = self.account;
290
            vc.container = self.container;
291
            vc.folder = self.folder;
292
            vc.object = item;
293
            vc.folderViewController = self;
294
            vc.selectedIndexPath = indexPath;
295
            [self presentPrimaryViewController:vc];
296
            if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
297
                self.selectedObjectViewController = vc;
298
                OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate];
299
                if (app.rootViewController.popoverController != nil) {
300
                    [app.rootViewController.popoverController dismissPopoverAnimated:YES];
301
                }
302
            } else {
303
                [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
304
            }
305
            [vc release];
306
        }
307
    }
308
}
309

    
310
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
311
    Folder *folderForDetailView;
312
    if ([folder.sortedContents count] > 0) {
313
        folderForDetailView = [self.folder.sortedContents objectAtIndex:indexPath.row];
314
    } else {
315
        folderForDetailView = nil;
316
    }
317
    FolderDetailViewController *vc = [[FolderDetailViewController alloc] initWithNibName:@"FolderDetailViewController" bundle:nil];
318
    vc.account = account;
319
    vc.container = container;
320
    vc.folder = folderForDetailView;
321
    vc.folderViewController = self;
322
    [self.navigationController pushViewController:vc animated:YES];
323
    [vc release];
324
}
325

    
326
#pragma mark - Button Handlers
327

    
328
- (IBAction)homeButtonPressed:(id)sender {
329
    [self.navigationController popToViewController:containersViewController.accountHomeViewController animated:YES];
330
}
331

    
332
- (IBAction)refreshButtonPressed:(id)sender {
333
    activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:@"Loading..."] text:@"Loading..."];
334
    [activityIndicatorView addToView:self.view];
335
    
336
    [self.account.manager getObjects:self.container];
337
    successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"getObjectsSucceeded"
338
                                                                        object:self.container
339
                                                                         queue:[NSOperationQueue mainQueue]
340
                                                                    usingBlock:^(NSNotification* notification)
341
    {
342
        [activityIndicatorView removeFromSuperviewAndRelease];
343
        contentsLoaded = YES;
344
        [self reloadFolderViewControllers];
345
        needsRefreshing = NO;
346
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
347
           if (self.selectedObjectViewController) {
348
               [self.selectedObjectViewController reloadMetadataSection];
349
           } else if ([self.folder isEqual:container.rootFolder]) {
350
               [containersViewController.containerDetailViewController reloadMetadataSection];
351
           } else if ([parentFolderViewController.folderDetailVC.navigationController.topViewController 
352
                       isEqual:parentFolderViewController.folderDetailVC]) {
353
               [parentFolderViewController.folderDetailVC reloadMetadataSection];
354
           }
355
        }
356
        [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
357
    }];
358
    failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"getObjectsFailed"
359
                                                                        object:self.container
360
                                                                         queue:[NSOperationQueue mainQueue]
361
                                                                    usingBlock:^(NSNotification* notification)
362
    {
363
        needsRefreshing = NO;
364
        [self.tableView reloadData];
365
        [activityIndicatorView removeFromSuperviewAndRelease];
366
        [self alert:@"Error" message:@"Failed to retrieve files from server"];
367
        [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
368
    }];
369
}
370

    
371
- (void)addButtonPressed:(id)sender {
372
    AddObjectViewController *vc = [[AddObjectViewController alloc] initWithNibName:@"AddObjectViewController" bundle:nil];
373
    vc.account = self.account;
374
    vc.container = self.container;
375
    vc.folder = self.folder;
376
    vc.folderViewController = self;
377
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
378
        vc.modalPresentationStyle = UIModalPresentationFormSheet;
379
        OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate];
380
        if (app.rootViewController.popoverController != nil) {
381
            [app.rootViewController.popoverController dismissPopoverAnimated:YES];
382
        }
383
    }
384
    [self presentModalViewControllerWithNavigation:vc animated:YES];
385
    [vc release];
386
}
387

    
388
- (void)deleteButtonPressed:(id)sender {
389
    UIActionSheet *deleteActionSheet = [[[UIActionSheet alloc] initWithTitle:@"Are you sure you want to delete this folder? This operation cannot be undone."
390
                                                                    delegate:self
391
                                                           cancelButtonTitle:@"Cancel"
392
                                                      destructiveButtonTitle:@"Delete Folder"
393
                                                           otherButtonTitles:nil] autorelease];
394
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
395
        OpenStackAppDelegate *appDelegate = (OpenStackAppDelegate *)[[UIApplication sharedApplication] delegate];
396
        [deleteActionSheet showInView:appDelegate.masterNavigationController.view];
397
    } else {
398
        [deleteActionSheet showInView:self.view];
399
    }
400
}
401

    
402
#pragma mark - UIActionSheetDelegate
403

    
404
- (void)deleteFolderRow {
405
    [self.parentFolderViewController.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:selectedFolderIndexPath] withRowAnimation:UITableViewRowAnimationLeft];
406
}
407

    
408
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
409
    if (buttonIndex == 0) {
410
        StorageObject *object = [[StorageObject alloc] init];
411
        object.name = object.fullPath = [self.folder fullPath];
412
        
413
        NSString *activityMessage = @"Deleting folder...";
414
        activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
415
        [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];    
416

    
417
        [[self.account.manager deleteObject:self.container object:object]
418
         success:^(OpenStackRequest *request) {
419
             if (self.folder.parent) {
420
                 [self.folder.parent.folders removeObjectForKey:self.folder.name];
421
             } else {
422
                 [self.container.rootFolder.folders removeObjectForKey:self.folder.name];
423
             }
424
             [self.account persist];
425
             
426
             [activityIndicatorView removeFromSuperviewAndRelease];
427
             [self.navigationController popViewControllerAnimated:YES];
428
             
429
             if (self.folder.parent) {
430
                 if ([self.folder.parent.folders count] + [self.folder.parent.objects count] == 0) {
431
                     [self.parentFolderViewController.tableView reloadData];
432
                 } else {
433
                     [self.parentFolderViewController.tableView selectRowAtIndexPath:selectedFolderIndexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
434
                     [NSTimer scheduledTimerWithTimeInterval:0.75 target:self selector:@selector(deleteFolderRow) userInfo:nil repeats:NO];
435
                 }
436
                 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
437
                     [self.parentFolderViewController setDetailViewController];
438
             } else {
439
                 if ([self.container.rootFolder.folders count] + [self.container.rootFolder.objects count] == 0) {
440
                     [self.parentFolderViewController.tableView reloadData];
441
                 } else {
442
                     [self.parentFolderViewController.tableView selectRowAtIndexPath:selectedFolderIndexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
443
                     [NSTimer scheduledTimerWithTimeInterval:0.75 target:self selector:@selector(deleteFolderRow) userInfo:nil repeats:NO];
444
                 }
445
             }
446
             [object release];
447
         }
448
         failure:^(OpenStackRequest *request) {
449
             [activityIndicatorView removeFromSuperviewAndRelease];
450
             [self alert:@"There was a problem deleting this folder." request:request];
451
             [object release];
452
         }];        
453
    }
454
}
455

    
456
@end
457