Statistics
| Branch: | Tag: | Revision:

root / Classes / ContainerDetailViewController.m @ 54fd5c36

History | View | Annotate | Download (30.6 kB)

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

    
9
#import "ContainerDetailViewController.h"
10
#import "OpenStackAccount.h"
11
#import "Container.h"
12
#import "ActivityIndicatorView.h"
13
#import "AccountManager.h"
14
#import "UIViewController+Conveniences.h"
15
#import "UIColor+MoreColors.h"
16
#import "ReferrerACLViewController.h"
17
#import "UserAgentACLViewController.h"
18
#import "ContainersViewController.h"
19
#import "EditMetadataViewController.h"
20
#import "EditPolicyViewController.h"
21
#import "Folder.h"
22
#import "FolderViewController.h"
23
#import "OpenStackRequest.h"
24
#import "APICallback.h"
25

    
26
#define kOverview 0
27
#define kMetadata 1
28
#define kCDNAccess 3
29
#define kCDNAttributes 4
30
#define kLogRetention 5
31
#define kReferrerACL 6
32
#define kUserAgentACL 7
33

    
34
#define maxMetadataViewableLength 12
35

    
36

    
37
/* 
38
 Name
39
 Size
40
 
41
 Publish to CDN [On/Off]
42
 @"Containers published to the CDN will be viewable to everyone.  If you disable CDN access, container contents will not be purged from the CDN until the TTL expires."
43
 
44
 CDN URL
45
 TTL
46
 
47
 Log Retention [On/Off]
48
 @"When Log Retention is enabled, CDN access logs will be stored in the .CDN_ACCESS_LOGS container in your account."
49
 
50
 Referrer ACL
51
 @"The Referrer ACL is a Perl Compatible Regular Expression (PCRE) that must match the referrer in order for container contents to be served.  This is a useful mechanism to prevent other content providers from hot-linking your CDN content."
52
 
53
 User Agent ACL
54
 @"The User Agent ACL is a PCRE that must match the user agent that your users are using to access the CDN content." 
55
 
56
 */
57

    
58
@implementation ContainerDetailViewController
59

    
60
@synthesize account, container, containersViewController, selectedContainerIndexPath, rootFolderViewController;
61

    
62
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
63
    return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
64
}
65

    
66
- (void)setBackgroundView {
67
    if (!self.container) {
68
        UIView *viewContainer = [[UIView alloc] init];
69
        viewContainer.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
70
        viewContainer.backgroundColor = [UIColor iPadTableBackgroundColor];
71
        
72
        UILabel *label = [[UILabel alloc] init];
73
        label.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
74
        label.backgroundColor = [UIColor clearColor];
75
        label.textColor = [UIColor emptyCollectionGrayColor];
76
        label.font = [UIFont boldSystemFontOfSize:18.0];
77
        label.text = @"No container selected";
78
        label.textAlignment = UITextAlignmentCenter;
79
        [viewContainer addSubview:label];
80
        [label release];
81
        
82
        self.tableView.backgroundView = viewContainer;
83
        [viewContainer release];
84
    }
85
}
86

    
87
#pragma mark -
88
#pragma mark View lifecycle
89

    
90
- (void)viewDidLoad {
91
    [super viewDidLoad];
92
    cdnEnabledSwitch = [[UISwitch alloc] init];
93
    cdnEnabledSwitch.on = container.cdnEnabled;
94
    [cdnEnabledSwitch addTarget:self action:@selector(cdnEnabledSwitchChanged:) forControlEvents:UIControlEventValueChanged];
95
    
96
    logRetentionSwitch = [[UISwitch alloc] init];
97
    logRetentionSwitch.on = container.logRetention;
98
    [logRetentionSwitch addTarget:self action:@selector(logRetentionSwitchChanged:) forControlEvents:UIControlEventValueChanged];
99

    
100
    ttlSlider = [[UISlider alloc] init];
101
    cdnURLActionSheet = [[UIActionSheet alloc] initWithTitle:container.cdnURL delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Copy to Pasteboard", nil];
102
    deleteActionSheet = [[UIActionSheet alloc] initWithTitle:@"Are you sure you want to delete this container?  This operation cannot be undone." delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete Container" otherButtonTitles:nil];
103
    
104
    if (!account.sharingAccount) {
105
        deleteSection = container.cdnEnabled ? 8 : 3;
106
        policySection = container.cdnEnabled ? 7 : 2;
107
    } else {
108
        deleteSection = -1;
109
        policySection = -1;
110
    }
111
}
112

    
113
- (void)viewWillAppear:(BOOL)animated {
114
    [super viewWillAppear:animated];
115
    if (container) {
116
        self.navigationItem.title = container.name;
117
    } 
118
    originalTTL = container.ttl;
119
    [self setBackgroundView];
120
    [self.tableView reloadData];
121
}
122

    
123
- (void)viewWillDisappear:(BOOL)animated {
124
    [super viewWillDisappear:animated];
125
}
126

    
127
#pragma mark -
128
#pragma mark TTL
129

    
130
- (float)ttlToPercentage {
131
    return self.container.ttl / 259200.0;
132
}
133

    
134
- (NSInteger)ttlFromPercentage:(float)percentage {
135
    return percentage * 259200;
136
}
137

    
138
- (NSString *)ttlToHours {
139
    NSString *result = [NSString stringWithFormat:@"%.0f hours", self.container.ttl / 3600.0];
140
    if ([result isEqualToString:@"1 hours"]) {
141
        result = @"1 hour";
142
    }
143
    return result;
144
}
145

    
146
- (void)ttlSliderFinished:(id)sender {
147
    NSString *activityMessage = @"Updating TTL...";
148
    activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
149
    [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];
150
    
151
    [self.account.manager updateCDNContainer:self.container];
152
    
153
    successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerSucceeded" object:self.container
154
                                                                         queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
155
       {
156
           [activityIndicatorView removeFromSuperviewAndRelease];
157
           [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
158
       }];
159
    
160
    failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerFailed" object:self.container
161
                                                                         queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
162
       {
163
           [activityIndicatorView removeFromSuperviewAndRelease];
164
           container.ttl = originalTTL;
165
           [self.tableView reloadData];
166
           [self alert:@"There was a problem updating this container." request:[notification.userInfo objectForKey:@"request"]];
167
           [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
168
       }];
169
}
170

    
171
- (void)ttlSliderMoved:(id)sender {
172
	CGFloat newTTL = ttlSlider.value;
173
    self.container.ttl = [self ttlFromPercentage:newTTL];
174
    ttlLabel.text = [self ttlToHours];
175
}
176

    
177

    
178
#pragma mark -
179
#pragma mark Table view data source
180

    
181
- (CGFloat)findLabelHeight:(NSString*)text font:(UIFont *)font {
182
    CGSize textLabelSize;
183
    
184
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
185
        textLabelSize = CGSizeMake(577.0, 9000.0f);
186
    } else {
187
        textLabelSize = CGSizeMake(260.0, 9000.0f);
188
    }
189
    // pad \n\n to fix layout bug
190
    CGSize stringSize = [text sizeWithFont:font constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeWordWrap];
191
    return stringSize.height;
192
}
193

    
194
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
195
    if (indexPath.section == deleteSection) {
196
        return tableView.rowHeight;
197
    } else if (indexPath.section == kCDNAttributes) {
198
        if (indexPath.row == 0) { // URL
199
            return tableView.rowHeight;
200
            //return 22.0 + [self findLabelHeight:container.cdnURL font:[UIFont systemFontOfSize:18.0]];
201
        } else { // if (indexPath.row == 1) {
202
            return tableView.rowHeight + ttlSlider.frame.size.height + 3.0;
203
        }
204
    } else {
205
        return tableView.rowHeight;
206
    }
207
}
208

    
209
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
210
    if (section == deleteSection) {
211
        return @"Only empty containers can be deleted.";
212
    } else if (section == kCDNAccess) {
213
        //return @"CDN allows you to access files in this container via the public internet. Transfer charges apply.";
214
        return @"CDN allows you to access files via the public internet. Transfer charges apply.";
215
    } else if (section == kLogRetention) {
216
        return @"When enabled, access logs will be stored in the .CDN_ACCESS_LOGS container.";
217
    } else if (section == kReferrerACL) {
218
        return @"The Referrer ACL is a Perl Compatible Regular Expression that must match the referrer for all content requests.";
219
    } else if (section == kUserAgentACL) {
220
        return @"The User Agent ACL is a Perl Compatible Regular Expression that must match the user agent for all content requests.";
221
    } else {
222
        return @"";
223
    }
224
}
225

    
226
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
227
    if (self.container) {
228
        int numberOfSections;
229
        if (transitioning) {
230
            numberOfSections = container.cdnEnabled ? 4 : 9;
231
        } else {
232
            numberOfSections = container.cdnEnabled ? 9 : 4;
233
        }
234
        if (account.sharingAccount)
235
            return numberOfSections - 2;
236
        else
237
            return numberOfSections;
238
    } else {
239
        return 0;
240
    }
241
}
242

    
243
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
244
    // Return the number of rows in the section.
245
    if (section == kOverview) {
246
        return 2;
247
    } else if (section == kMetadata) {
248
        if (account.sharingAccount)
249
            return [container.metadata count];
250
        else
251
            return 1 + [container.metadata count];     
252
    } else if (section == policySection) {
253
        if (account.sharingAccount)
254
            return 2;
255
        else
256
            return 3;
257
    } else {
258
        return 1;
259
    }
260
}
261

    
262
- (UITableViewCell *)tableView:(UITableView *)tableView ttlCellForRowAtIndexPath:(NSIndexPath *)indexPath {
263
    static NSString *CellIdentifier = @"TTLCell";
264
    
265
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
266
    if (cell == nil) {
267
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
268
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
269
        
270
        UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 13.0, 280.0, 20.0)];
271
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
272
            textLabel.frame = CGRectMake(54.0, 13.0, 458.0, 20.0);
273
        }
274
        textLabel.font = [UIFont boldSystemFontOfSize:17.0];
275
        textLabel.text = @"TTL";
276
        textLabel.textColor = [UIColor blackColor];
277
        textLabel.backgroundColor = [UIColor clearColor];
278
        [cell addSubview:textLabel];
279
        [textLabel release];
280
        
281
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
282
            ttlSlider.frame = CGRectMake(54.0, 38.0, 596.0, ttlSlider.frame.size.height);
283
        } else {
284
            ttlSlider.frame = CGRectMake(20.0, 38.0, 280.0, ttlSlider.frame.size.height);
285
        }
286
        [ttlSlider addTarget:self action:@selector(ttlSliderMoved:) forControlEvents:UIControlEventValueChanged];
287
        [ttlSlider addTarget:self action:@selector(ttlSliderFinished:) forControlEvents:UIControlEventTouchUpInside];
288
        
289
        [cell addSubview:ttlSlider];
290
        ttlLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 14.0, 280.0, 18.0)];
291
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
292
            ttlLabel.frame = CGRectMake(54.0, 14.0, 596.0, 18.0);
293
        }
294
        ttlLabel.font = [UIFont systemFontOfSize:17.0];
295
        ttlLabel.textColor = [UIColor value1DetailTextLabelColor];
296
        ttlLabel.backgroundColor = [UIColor clearColor];
297
        ttlLabel.textAlignment = UITextAlignmentRight;
298
        [cell addSubview:ttlLabel];
299
    }
300
    
301
    ttlLabel.text = [self ttlToHours];
302
    ttlSlider.value = [self ttlToPercentage];
303
    
304
    return cell;
305
}
306

    
307
- (UITableViewCell *)tableView:(UITableView *)tableView deleteCellForRowAtIndexPath:(NSIndexPath *)indexPath {
308
    static NSString *CellIdentifier = @"DeleteCell";
309
    
310
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
311
    if (cell == nil) {
312
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
313
        cell.textLabel.textAlignment = UITextAlignmentCenter;
314
        cell.textLabel.text = @"Delete Container";
315
    }
316
    
317
    if (self.container.rootFolder) {
318
        if (self.container.count == 0 || ([self.container.rootFolder.folders count] + [self.container.rootFolder.objects count] == 0)) {
319
            cell.textLabel.textColor = [UIColor blackColor];
320
            cell.selectionStyle = UITableViewCellSelectionStyleBlue;
321
        } else {
322
            cell.textLabel.textColor = [UIColor grayColor];
323
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
324
            cell.userInteractionEnabled = NO;
325
        }
326
    } else {
327
        if (self.container.count == 0) {
328
            cell.textLabel.textColor = [UIColor blackColor];
329
            cell.selectionStyle = UITableViewCellSelectionStyleBlue;
330
        } else {
331
            cell.textLabel.textColor = [UIColor grayColor];
332
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
333
            cell.userInteractionEnabled = NO;
334
        }
335
    }
336
    
337
    return cell;
338
}
339

    
340
// Customize the appearance of table view cells.
341
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
342
    
343
    static NSString *CellIdentifier = @"Cell";
344
    
345
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
346
    if (cell == nil) {
347
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
348
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
349
        cell.textLabel.backgroundColor = [UIColor clearColor];
350
        cell.detailTextLabel.backgroundColor = [UIColor clearColor];
351
        cell.detailTextLabel.numberOfLines = 0;
352
        cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
353
        cell.detailTextLabel.textAlignment = UITextAlignmentLeft;
354
    }
355
    
356
    cell.accessoryType = UITableViewCellAccessoryNone;
357
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
358
    
359
    if (indexPath.section == kOverview) {
360
        cell.accessoryView = nil;
361
        if (indexPath.row == 0) {
362
            cell.textLabel.text = @"Name";
363
            cell.detailTextLabel.text = container.name;
364
        } else if (indexPath.row == 1) {
365
            cell.textLabel.text = @"Size";
366
            cell.detailTextLabel.text = [container humanizedSize];
367
        }
368
    } else if (indexPath.section == kMetadata) {
369
        if (account.sharingAccount) {
370
            cell.accessoryType = UITableViewCellAccessoryNone;
371
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
372
            cell.userInteractionEnabled = NO;
373
        }
374
        else {
375
            cell.selectionStyle = UITableViewCellSelectionStyleBlue;
376
            cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
377
        }
378
        if (indexPath.row == [container.metadata count]) {
379
            cell.textLabel.text = @"Add Metadata";
380
            cell.detailTextLabel.text = @"";
381
        } else {
382
            NSString *key = [[container.metadata allKeys] objectAtIndex:indexPath.row];
383
            NSString *value = [container.metadata objectForKey:key];
384
            NSString *metadataKeyCellText = key;
385
            NSString *metadataValueCellText = value;
386
            if ([metadataKeyCellText length] > maxMetadataViewableLength) {
387
                metadataKeyCellText = [metadataKeyCellText substringToIndex:(maxMetadataViewableLength - 3)];
388
                metadataKeyCellText = [metadataKeyCellText stringByAppendingString:@"..."];
389
            }
390
            if ([metadataValueCellText length] > maxMetadataViewableLength) {
391
                metadataValueCellText = [metadataValueCellText substringToIndex:(maxMetadataViewableLength - 3)];
392
                metadataValueCellText = [metadataValueCellText stringByAppendingString:@"..."];
393
            }
394
            cell.textLabel.text = metadataKeyCellText;
395
            cell.detailTextLabel.text = metadataValueCellText;
396
        }
397
    } else if (indexPath.section == policySection) {
398
        cell.selectionStyle = UITableViewCellSelectionStyleBlue;
399
        if (indexPath.row == 0) {
400
            cell.textLabel.text = @"Versioning";
401
            cell.detailTextLabel.text = container.versioning;
402
            cell.accessoryType = UITableViewCellAccessoryNone;
403
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
404
        }
405
        else if (indexPath.row == 1) {
406
            cell.textLabel.text = @"Quota";
407
            cell.detailTextLabel.text = [NSString stringWithFormat:@"%u", container.quota];
408
            cell.accessoryType = UITableViewCellAccessoryNone;
409
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
410
        }
411
        else {
412
            cell.textLabel.text = @"Edit policy";
413
            cell.detailTextLabel.text = @"";
414
            cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
415
        }
416
    } else if (indexPath.section == deleteSection) {
417
        return [self tableView:tableView deleteCellForRowAtIndexPath:indexPath];
418
    } else if (indexPath.section == kLogRetention) {
419
        cell.textLabel.text = @"Log Retention";
420
        cell.detailTextLabel.text = @"";
421
        cell.accessoryView = logRetentionSwitch;
422
        cell.accessoryType = UITableViewCellAccessoryNone;
423
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
424
    } else if (indexPath.section == kReferrerACL) {
425
        cell.textLabel.text = @"Referrer ACL";
426
        cell.detailTextLabel.text = container.referrerACL;
427
        cell.accessoryView = nil;
428
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
429
        cell.selectionStyle = UITableViewCellSelectionStyleBlue;
430
        cell.detailTextLabel.numberOfLines = 1;
431
    } else if (indexPath.section == kUserAgentACL) {
432
        cell.textLabel.text = @"User Agent ACL";
433
        cell.detailTextLabel.text = container.useragentACL;
434
        cell.accessoryView = nil;
435
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
436
        cell.selectionStyle = UITableViewCellSelectionStyleBlue;
437
        cell.detailTextLabel.numberOfLines = 1;
438
    }
439
    
440
    return cell;
441
}
442

    
443
#pragma mark -
444
#pragma mark Table view delegate
445

    
446
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
447
    
448
    if (indexPath.section == kMetadata) {
449
        EditMetadataViewController *vc = [[EditMetadataViewController alloc] initWithNibName:@"EditMetadataViewController" bundle:nil];
450
        NSString *metadataKey;
451
        NSString *metadataValue;
452
        
453
        if (indexPath.row == [self.container.metadata count]) {
454
            metadataKey = @"";
455
            metadataValue = @"";
456
            vc.removeMetadataEnabled = FALSE;
457
            vc.navigationItem.title = @"Add Metadata";
458
        }
459
        else {
460
            metadataKey = [[self.container.metadata allKeys] objectAtIndex:indexPath.row];
461
            metadataValue = [self.container.metadata objectForKey:metadataKey];
462
            vc.removeMetadataEnabled = TRUE;
463
            vc.navigationItem.title = @"Edit Metadata";
464
        }
465
        
466
        StorageObject *object = [[[StorageObject alloc] init] autorelease];
467
        object.name = container.name;
468
        object.metadata = container.metadata;
469
        object.fullPath = @"";
470
        
471
        vc.metadataKey = metadataKey;
472
        vc.metadataValue = metadataValue;
473
        vc.account = account;
474
        vc.container = container;
475
        vc.object = object;
476
        vc.objectIsContainer = YES;
477
        
478
        [self.navigationController pushViewController:vc animated:YES];
479
        [vc release];
480
    } else if (indexPath.section == policySection) {
481
        if (indexPath.row == 2) {
482
            EditPolicyViewController *vc = [[EditPolicyViewController alloc] initWithNibName:@"EditPolicyViewController" bundle:nil];
483
    
484
            vc.account = account;
485
            vc.container = container;
486
            vc.containerDetailViewController = self;
487
        
488
            [self.navigationController pushViewController:vc animated:YES];
489
            [vc release];
490
        }
491
    } else if (indexPath.section == deleteSection) {
492
        if (self.container.count == 0 || ([self.container.rootFolder.folders count] + [self.container.rootFolder.objects count] == 0)) {
493
            [deleteActionSheet showInView:self.view];
494
        }
495
    } else if (indexPath.section == kCDNAttributes && indexPath.row == 0) {
496
        [cdnURLActionSheet showInView:self.view];
497
    } else if (indexPath.section == kReferrerACL) {
498
        ReferrerACLViewController *vc = [[ReferrerACLViewController alloc] initWithNibName:@"ReferrerACLViewController" bundle:nil];
499
        vc.account = self.account;
500
        vc.container = self.container;
501
        vc.containerDetailViewController = self;
502
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
503
            vc.modalPresentationStyle = UIModalPresentationFormSheet;
504
            [self presentModalViewControllerWithNavigation:vc animated:YES];
505
        } else {
506
            [self.navigationController pushViewController:vc animated:YES];
507
        }        
508
        [vc release];
509
    } else if (indexPath.section == kUserAgentACL) {
510
        UserAgentACLViewController *vc = [[UserAgentACLViewController alloc] initWithNibName:@"UserAgentACLViewController" bundle:nil];
511
        vc.account = self.account;
512
        vc.container = self.container;
513
        vc.containerDetailViewController = self;
514
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
515
            vc.modalPresentationStyle = UIModalPresentationFormSheet;
516
            [self presentModalViewControllerWithNavigation:vc animated:YES];
517
        } else {
518
            [self.navigationController pushViewController:vc animated:YES];
519
        }        
520
        [vc release];
521
    }
522
}
523

    
524
#pragma mark -
525
#pragma mark Switches
526

    
527
- (void)cdnEnabledSwitchChanged:(id)sender {
528
    
529
    NSString *activityMessage = @"Disabling CDN Access...";
530
    if (!container.cdnEnabled) {
531
        activityMessage = @"Enabling CDN Access...";
532
    }
533
    activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
534
    [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];    
535
    container.cdnEnabled = !container.cdnEnabled;
536
    [self.account.manager updateCDNContainer:container];
537
    
538
    successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerSucceeded" object:self.container
539
                                                                         queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
540
    {
541
        [activityIndicatorView removeFromSuperviewAndRelease];
542
        
543
        NSIndexSet *sections = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(3, 4)];
544
        NSInteger oldDeleteSection = deleteSection;
545
        if (container.cdnEnabled) {
546
            deleteSection = 6;
547
            transitioning = YES;
548
            [self.tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(oldDeleteSection, 1)] withRowAnimation:UITableViewRowAnimationBottom];
549
            transitioning = NO;
550
            [self.tableView insertSections:sections withRowAnimation:UITableViewRowAnimationBottom];
551
        } else {
552
            deleteSection = 2;
553
            transitioning = YES;
554
            [self.tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(deleteSection, 1)] withRowAnimation:UITableViewRowAnimationTop];
555
            transitioning = NO;
556
            [self.tableView deleteSections:sections withRowAnimation:UITableViewRowAnimationTop];
557
        }
558
        
559
        [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
560
    }];
561
    
562
    failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerFailed" object:self.container
563
                                                                         queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
564
    {
565
        [activityIndicatorView removeFromSuperviewAndRelease];
566
        container.cdnEnabled = !container.cdnEnabled;
567
        cdnEnabledSwitch.on = !cdnEnabledSwitch.on;
568
        [self alert:@"There was a problem updating this container." request:[notification.userInfo objectForKey:@"request"]];           
569
        [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
570
    }];
571
}
572

    
573
- (void)logRetentionSwitchChanged:(id)sender {
574

    
575
    NSString *activityMessage = @"Disabling Log Retention...";
576
    if (!container.logRetention) {
577
        activityMessage = @"Enabling Log Retention...";
578
    }
579
    activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
580
    [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];    
581

    
582
    container.logRetention = !container.logRetention;
583
    [self.account.manager updateCDNContainer:container];
584
    
585
    successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerSucceeded" object:self.container
586
                                                                         queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
587
       {
588
           [activityIndicatorView removeFromSuperviewAndRelease];
589
           [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
590
       }];
591
    
592
    failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerFailed" object:self.container
593
                                                                         queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
594
       {
595
           [activityIndicatorView removeFromSuperviewAndRelease];
596
           container.logRetention = !container.logRetention;
597
           logRetentionSwitch.on = !logRetentionSwitch.on;
598
           [self alert:@"There was a problem updating this container." request:[notification.userInfo objectForKey:@"request"]];
599
           [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
600
       }];
601
}
602

    
603
#pragma mark -
604
#pragma mark Action Sheet
605

    
606
- (void)deleteContainerRow {
607
    if ([self.account.containers count] == 0) {
608
        [self.containersViewController.tableView reloadData];
609
    } else {
610
        [self.containersViewController.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:selectedContainerIndexPath] withRowAnimation:UITableViewRowAnimationLeft];
611
    }
612
    [self.rootFolderViewController.navigationController popViewControllerAnimated:YES];
613
}
614

    
615
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
616
    if ([actionSheet isEqual:cdnURLActionSheet]) {
617
        if (buttonIndex == 0) {
618
            UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
619
            [pasteboard setString:container.cdnURL];
620
        }
621
        [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:kCDNAttributes] animated:YES];
622
    } else if ([actionSheet isEqual:deleteActionSheet]) {
623
        if (buttonIndex == 0) {
624
         
625
            NSString *activityMessage = @"Deleting container...";
626
            activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
627
            [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];  
628
            
629
            [[self.account.manager deleteContainer:self.container] success:^(OpenStackRequest *request) {
630
                
631
                [activityIndicatorView removeFromSuperviewAndRelease];                
632
                [self.account.containers removeObjectForKey:self.container.name];
633
                [self.account persist];
634
                if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
635
                    [self.containersViewController.navigationController popViewControllerAnimated:YES];
636
                else
637
                    [self.navigationController popViewControllerAnimated:YES];
638
                
639
                [self deleteContainerRow];
640

    
641
                
642
            } failure:^(OpenStackRequest *request) {
643
                
644
                // 404 Not Found means it's not there, so we can show the user that it's deleted
645
                if ([request responseStatusCode] == 404) {
646
                    [self.account.containers removeObjectForKey:container.name];
647
                    [self.account persist];
648
                    
649
                } else {
650
                    [activityIndicatorView removeFromSuperviewAndRelease];
651
                    [self alert:@"There was a problem deleting this container." request:request];
652
                }
653
            }];
654
                        
655
        }
656
        [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:deleteSection] animated:YES];
657
    }
658
}
659

    
660

    
661
#pragma mark -
662
#pragma mark Memory management
663

    
664
- (void)dealloc {
665
    [account release];
666
    [container release];
667
    [cdnEnabledSwitch release];
668
    [ttlSlider release];
669
    [cdnURLActionSheet release];
670
    [deleteActionSheet release];
671
    [containersViewController release];
672
    [selectedContainerIndexPath release];
673
    [rootFolderViewController release];
674
    [super dealloc];
675
}
676

    
677
#pragma mark -
678
#pragma mark Helper functions
679

    
680
- (void)reloadMetadataSection {
681
    NSString *activityMessage = @"Loading metadata...";
682
    activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
683
    [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y]; 
684
    [[self.account.manager getContainerInfo:container] 
685
     success:^(OpenStackRequest *request) {
686
         [activityIndicatorView removeFromSuperviewAndRelease];
687
         container.metadata = [NSMutableDictionary dictionary];
688
         for (NSString *header in request.responseHeaders) {
689
             NSString *metadataKey;
690
             NSString *metadataValue;
691
             if ([header rangeOfString:@"X-Container-Meta-"].location != NSNotFound) {
692
                 metadataKey = [header substringFromIndex:17];
693
                 metadataValue = [request.responseHeaders objectForKey:header];
694
                 [container.metadata setObject:metadataValue forKey:metadataKey];
695
             }
696
         } 
697
         NSIndexSet *metadataSections = [NSIndexSet indexSetWithIndex:kMetadata];
698
         [self.tableView reloadSections:metadataSections withRowAnimation:UITableViewRowAnimationFade];
699
     }
700
     failure:^(OpenStackRequest *request) {
701
         [activityIndicatorView removeFromSuperviewAndRelease];
702
         [self alert:@"There was a problem retrieving the container's metadata." request:request]; 
703
     }];
704
}
705

    
706
@end
707