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 |
|