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