Statistics
| Branch: | Tag: | Revision:

root / Classes / FolderViewController.m @ 29cc4957

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
#import <MobileCoreServices/MobileCoreServices.h>
31
#import "ComputeModel.h"
32

    
33

    
34
@implementation FolderViewController
35

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

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

    
42
#pragma mark -
43
#pragma mark View lifecycle
44

    
45
- (void)viewDidLoad {
46
    [super viewDidLoad];
47
    [self addAddButton];
48
    [self addHomeButton];
49
    
50
    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];
51
}
52

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

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

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

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

    
122

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

    
155

    
156

    
157
#pragma mark -
158
#pragma mark Table view data source
159

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

    
164

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

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

    
181

    
182
// Customize the appearance of table view cells.
183

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

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

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

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

    
338
#pragma mark -
339
#pragma mark Buttons
340

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

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

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

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

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

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

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

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

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

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

    
477

    
478
@end
479