root / Classes / ContainerDetailViewController.m @ c2940e36
History | View | Annotate | Download (15.5 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 "ContainersViewController.h" |
17 |
#import "EditMetadataViewController.h" |
18 |
#import "EditPolicyViewController.h" |
19 |
#import "Folder.h" |
20 |
#import "StorageObject.h" |
21 |
#import "FolderViewController.h" |
22 |
#import "OpenStackRequest.h" |
23 |
#import "APICallback.h" |
24 |
#import "NSString+Conveniences.h" |
25 |
|
26 |
#define kOverview 0 |
27 |
#define kMetadata 1 |
28 |
|
29 |
#define maxMetadataViewableLength 12 |
30 |
|
31 |
@implementation ContainerDetailViewController |
32 |
|
33 |
@synthesize account, container, containersViewController, selectedContainerIndexPath, rootFolderViewController; |
34 |
|
35 |
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { |
36 |
return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait); |
37 |
} |
38 |
|
39 |
- (void)setBackgroundView { |
40 |
if (!self.container) { |
41 |
UIView *viewContainer = [[UIView alloc] init]; |
42 |
viewContainer.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; |
43 |
viewContainer.backgroundColor = [UIColor iPadTableBackgroundColor]; |
44 |
|
45 |
UILabel *label = [[UILabel alloc] init]; |
46 |
label.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin; |
47 |
label.backgroundColor = [UIColor clearColor]; |
48 |
label.textColor = [UIColor emptyCollectionGrayColor]; |
49 |
label.font = [UIFont boldSystemFontOfSize:18.0]; |
50 |
label.text = @"No container selected"; |
51 |
label.textAlignment = UITextAlignmentCenter; |
52 |
[viewContainer addSubview:label]; |
53 |
[label release]; |
54 |
|
55 |
self.tableView.backgroundView = viewContainer; |
56 |
[viewContainer release]; |
57 |
} |
58 |
} |
59 |
|
60 |
#pragma mark - |
61 |
#pragma mark View lifecycle |
62 |
|
63 |
- (void)viewDidLoad { |
64 |
[super viewDidLoad]; |
65 |
if (!account.sharingAccount) { |
66 |
deleteSection = 3; |
67 |
policySection = 2; |
68 |
} else { |
69 |
deleteSection = -1; |
70 |
policySection = -1; |
71 |
} |
72 |
} |
73 |
|
74 |
- (void)viewWillAppear:(BOOL)animated { |
75 |
[super viewWillAppear:animated]; |
76 |
if (container) { |
77 |
self.navigationItem.title = container.name; |
78 |
} |
79 |
[self setBackgroundView]; |
80 |
[self.tableView reloadData]; |
81 |
} |
82 |
|
83 |
- (void)viewDidAppear:(BOOL)animated { |
84 |
[super viewDidAppear:animated]; |
85 |
if (self.container && !container.metadata && ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone)) |
86 |
[self reloadMetadataSection]; |
87 |
} |
88 |
|
89 |
- (void)viewWillDisappear:(BOOL)animated { |
90 |
[super viewWillDisappear:animated]; |
91 |
} |
92 |
|
93 |
#pragma mark - |
94 |
#pragma mark Table view data source |
95 |
|
96 |
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { |
97 |
if (section == deleteSection) { |
98 |
return @"Only empty containers can be deleted."; |
99 |
} else { |
100 |
return @""; |
101 |
} |
102 |
} |
103 |
|
104 |
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { |
105 |
if (self.container) { |
106 |
if (account.sharingAccount) |
107 |
return 2; |
108 |
else |
109 |
return 4; |
110 |
} else { |
111 |
return 0; |
112 |
} |
113 |
} |
114 |
|
115 |
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { |
116 |
// Return the number of rows in the section. |
117 |
if (section == kOverview) { |
118 |
return 2; |
119 |
} else if (section == kMetadata) { |
120 |
if (account.sharingAccount) |
121 |
return [container.metadata count]; |
122 |
else |
123 |
return 1 + [container.metadata count]; |
124 |
} else if (section == policySection) { |
125 |
if (account.sharingAccount) |
126 |
return 2; |
127 |
else |
128 |
return 3; |
129 |
} else { |
130 |
return 1; |
131 |
} |
132 |
} |
133 |
|
134 |
// Customize the appearance of table view cells. |
135 |
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { |
136 |
if (indexPath.section == deleteSection) { |
137 |
static NSString *CellIdentifier = @"DeleteCell"; |
138 |
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; |
139 |
if (cell == nil) { |
140 |
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; |
141 |
cell.textLabel.textAlignment = UITextAlignmentCenter; |
142 |
cell.textLabel.text = @"Delete Container"; |
143 |
} |
144 |
if ((self.container.count == 0) || |
145 |
(self.container.rootFolder && !self.container.rootFolder.objectsAndFoldersCount)) { |
146 |
cell.textLabel.textColor = [UIColor blackColor]; |
147 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue; |
148 |
} else { |
149 |
cell.textLabel.textColor = [UIColor grayColor]; |
150 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
151 |
cell.userInteractionEnabled = NO; |
152 |
} |
153 |
return cell; |
154 |
} |
155 |
|
156 |
static NSString *CellIdentifier = @"Cell"; |
157 |
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; |
158 |
if (cell == nil) { |
159 |
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease]; |
160 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
161 |
cell.textLabel.backgroundColor = [UIColor clearColor]; |
162 |
cell.detailTextLabel.backgroundColor = [UIColor clearColor]; |
163 |
cell.detailTextLabel.numberOfLines = 0; |
164 |
cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap; |
165 |
cell.detailTextLabel.textAlignment = UITextAlignmentLeft; |
166 |
} |
167 |
cell.accessoryType = UITableViewCellAccessoryNone; |
168 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
169 |
|
170 |
if (indexPath.section == kOverview) { |
171 |
cell.accessoryView = nil; |
172 |
if (indexPath.row == 0) { |
173 |
cell.textLabel.text = @"Name"; |
174 |
cell.detailTextLabel.text = container.name; |
175 |
} else if (indexPath.row == 1) { |
176 |
cell.textLabel.text = @"Size"; |
177 |
cell.detailTextLabel.text = [container humanizedSize]; |
178 |
} |
179 |
} else if (indexPath.section == kMetadata) { |
180 |
if (account.sharingAccount) { |
181 |
cell.accessoryType = UITableViewCellAccessoryNone; |
182 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
183 |
cell.userInteractionEnabled = NO; |
184 |
} |
185 |
else { |
186 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue; |
187 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
188 |
} |
189 |
if (indexPath.row == [container.metadata count]) { |
190 |
cell.textLabel.text = @"Add Metadata"; |
191 |
cell.detailTextLabel.text = @""; |
192 |
} else { |
193 |
NSString *key = [[container.metadata allKeys] objectAtIndex:indexPath.row]; |
194 |
NSString *value = [container.metadata objectForKey:key]; |
195 |
NSString *metadataKeyCellText = key; |
196 |
NSString *metadataValueCellText = value; |
197 |
if ([metadataKeyCellText length] > maxMetadataViewableLength) { |
198 |
metadataKeyCellText = [metadataKeyCellText substringToIndex:(maxMetadataViewableLength - 3)]; |
199 |
metadataKeyCellText = [metadataKeyCellText stringByAppendingString:@"..."]; |
200 |
} |
201 |
if ([metadataValueCellText length] > maxMetadataViewableLength) { |
202 |
metadataValueCellText = [metadataValueCellText substringToIndex:(maxMetadataViewableLength - 3)]; |
203 |
metadataValueCellText = [metadataValueCellText stringByAppendingString:@"..."]; |
204 |
} |
205 |
cell.textLabel.text = metadataKeyCellText; |
206 |
cell.detailTextLabel.text = metadataValueCellText; |
207 |
} |
208 |
} else if (indexPath.section == policySection) { |
209 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue; |
210 |
if (indexPath.row == 0) { |
211 |
cell.textLabel.text = @"Versioning"; |
212 |
cell.detailTextLabel.text = container.versioning; |
213 |
cell.accessoryType = UITableViewCellAccessoryNone; |
214 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
215 |
} |
216 |
else if (indexPath.row == 1) { |
217 |
cell.textLabel.text = @"Quota"; |
218 |
cell.detailTextLabel.text = [NSString stringWithFormat:@"%u", container.quota]; |
219 |
cell.accessoryType = UITableViewCellAccessoryNone; |
220 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
221 |
} |
222 |
else { |
223 |
cell.textLabel.text = @"Edit policy"; |
224 |
cell.detailTextLabel.text = @""; |
225 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
226 |
} |
227 |
} |
228 |
|
229 |
return cell; |
230 |
} |
231 |
|
232 |
#pragma mark - |
233 |
#pragma mark Table view delegate |
234 |
|
235 |
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { |
236 |
|
237 |
if (indexPath.section == kMetadata) { |
238 |
EditMetadataViewController *vc = [[EditMetadataViewController alloc] initWithNibName:@"EditMetadataViewController" bundle:nil]; |
239 |
NSString *metadataKey; |
240 |
NSString *metadataValue; |
241 |
|
242 |
if (indexPath.row == [self.container.metadata count]) { |
243 |
metadataKey = @""; |
244 |
metadataValue = @""; |
245 |
vc.removeMetadataEnabled = FALSE; |
246 |
vc.navigationItem.title = @"Add Metadata"; |
247 |
} |
248 |
else { |
249 |
metadataKey = [[self.container.metadata allKeys] objectAtIndex:indexPath.row]; |
250 |
metadataValue = [self.container.metadata objectForKey:metadataKey]; |
251 |
vc.removeMetadataEnabled = TRUE; |
252 |
vc.navigationItem.title = @"Edit Metadata"; |
253 |
} |
254 |
|
255 |
StorageObject *object = [[[StorageObject alloc] init] autorelease]; |
256 |
object.name = container.name; |
257 |
object.metadata = container.metadata; |
258 |
object.fullPath = @""; |
259 |
|
260 |
vc.metadataKey = metadataKey; |
261 |
vc.metadataValue = metadataValue; |
262 |
vc.account = account; |
263 |
vc.container = container; |
264 |
vc.object = object; |
265 |
vc.objectIsContainer = YES; |
266 |
|
267 |
[self.navigationController pushViewController:vc animated:YES]; |
268 |
[vc release]; |
269 |
} else if (indexPath.section == policySection) { |
270 |
if (indexPath.row == 2) { |
271 |
EditPolicyViewController *vc = [[EditPolicyViewController alloc] initWithNibName:@"EditPolicyViewController" bundle:nil]; |
272 |
|
273 |
vc.account = account; |
274 |
vc.container = container; |
275 |
vc.containerDetailViewController = self; |
276 |
|
277 |
[self.navigationController pushViewController:vc animated:YES]; |
278 |
[vc release]; |
279 |
} |
280 |
} else if (indexPath.section == deleteSection) { |
281 |
if (self.container.count == 0 || !self.container.rootFolder.objectsAndFoldersCount) { |
282 |
UIActionSheet *deleteActionSheet = [[[UIActionSheet alloc] initWithTitle:@"Are you sure you want to delete this container? This operation cannot be undone." |
283 |
delegate:self |
284 |
cancelButtonTitle:@"Cancel" |
285 |
destructiveButtonTitle:@"Delete Container" |
286 |
otherButtonTitles:nil] autorelease]; |
287 |
[deleteActionSheet showInView:self.view]; |
288 |
} |
289 |
} |
290 |
} |
291 |
|
292 |
#pragma mark - |
293 |
#pragma mark Action Sheet |
294 |
|
295 |
- (void)deleteContainerRow { |
296 |
if ([self.account.containers count] == 0) { |
297 |
[self.containersViewController.tableView reloadData]; |
298 |
} else { |
299 |
[self.containersViewController.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:selectedContainerIndexPath] withRowAnimation:UITableViewRowAnimationLeft]; |
300 |
} |
301 |
[self.rootFolderViewController.navigationController popViewControllerAnimated:YES]; |
302 |
} |
303 |
|
304 |
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { |
305 |
if (buttonIndex == 0) { |
306 |
__block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Deleting container..." |
307 |
andAddToView:self.view |
308 |
scrollOffset:self.tableView.contentOffset.y]; |
309 |
[[self.account.manager deleteContainer:self.container] |
310 |
success:^(OpenStackRequest *request) { |
311 |
[activityIndicatorView stopAnimatingAndRemoveFromSuperview]; |
312 |
[self.account.containers removeObjectForKey:self.container.name]; |
313 |
[self.account persist]; |
314 |
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { |
315 |
[self.containersViewController.navigationController popViewControllerAnimated:YES]; |
316 |
} else { |
317 |
[self.navigationController popViewControllerAnimated:YES]; |
318 |
} |
319 |
[self deleteContainerRow]; |
320 |
} |
321 |
failure:^(OpenStackRequest *request) { |
322 |
[activityIndicatorView stopAnimatingAndRemoveFromSuperview]; |
323 |
// 404 Not Found means it's not there, so we can show the user that it's deleted |
324 |
if ([request responseStatusCode] == 404) { |
325 |
[self.account.containers removeObjectForKey:container.name]; |
326 |
[self.account persist]; |
327 |
} else { |
328 |
[self alert:@"There was a problem deleting this container." request:request]; |
329 |
} |
330 |
}]; |
331 |
} |
332 |
[self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:deleteSection] animated:YES]; |
333 |
} |
334 |
|
335 |
|
336 |
#pragma mark - |
337 |
#pragma mark Memory management |
338 |
|
339 |
- (void)dealloc { |
340 |
[account release]; |
341 |
[container release]; |
342 |
[containersViewController release]; |
343 |
[selectedContainerIndexPath release]; |
344 |
[rootFolderViewController release]; |
345 |
[super dealloc]; |
346 |
} |
347 |
|
348 |
#pragma mark - |
349 |
#pragma mark Helper functions |
350 |
|
351 |
- (void)reloadMetadataSection { |
352 |
__block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Loading metadata..." |
353 |
andAddToView:self.view |
354 |
scrollOffset:self.tableView.contentOffset.y]; |
355 |
[[self.account.manager getContainerInfo:container] |
356 |
success:^(OpenStackRequest *request) { |
357 |
[activityIndicatorView stopAnimatingAndRemoveFromSuperview]; |
358 |
container.metadata = [NSMutableDictionary dictionary]; |
359 |
for (NSString *header in request.responseHeaders) { |
360 |
NSString *metadataKey; |
361 |
NSString *metadataValue; |
362 |
if ([header rangeOfString:@"X-Container-Meta-"].location != NSNotFound) { |
363 |
metadataKey = [NSString decodeFromPercentEscape:[header substringFromIndex:17]]; |
364 |
metadataValue = [NSString decodeFromPercentEscape:[request.responseHeaders objectForKey:header]]; |
365 |
[container.metadata setObject:metadataValue forKey:metadataKey]; |
366 |
} |
367 |
} |
368 |
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:kMetadata] withRowAnimation:UITableViewRowAnimationFade]; |
369 |
} |
370 |
failure:^(OpenStackRequest *request) { |
371 |
[activityIndicatorView stopAnimatingAndRemoveFromSuperview]; |
372 |
[self alert:@"There was a problem retrieving the container's metadata." request:request]; |
373 |
}]; |
374 |
} |
375 |
|
376 |
@end |
377 |
|