Added my shared/others shared functionality.
[pithos-ios] / Classes / ContainerDetailViewController.m
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
24 #define kOverview 0
25 #define kMetadata 1
26 #define kCDNAccess 3
27 #define kCDNAttributes 4
28 #define kLogRetention 5
29 #define kReferrerACL 6
30 #define kUserAgentACL 7
31
32 #define maxMetadataViewableLength 12
33
34
35 /* 
36  Name
37  Size
38  
39  Publish to CDN [On/Off]
40  @"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."
41  
42  CDN URL
43  TTL
44  
45  Log Retention [On/Off]
46  @"When Log Retention is enabled, CDN access logs will be stored in the .CDN_ACCESS_LOGS container in your account."
47  
48  Referrer ACL
49  @"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."
50  
51  User Agent ACL
52  @"The User Agent ACL is a PCRE that must match the user agent that your users are using to access the CDN content." 
53  
54  */
55
56 @implementation ContainerDetailViewController
57
58 @synthesize account, container, containersViewController, selectedContainerIndexPath, rootFolderViewController;
59
60 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
61     return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
62 }
63
64 - (void)setBackgroundView {
65     if (!self.container) {
66         UIView *viewContainer = [[UIView alloc] init];
67         viewContainer.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
68         viewContainer.backgroundColor = [UIColor iPadTableBackgroundColor];
69         
70         UILabel *label = [[UILabel alloc] init];
71         label.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
72         label.backgroundColor = [UIColor clearColor];
73         label.textColor = [UIColor emptyCollectionGrayColor];
74         label.font = [UIFont boldSystemFontOfSize:18.0];
75         label.text = @"No container selected";
76         label.textAlignment = UITextAlignmentCenter;
77         [viewContainer addSubview:label];
78         [label release];
79         
80         self.tableView.backgroundView = viewContainer;
81         [viewContainer release];
82     }
83 }
84
85 #pragma mark -
86 #pragma mark View lifecycle
87
88 - (void)viewDidLoad {
89     [super viewDidLoad];
90     cdnEnabledSwitch = [[UISwitch alloc] init];
91     cdnEnabledSwitch.on = container.cdnEnabled;
92     [cdnEnabledSwitch addTarget:self action:@selector(cdnEnabledSwitchChanged:) forControlEvents:UIControlEventValueChanged];
93     
94     logRetentionSwitch = [[UISwitch alloc] init];
95     logRetentionSwitch.on = container.logRetention;
96     [logRetentionSwitch addTarget:self action:@selector(logRetentionSwitchChanged:) forControlEvents:UIControlEventValueChanged];
97
98     ttlSlider = [[UISlider alloc] init];
99     cdnURLActionSheet = [[UIActionSheet alloc] initWithTitle:container.cdnURL delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Copy to Pasteboard", nil];
100     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];
101     
102     if (!account.sharingAccount) {
103         deleteSection = container.cdnEnabled ? 8 : 3;
104         policySection = container.cdnEnabled ? 7 : 2;
105     } else {
106         deleteSection = -1;
107         policySection = -1;
108     }
109 }
110
111 - (void)viewWillAppear:(BOOL)animated {
112     [super viewWillAppear:animated];
113     if (container) {
114         self.navigationItem.title = container.name;
115     } 
116     originalTTL = container.ttl;
117     [self setBackgroundView];
118     [self.tableView reloadData];
119 }
120
121 #pragma mark -
122 #pragma mark TTL
123
124 - (float)ttlToPercentage {
125     return self.container.ttl / 259200.0;
126 }
127
128 - (NSInteger)ttlFromPercentage:(float)percentage {
129     return percentage * 259200;
130 }
131
132 - (NSString *)ttlToHours {
133     NSString *result = [NSString stringWithFormat:@"%.0f hours", self.container.ttl / 3600.0];
134     if ([result isEqualToString:@"1 hours"]) {
135         result = @"1 hour";
136     }
137     return result;
138 }
139
140 - (void)ttlSliderFinished:(id)sender {
141     NSString *activityMessage = @"Updating TTL...";
142     activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
143     [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];
144     
145     [self.account.manager updateCDNContainer:self.container];
146     
147     successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerSucceeded" object:self.container
148                                                                          queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
149        {
150            [activityIndicatorView removeFromSuperviewAndRelease];
151            [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
152        }];
153     
154     failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerFailed" object:self.container
155                                                                          queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
156        {
157            [activityIndicatorView removeFromSuperviewAndRelease];
158            container.ttl = originalTTL;
159            [self.tableView reloadData];
160            [self alert:@"There was a problem updating this container." request:[notification.userInfo objectForKey:@"request"]];
161            [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
162        }];
163 }
164
165 - (void)ttlSliderMoved:(id)sender {
166         CGFloat newTTL = ttlSlider.value;
167     self.container.ttl = [self ttlFromPercentage:newTTL];
168     ttlLabel.text = [self ttlToHours];
169 }
170
171
172 #pragma mark -
173 #pragma mark Table view data source
174
175 - (CGFloat)findLabelHeight:(NSString*)text font:(UIFont *)font {
176     CGSize textLabelSize;
177     
178     if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
179         textLabelSize = CGSizeMake(577.0, 9000.0f);
180     } else {
181         textLabelSize = CGSizeMake(260.0, 9000.0f);
182     }
183     // pad \n\n to fix layout bug
184     CGSize stringSize = [text sizeWithFont:font constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeWordWrap];
185     return stringSize.height;
186 }
187
188 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
189     if (indexPath.section == deleteSection) {
190         return tableView.rowHeight;
191     } else if (indexPath.section == kCDNAttributes) {
192         if (indexPath.row == 0) { // URL
193             return tableView.rowHeight;
194             //return 22.0 + [self findLabelHeight:container.cdnURL font:[UIFont systemFontOfSize:18.0]];
195         } else { // if (indexPath.row == 1) {
196             return tableView.rowHeight + ttlSlider.frame.size.height + 3.0;
197         }
198     } else {
199         return tableView.rowHeight;
200     }
201 }
202
203 - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
204     if (section == deleteSection) {
205         return @"Only empty containers can be deleted.";
206     } else if (section == kCDNAccess) {
207         //return @"CDN allows you to access files in this container via the public internet. Transfer charges apply.";
208         return @"CDN allows you to access files via the public internet. Transfer charges apply.";
209     } else if (section == kLogRetention) {
210         return @"When enabled, access logs will be stored in the .CDN_ACCESS_LOGS container.";
211     } else if (section == kReferrerACL) {
212         return @"The Referrer ACL is a Perl Compatible Regular Expression that must match the referrer for all content requests.";
213     } else if (section == kUserAgentACL) {
214         return @"The User Agent ACL is a Perl Compatible Regular Expression that must match the user agent for all content requests.";
215     } else {
216         return @"";
217     }
218 }
219
220 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
221     if (self.container) {
222         int numberOfSections;
223         if (transitioning) {
224             numberOfSections = container.cdnEnabled ? 4 : 9;
225         } else {
226             numberOfSections = container.cdnEnabled ? 9 : 4;
227         }
228         if (account.sharingAccount)
229             return numberOfSections - 2;
230         else
231             return numberOfSections;
232     } else {
233         return 0;
234     }
235 }
236
237 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
238     // Return the number of rows in the section.
239     if (section == kOverview) {
240         return 2;
241     } else if (section == kMetadata) {
242         if (account.sharingAccount)
243             return [container.metadata count];
244         else
245             return 1 + [container.metadata count];     
246     } else if (section == policySection) {
247         if (account.sharingAccount)
248             return 2;
249         else
250             return 3;
251     } else {
252         return 1;
253     }
254 }
255
256 - (UITableViewCell *)tableView:(UITableView *)tableView ttlCellForRowAtIndexPath:(NSIndexPath *)indexPath {
257     static NSString *CellIdentifier = @"TTLCell";
258     
259     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
260     if (cell == nil) {
261         cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
262         cell.selectionStyle = UITableViewCellSelectionStyleNone;
263         
264         UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 13.0, 280.0, 20.0)];
265         if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
266             textLabel.frame = CGRectMake(54.0, 13.0, 458.0, 20.0);
267         }
268         textLabel.font = [UIFont boldSystemFontOfSize:17.0];
269         textLabel.text = @"TTL";
270         textLabel.textColor = [UIColor blackColor];
271         textLabel.backgroundColor = [UIColor clearColor];
272         [cell addSubview:textLabel];
273         [textLabel release];
274         
275         if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
276             ttlSlider.frame = CGRectMake(54.0, 38.0, 596.0, ttlSlider.frame.size.height);
277         } else {
278             ttlSlider.frame = CGRectMake(20.0, 38.0, 280.0, ttlSlider.frame.size.height);
279         }
280         [ttlSlider addTarget:self action:@selector(ttlSliderMoved:) forControlEvents:UIControlEventValueChanged];
281         [ttlSlider addTarget:self action:@selector(ttlSliderFinished:) forControlEvents:UIControlEventTouchUpInside];
282         
283         [cell addSubview:ttlSlider];
284         ttlLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 14.0, 280.0, 18.0)];
285         if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
286             ttlLabel.frame = CGRectMake(54.0, 14.0, 596.0, 18.0);
287         }
288         ttlLabel.font = [UIFont systemFontOfSize:17.0];
289         ttlLabel.textColor = [UIColor value1DetailTextLabelColor];
290         ttlLabel.backgroundColor = [UIColor clearColor];
291         ttlLabel.textAlignment = UITextAlignmentRight;
292         [cell addSubview:ttlLabel];
293     }
294     
295     ttlLabel.text = [self ttlToHours];
296     ttlSlider.value = [self ttlToPercentage];
297     
298     return cell;
299 }
300
301 - (UITableViewCell *)tableView:(UITableView *)tableView deleteCellForRowAtIndexPath:(NSIndexPath *)indexPath {
302     static NSString *CellIdentifier = @"DeleteCell";
303     
304     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
305     if (cell == nil) {
306         cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
307         cell.textLabel.textAlignment = UITextAlignmentCenter;
308         cell.textLabel.text = @"Delete Container";
309     }
310     
311     if (self.container.rootFolder) {
312         if (self.container.count == 0 || ([self.container.rootFolder.folders count] + [self.container.rootFolder.objects count] == 0)) {
313             cell.textLabel.textColor = [UIColor blackColor];
314             cell.selectionStyle = UITableViewCellSelectionStyleBlue;
315         } else {
316             cell.textLabel.textColor = [UIColor grayColor];
317             cell.selectionStyle = UITableViewCellSelectionStyleNone;
318             cell.userInteractionEnabled = NO;
319         }
320     } else {
321         if (self.container.count == 0) {
322             cell.textLabel.textColor = [UIColor blackColor];
323             cell.selectionStyle = UITableViewCellSelectionStyleBlue;
324         } else {
325             cell.textLabel.textColor = [UIColor grayColor];
326             cell.selectionStyle = UITableViewCellSelectionStyleNone;
327             cell.userInteractionEnabled = NO;
328         }
329     }
330     
331     return cell;
332 }
333
334 // Customize the appearance of table view cells.
335 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
336     
337     static NSString *CellIdentifier = @"Cell";
338     
339     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
340     if (cell == nil) {
341         cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
342         cell.selectionStyle = UITableViewCellSelectionStyleNone;
343         cell.textLabel.backgroundColor = [UIColor clearColor];
344         cell.detailTextLabel.backgroundColor = [UIColor clearColor];
345         cell.detailTextLabel.numberOfLines = 0;
346         cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
347         cell.detailTextLabel.textAlignment = UITextAlignmentLeft;
348     }
349     
350     cell.accessoryType = UITableViewCellAccessoryNone;
351     cell.selectionStyle = UITableViewCellSelectionStyleNone;
352     
353     if (indexPath.section == kOverview) {
354         cell.accessoryView = nil;
355         if (indexPath.row == 0) {
356             cell.textLabel.text = @"Name";
357             cell.detailTextLabel.text = container.name;
358         } else if (indexPath.row == 1) {
359             cell.textLabel.text = @"Size";
360             cell.detailTextLabel.text = [container humanizedSize];
361         }
362     } else if (indexPath.section == kMetadata) {
363         if (account.sharingAccount) {
364             cell.accessoryType = UITableViewCellAccessoryNone;
365             cell.selectionStyle = UITableViewCellSelectionStyleNone;
366             cell.userInteractionEnabled = NO;
367         }
368         else {
369             cell.selectionStyle = UITableViewCellSelectionStyleBlue;
370             cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
371         }
372         if (indexPath.row == [container.metadata count]) {
373             cell.textLabel.text = @"Add Metadata";
374             cell.detailTextLabel.text = @"";
375         } else {
376             NSString *key = [[container.metadata allKeys] objectAtIndex:indexPath.row];
377             NSString *value = [container.metadata objectForKey:key];
378             NSString *metadataKeyCellText = key;
379             NSString *metadataValueCellText = value;
380             if ([metadataKeyCellText length] > maxMetadataViewableLength) {
381                 metadataKeyCellText = [metadataKeyCellText substringToIndex:(maxMetadataViewableLength - 3)];
382                 metadataKeyCellText = [metadataKeyCellText stringByAppendingString:@"..."];
383             }
384             if ([metadataValueCellText length] > maxMetadataViewableLength) {
385                 metadataValueCellText = [metadataValueCellText substringToIndex:(maxMetadataViewableLength - 3)];
386                 metadataValueCellText = [metadataValueCellText stringByAppendingString:@"..."];
387             }
388             cell.textLabel.text = metadataKeyCellText;
389             cell.detailTextLabel.text = metadataValueCellText;
390         }
391     } else if (indexPath.section == policySection) {
392         cell.selectionStyle = UITableViewCellSelectionStyleBlue;
393         if (indexPath.row == 0) {
394             cell.textLabel.text = @"Versioning";
395             cell.detailTextLabel.text = container.versioning;
396             cell.accessoryType = UITableViewCellAccessoryNone;
397             cell.selectionStyle = UITableViewCellEditingStyleNone;
398         }
399         else if (indexPath.row == 1) {
400             cell.textLabel.text = @"Quota";
401             cell.detailTextLabel.text = [NSString stringWithFormat:@"%u", container.quota];
402             cell.accessoryType = UITableViewCellAccessoryNone;
403             cell.selectionStyle = UITableViewCellEditingStyleNone;
404         }
405         else {
406             cell.textLabel.text = @"Edit policy";
407             cell.detailTextLabel.text = @"";
408             cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
409         }
410     } else if (indexPath.section == deleteSection) {
411         return [self tableView:tableView deleteCellForRowAtIndexPath:indexPath];
412     } else if (indexPath.section == kLogRetention) {
413         cell.textLabel.text = @"Log Retention";
414         cell.detailTextLabel.text = @"";
415         cell.accessoryView = logRetentionSwitch;
416         cell.accessoryType = UITableViewCellAccessoryNone;
417         cell.selectionStyle = UITableViewCellSelectionStyleNone;
418     } else if (indexPath.section == kReferrerACL) {
419         cell.textLabel.text = @"Referrer ACL";
420         cell.detailTextLabel.text = container.referrerACL;
421         cell.accessoryView = nil;
422         cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
423         cell.selectionStyle = UITableViewCellSelectionStyleBlue;
424         cell.detailTextLabel.numberOfLines = 1;
425     } else if (indexPath.section == kUserAgentACL) {
426         cell.textLabel.text = @"User Agent ACL";
427         cell.detailTextLabel.text = container.useragentACL;
428         cell.accessoryView = nil;
429         cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
430         cell.selectionStyle = UITableViewCellSelectionStyleBlue;
431         cell.detailTextLabel.numberOfLines = 1;
432     }
433     
434     return cell;
435 }
436
437 #pragma mark -
438 #pragma mark Table view delegate
439
440 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
441     
442     if (indexPath.section == kMetadata) {
443         EditMetadataViewController *vc = [[EditMetadataViewController alloc] initWithNibName:@"EditMetadataViewController" bundle:nil];
444         NSString *metadataKey;
445         NSString *metadataValue;
446         
447         if (indexPath.row == [self.container.metadata count]) {
448             metadataKey = @"";
449             metadataValue = @"";
450             vc.removeMetadataEnabled = FALSE;
451             vc.navigationItem.title = @"Add Metadata";
452         }
453         else {
454             metadataKey = [[self.container.metadata allKeys] objectAtIndex:indexPath.row];
455             metadataValue = [self.container.metadata objectForKey:metadataKey];
456             vc.removeMetadataEnabled = TRUE;
457             vc.navigationItem.title = @"Edit Metadata";
458         }
459         
460         StorageObject *object = [[[StorageObject alloc] init] autorelease];
461         object.name = container.name;
462         object.metadata = container.metadata;
463         object.fullPath = @"";
464         
465         vc.metadataKey = metadataKey;
466         vc.metadataValue = metadataValue;
467         vc.account = account;
468         vc.container = container;
469         vc.object = object;
470         
471         [self.navigationController pushViewController:vc animated:YES];
472         [vc release];
473     } else if (indexPath.section == policySection) {
474         if (indexPath.row == 2) {
475             EditPolicyViewController *vc = [[EditPolicyViewController alloc] initWithNibName:@"EditPolicyViewController" bundle:nil];
476     
477             vc.account = account;
478             vc.container = container;
479             vc.containerDetailViewController = self;
480         
481             [self.navigationController pushViewController:vc animated:YES];
482             [vc release];
483         }
484     } else if (indexPath.section == deleteSection) {
485         if (self.container.count == 0 || ([self.container.rootFolder.folders count] + [self.container.rootFolder.objects count] == 0)) {
486             [deleteActionSheet showInView:self.view];
487         }
488     } else if (indexPath.section == kCDNAttributes && indexPath.row == 0) {
489         [cdnURLActionSheet showInView:self.view];
490     } else if (indexPath.section == kReferrerACL) {
491         ReferrerACLViewController *vc = [[ReferrerACLViewController alloc] initWithNibName:@"ReferrerACLViewController" bundle:nil];
492         vc.account = self.account;
493         vc.container = self.container;
494         vc.containerDetailViewController = self;
495         if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
496             vc.modalPresentationStyle = UIModalPresentationFormSheet;
497             [self presentModalViewControllerWithNavigation:vc animated:YES];
498         } else {
499             [self.navigationController pushViewController:vc animated:YES];
500         }        
501         [vc release];
502     } else if (indexPath.section == kUserAgentACL) {
503         UserAgentACLViewController *vc = [[UserAgentACLViewController alloc] initWithNibName:@"UserAgentACLViewController" bundle:nil];
504         vc.account = self.account;
505         vc.container = self.container;
506         vc.containerDetailViewController = self;
507         if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
508             vc.modalPresentationStyle = UIModalPresentationFormSheet;
509             [self presentModalViewControllerWithNavigation:vc animated:YES];
510         } else {
511             [self.navigationController pushViewController:vc animated:YES];
512         }        
513         [vc release];
514     }
515 }
516
517 #pragma mark -
518 #pragma mark Switches
519
520 - (void)cdnEnabledSwitchChanged:(id)sender {
521     
522     NSString *activityMessage = @"Disabling CDN Access...";
523     if (!container.cdnEnabled) {
524         activityMessage = @"Enabling CDN Access...";
525     }
526     activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
527     [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];    
528     container.cdnEnabled = !container.cdnEnabled;
529     [self.account.manager updateCDNContainer:container];
530     
531     successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerSucceeded" object:self.container
532                                                                          queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
533     {
534         [activityIndicatorView removeFromSuperviewAndRelease];
535         
536         NSIndexSet *sections = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(3, 4)];
537         NSInteger oldDeleteSection = deleteSection;
538         if (container.cdnEnabled) {
539             deleteSection = 6;
540             transitioning = YES;
541             [self.tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(oldDeleteSection, 1)] withRowAnimation:UITableViewRowAnimationBottom];
542             transitioning = NO;
543             [self.tableView insertSections:sections withRowAnimation:UITableViewRowAnimationBottom];
544         } else {
545             deleteSection = 2;
546             transitioning = YES;
547             [self.tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(deleteSection, 1)] withRowAnimation:UITableViewRowAnimationTop];
548             transitioning = NO;
549             [self.tableView deleteSections:sections withRowAnimation:UITableViewRowAnimationTop];
550         }
551         
552         [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
553     }];
554     
555     failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerFailed" object:self.container
556                                                                          queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
557     {
558         [activityIndicatorView removeFromSuperviewAndRelease];
559         container.cdnEnabled = !container.cdnEnabled;
560         cdnEnabledSwitch.on = !cdnEnabledSwitch.on;
561         [self alert:@"There was a problem updating this container." request:[notification.userInfo objectForKey:@"request"]];           
562         [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
563     }];
564 }
565
566 - (void)logRetentionSwitchChanged:(id)sender {
567
568     NSString *activityMessage = @"Disabling Log Retention...";
569     if (!container.logRetention) {
570         activityMessage = @"Enabling Log Retention...";
571     }
572     activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
573     [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];    
574
575     container.logRetention = !container.logRetention;
576     [self.account.manager updateCDNContainer:container];
577     
578     successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerSucceeded" object:self.container
579                                                                          queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
580        {
581            [activityIndicatorView removeFromSuperviewAndRelease];
582            [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
583        }];
584     
585     failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerFailed" object:self.container
586                                                                          queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
587        {
588            [activityIndicatorView removeFromSuperviewAndRelease];
589            container.logRetention = !container.logRetention;
590            logRetentionSwitch.on = !logRetentionSwitch.on;
591            [self alert:@"There was a problem updating this container." request:[notification.userInfo objectForKey:@"request"]];
592            [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
593        }];
594 }
595
596 #pragma mark -
597 #pragma mark Action Sheet
598
599 - (void)deleteContainerRow {
600     if ([self.account.containers count] == 0) {
601         [self.containersViewController.tableView reloadData];
602     } else {
603         [self.containersViewController.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:selectedContainerIndexPath] withRowAnimation:UITableViewRowAnimationLeft];
604     }
605     [self.rootFolderViewController.navigationController popViewControllerAnimated:YES];
606 }
607
608 - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
609     if ([actionSheet isEqual:cdnURLActionSheet]) {
610         if (buttonIndex == 0) {
611             UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
612             [pasteboard setString:container.cdnURL];
613         }
614         [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:kCDNAttributes] animated:YES];
615     } else if ([actionSheet isEqual:deleteActionSheet]) {
616         if (buttonIndex == 0) {
617          
618             NSString *activityMessage = @"Deleting container...";
619             activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
620             [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];    
621             
622             [self.account.manager deleteContainer:self.container];
623             
624             successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"deleteContainerSucceeded" object:self.container
625                                                                                  queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
626             {
627                 [activityIndicatorView removeFromSuperviewAndRelease];
628
629                 [self.account.containers removeObjectForKey:self.container.name];
630                 [self.account persist];
631                 
632                 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && [self.account.containers count] == 0) { 
633                     // on ipad, delete needs to get rid of the container on the main view
634                     self.container = nil;
635                     [self setBackgroundView];
636                     [self.tableView reloadData];
637                 } else {
638                     [self.navigationController popViewControllerAnimated:YES];
639                 }
640                 
641                 [self deleteContainerRow];
642                 //[NSTimer scheduledTimerWithTimeInterval:0.75 target:self selector:@selector(deleteContainerRow) userInfo:nil repeats:NO];
643                 
644                 [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
645             }];
646             
647             failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"deleteContainerFailed" object:self.container
648                                                                                  queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
649             {
650                 [activityIndicatorView removeFromSuperviewAndRelease];
651                 [self alert:@"There was a problem deleting this container." request:[notification.userInfo objectForKey:@"request"]];
652                 [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
653             }];
654             
655         }
656         
657         [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:deleteSection] animated:YES];
658     }
659 }
660
661
662 #pragma mark -
663 #pragma mark Memory management
664
665 - (void)dealloc {
666     [account release];
667     [container release];
668     [cdnEnabledSwitch release];
669     [ttlSlider release];
670     [cdnURLActionSheet release];
671     [deleteActionSheet release];
672     [containersViewController release];
673     [selectedContainerIndexPath release];
674     [rootFolderViewController release];
675     [super dealloc];
676 }
677
678 @end
679