Statistics
| Branch: | Tag: | Revision:

root / Classes / FolderViewController.m @ 4ab364e1

History | View | Annotate | Download (22.1 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

    
31

    
32
@implementation FolderViewController
33

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

    
36
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
37
    return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
38
}
39

    
40
#pragma mark -
41
#pragma mark View lifecycle
42

    
43
- (void)viewDidLoad {
44
    [super viewDidLoad];
45
    [self addAddButton];
46
    [self addHomeButton];
47
    
48
    deleteActionSheet = [[UIActionSheet alloc] initWithTitle:@"Are you sure you want to delete this folder?  This operation cannot be undone." delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete Folder" otherButtonTitles:nil];
49
}
50

    
51
- (void)viewWillAppear:(BOOL)animated {
52
    [super viewWillAppear:animated];
53
    if (folder.name && ![@"" isEqualToString:folder.name]) {
54
        self.navigationItem.title = self.folder.name;
55
    } else {
56
        self.navigationItem.title = self.container.name;
57
    }
58
    self.selectedObjectViewController = nil;
59
}
60

    
61
- (void)viewDidAppear:(BOOL)animated {
62
    [super viewDidAppear:animated];
63
    if (!self.folder) {
64
        if (folderHasBeenRemoved) {
65
            if (needsRefreshing) 
66
                self.parentFolderViewController.needsRefreshing = YES;
67
            [self.navigationController popViewControllerAnimated:YES];
68
        }
69
        else
70
            [self refreshButtonPressed:nil];
71
    } else {
72
        if (self.needsRefreshing) {
73
            self.parentFolderViewController.needsRefreshing = YES;
74
            if (refreshWhenAppeared) {
75
                [self refreshButtonPressed:nil];
76
                refreshWhenAppeared = NO;
77
            }
78
            if (account.shared && ([folder.folders count] + [folder.objects count] == 0)) {
79
                [self.navigationController popViewControllerAnimated:YES];
80
            }
81
        }
82
    }
83
}
84

    
85
- (void)viewWillDisappear:(BOOL)animated {
86
    [super viewWillDisappear:animated];
87
    if (![self.navigationController.viewControllers containsObject:self]) {
88
        if (self.parentViewController && UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
89
            [parentFolderViewController setDetailViewController];
90
    }
91
    if (!(folder.name && ![@"" isEqualToString:folder.name])) {
92
//        [self.containersViewController.tableView deselectRowAtIndexPath:self.selectedContainerIndexPath animated:YES];
93
    }
94
}
95

    
96
- (void)setDetailViewController {
97
    if ([self.folder isEqual:self.container.rootFolder]) {
98
        ContainerDetailViewController *vc = [[ContainerDetailViewController alloc] initWithNibName:@"ContainerDetailViewController" bundle:nil];
99
        vc.account = self.account;
100
        vc.container = self.container;
101
        vc.containersViewController = self.containersViewController;
102
        vc.rootFolderViewController = self;
103
        vc.selectedContainerIndexPath = self.selectedContainerIndexPath;
104
        [self presentPrimaryViewController:vc];
105
        self.containersViewController.containerDetailViewController = vc;
106
        [vc release];
107
    }
108
    else {
109
        FolderDetailViewController *folderDetailViewController = [[FolderDetailViewController alloc] initWithNibName:@"FolderDetailViewController" bundle:nil];
110
        folderDetailViewController.account = account;
111
        folderDetailViewController.container = container;
112
        folderDetailViewController.folder = self.folder;
113
        folderDetailViewController.folderViewController = self.parentFolderViewController;
114
        [self presentPrimaryViewController:folderDetailViewController];
115
        self.parentFolderViewController.folderDetailVC = folderDetailViewController;
116
        [folderDetailViewController release];
117
    }
118
}
119

    
120

    
121
- (void)reloadFolderViewControllers
122
{
123
    NSArray *viewControllers = [self.navigationController viewControllers];
124
    
125
    int rootFolderControllerIndex = [viewControllers indexOfObject:self.containersViewController] + 1;
126
    FolderViewController *rootFolderViewController = [viewControllers objectAtIndex:rootFolderControllerIndex];
127
    rootFolderViewController.folder = self.container.rootFolder;
128
    [rootFolderViewController.tableView reloadData];
129
    
130
    for (int i = rootFolderControllerIndex + 1; i < [viewControllers count]; i++) {
131
        FolderViewController *folderViewController = [viewControllers objectAtIndex:i];
132
        Folder *parentFolder = folderViewController.parentFolderViewController.folder;
133
        
134
        folderViewController.folder = [parentFolder.folders objectForKey:folderViewController.folder.name];
135
        if (folderViewController.folder) {
136
            [folderViewController.tableView reloadData];
137
        }
138
        else {
139
            folderViewController.folderHasBeenRemoved = YES;
140
        }
141
    }
142
    if (!self.folder || (account.shared && [folder.folders count] + [folder.objects count] == 0)) {
143
        if (needsRefreshing && self.parentFolderViewController) {
144
            self.parentFolderViewController.needsRefreshing = YES;
145
        }
146
        [self.navigationController popViewControllerAnimated:YES];
147
    } else {
148
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && account.shared)
149
            [self setDetailViewController];
150
    }
151
}
152

    
153

    
154

    
155
#pragma mark -
156
#pragma mark Table view data source
157

    
158
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView {
159
    return 1;
160
}
161

    
162

    
163
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
164
    return MAX(contentsLoaded ? 1 : 0, [folder.objects count] + [folder.folders count]);
165
}
166

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

    
179

    
180
// Customize the appearance of table view cells.
181

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

    
263
#pragma mark -
264
#pragma mark Table view delegate
265

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

    
321
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
322
    Folder *folderForDetailView;
323
    if ([folder.sortedContents count] > 0) {
324
        folderForDetailView = [self.folder.sortedContents objectAtIndex:indexPath.row];
325
    } else {
326
        folderForDetailView = nil;
327
    }
328
    FolderDetailViewController *vc = [[FolderDetailViewController alloc] initWithNibName:@"FolderDetailViewController" bundle:nil];
329
    vc.account = account;
330
    vc.container = container;
331
    vc.folder = folderForDetailView;
332
    vc.folderViewController = self;
333
    [self.navigationController pushViewController:vc animated:YES];
334
    [vc release];
335
}
336

    
337
#pragma mark -
338
#pragma mark Buttons
339

    
340
- (IBAction)homeButtonPressed:(id)sender {
341
    [self.navigationController popToViewController:containersViewController.accountHomeViewController animated:YES];
342
}
343

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

    
383
- (void)addButtonPressed:(id)sender {
384
    AddObjectViewController *vc = [[AddObjectViewController alloc] initWithNibName:@"AddObjectViewController" bundle:nil];
385
    vc.account = self.account;
386
    vc.container = self.container;
387
    vc.folder = self.folder;
388
    vc.folderViewController = self;
389
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
390
        vc.modalPresentationStyle = UIModalPresentationFormSheet;
391
        OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate];
392
        if (app.rootViewController.popoverController != nil) {
393
            [app.rootViewController.popoverController dismissPopoverAnimated:YES];
394
        }
395
    }
396
    [self presentModalViewControllerWithNavigation:vc animated:YES];
397
    [vc release];
398
}
399

    
400
- (void)deleteButtonPressed:(id)sender {
401
    OpenStackAppDelegate *appDelegate = (OpenStackAppDelegate *)[[UIApplication sharedApplication] delegate];
402
    [deleteActionSheet showInView:appDelegate.masterNavigationController.view];    
403
}
404

    
405
#pragma mark -
406
#pragma mark Action Sheet Delegate
407

    
408
- (void)deleteFolderRow {
409
    [self.parentFolderViewController.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:selectedFolderIndexPath] withRowAnimation:UITableViewRowAnimationLeft];
410
}
411

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

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

    
460
#pragma mark -
461
#pragma mark Memory management
462

    
463
- (void)dealloc {
464
    [account release];
465
    [container release];
466
    [folder release];
467
    [containersViewController release];
468
    [selectedContainerIndexPath release];
469
    [deleteActionSheet release];
470
    [parentFolderViewController release];
471
    [selectedFolderIndexPath release];
472
    [super dealloc];
473
}
474

    
475

    
476
@end
477