2 // FolderDetailViewController.m
5 // Copyright 2011 GRNET S.A. All rights reserved.
7 // Redistribution and use in source and binary forms, with or
8 // without modification, are permitted provided that the following
11 // 1. Redistributions of source code must retain the above
12 // copyright notice, this list of conditions and the following
15 // 2. Redistributions in binary form must reproduce the above
16 // copyright notice, this list of conditions and the following
17 // disclaimer in the documentation and/or other materials
18 // provided with the distribution.
20 // THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
21 // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
24 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27 // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
33 // The views and conclusions contained in the software and
34 // documentation are those of the authors and should not be
35 // interpreted as representing official policies, either expressed
36 // or implied, of GRNET S.A.
38 #import "FolderDetailViewController.h"
39 #import "EditMetadataViewController.h"
40 #import "EditPermissionsViewController.h"
41 #import "StorageObject.h"
42 #import "APICallback.h"
43 #import "AccountManager.h"
44 #import "UIViewController+Conveniences.h"
45 #import "NSString+Conveniences.h"
49 #define kPermissions 2
51 #define maxMetadataViewableLength 12
54 @implementation FolderDetailViewController
56 @synthesize account, container, folder, folderViewController;
59 #pragma mark Memory management
66 [folderViewController release];
68 [permissions release];
72 - (void)didReceiveMemoryWarning
74 // Releases the view if it doesn't have a superview.
75 [super didReceiveMemoryWarning];
77 // Release any cached data, images, etc that aren't in use.
80 #pragma mark - View lifecycle
85 permissions = [[NSMutableDictionary alloc] init];
86 if (folder.sharing.length > 0) {
87 NSArray *sharingArray = [folder.sharing componentsSeparatedByString:@";"];
88 for (NSString *typeSpecificPermissions in sharingArray) {
89 NSArray *array=[typeSpecificPermissions componentsSeparatedByString:@"="];
90 NSString *permissionsType = [array objectAtIndex:0];
91 if ([permissionsType hasPrefix:@" "])
92 permissionsType = [permissionsType substringFromIndex:1];
94 NSArray *users = [[array objectAtIndex:1] componentsSeparatedByString:@","];
95 for (NSString *user in users) {
96 [permissions setObject:permissionsType forKey:user];
101 folderIsReadOnly = NO;
102 if (account.sharingAccount) {
103 if ([permissions count] > 0) {
104 folderIsReadOnly = [[permissions objectForKey:[account username]] isEqualToString:@"read"];
108 object = [[StorageObject alloc] init];
109 object.name = folder.name;
110 object.metadata = folder.metadata;
111 object.fullPath = [folder fullPath];
112 object.sharing = folder.sharing;
113 object.contentType = folder.contentType;
116 - (void)viewDidUnload
118 [super viewDidUnload];
121 - (void)viewWillAppear:(BOOL)animated
123 [super viewWillAppear:animated];
124 [self.tableView reloadData];
127 - (void)viewDidAppear:(BOOL)animated
129 [super viewDidAppear:animated];
130 if (folder.metadata == nil) {
131 [self reloadMetadataSection];
135 - (void)viewWillDisappear:(BOOL)animated
137 [super viewWillDisappear:animated];
138 folder.sharing = object.sharing;
141 - (void)viewDidDisappear:(BOOL)animated
143 [super viewDidDisappear:animated];
146 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
147 return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
150 #pragma mark - Table view data source
152 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
157 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
159 if (section == kOverview)
161 else if (section == kPermissions) {
162 if (account.sharingAccount)
163 return [permissions count];
165 return 1 + [permissions count];
167 else if (section == kMetadata)
168 if (folderIsReadOnly)
169 return [folder.metadata count];
171 return 1 + [folder.metadata count];
175 - (CGFloat)findLabelHeight:(NSString*)text font:(UIFont *)font {
176 CGSize textLabelSize;
177 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
178 textLabelSize = CGSizeMake(537.0, 9000.0f);
180 textLabelSize = CGSizeMake(221.0, 9000.0f);
183 CGSize stringSize = [text sizeWithFont:font constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeCharacterWrap];
184 return stringSize.height;
187 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
190 if (indexPath.section == kOverview) {
191 if (indexPath.row == 0) {
192 result = 22 + [self findLabelHeight:folder.name font:[UIFont systemFontOfSize:18.0]];
194 return MAX(tableView.rowHeight, result);
195 } else if (indexPath.row == 1) {
196 NSString *folderFullPathToShow = folder.fullPath;
197 if ([folderFullPathToShow hasPrefix:@"/"]) {
198 folderFullPathToShow = [folderFullPathToShow substringFromIndex:1];
200 result = 22 + [self findLabelHeight:folderFullPathToShow font:[UIFont systemFontOfSize:18.0]];
202 return MAX(tableView.rowHeight, result);
206 return tableView.rowHeight;
210 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
212 static NSString *CellIdentifier = @"Cell";
214 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
216 cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
218 cell.textLabel.backgroundColor = [UIColor clearColor];
219 cell.detailTextLabel.backgroundColor = [UIColor clearColor];
220 cell.detailTextLabel.numberOfLines = 0;
221 cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
222 cell.detailTextLabel.textAlignment = UITextAlignmentRight;
225 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
226 cell.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.8];
229 if (indexPath.section == kOverview) {
230 cell.accessoryType = UITableViewCellAccessoryNone;
231 cell.selectionStyle = UITableViewCellSelectionStyleNone;
232 cell.accessoryView = nil;
233 if (indexPath.row == 0) {
234 cell.textLabel.text = @"Name";
235 cell.detailTextLabel.text = folder.name;
236 } else if (indexPath.row == 1) {
237 cell.textLabel.text = @"Full Path";
238 NSString *folderFullPathToShow = folder.fullPath;
239 if ([folderFullPathToShow hasPrefix:@"/"]) {
240 folderFullPathToShow = [folderFullPathToShow substringFromIndex:1];
242 cell.detailTextLabel.text = folderFullPathToShow;
244 } else if (indexPath.section == kMetadata) {
245 if (folderIsReadOnly) {
246 cell.accessoryType = UITableViewCellAccessoryNone;
247 cell.selectionStyle = UITableViewCellSelectionStyleNone;
248 cell.userInteractionEnabled = NO;
251 cell.selectionStyle = UITableViewCellSelectionStyleBlue;
252 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
254 cell.accessoryView = nil;
255 if (indexPath.row == [folder.metadata count]) {
256 cell.textLabel.text = @"Add Metadata";
257 cell.detailTextLabel.text = @"";
259 NSString *key = [[folder.metadata allKeys] objectAtIndex:indexPath.row];
260 NSString *value = [folder.metadata objectForKey:key];
261 NSString *metadataKeyCellText = key;
262 NSString *metadataValueCellText = value;
263 if ([metadataKeyCellText length] > maxMetadataViewableLength) {
264 metadataKeyCellText = [metadataKeyCellText substringToIndex:(maxMetadataViewableLength - 3)];
265 metadataKeyCellText = [metadataKeyCellText stringByAppendingString:@"..."];
267 if ([metadataValueCellText length] > maxMetadataViewableLength) {
268 metadataValueCellText = [metadataValueCellText substringToIndex:(maxMetadataViewableLength - 3)];
269 metadataValueCellText = [metadataValueCellText stringByAppendingString:@"..."];
272 cell.textLabel.text = metadataKeyCellText;
273 cell.detailTextLabel.text = metadataValueCellText;
275 } else if (indexPath.section == kPermissions) {
276 if (account.sharingAccount) {
277 cell.accessoryType = UITableViewCellAccessoryNone;
278 cell.selectionStyle = UITableViewCellSelectionStyleNone;
279 cell.userInteractionEnabled = NO;
282 cell.selectionStyle = UITableViewCellSelectionStyleBlue;
283 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
285 cell.accessoryView = nil;
287 if (indexPath.row == [permissions count]) {
288 cell.textLabel.text = @"Share";
289 cell.detailTextLabel.text = @"";
292 NSString *user = [[permissions allKeys] objectAtIndex:indexPath.row];
293 cell.textLabel.text = user;
294 cell.detailTextLabel.text = [permissions objectForKey:user];
302 #pragma mark - Table view delegate
304 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
306 if (indexPath.section == kMetadata) {
307 EditMetadataViewController *vc = [[EditMetadataViewController alloc] initWithNibName:@"EditMetadataViewController" bundle:nil];
308 NSString *metadataKey;
309 NSString *metadataValue;
311 if (indexPath.row == [self.folder.metadata count]) {
314 vc.removeMetadataEnabled = FALSE;
315 vc.navigationItem.title = @"Add Metadata";
318 metadataKey = [[self.folder.metadata allKeys] objectAtIndex:indexPath.row];
319 metadataValue = [self.folder.metadata objectForKey:metadataKey];
320 vc.removeMetadataEnabled = TRUE;
321 vc.navigationItem.title = @"Edit Metadata";
324 vc.metadataKey = metadataKey;
325 vc.metadataValue = metadataValue;
326 vc.account = account;
327 vc.container = container;
329 vc.objectIsFolder = YES;
330 vc.folderViewController = folderViewController;
332 [self.navigationController pushViewController:vc animated:YES];
334 } else if (indexPath.section == kPermissions) {
335 EditPermissionsViewController *vc = [[EditPermissionsViewController alloc] initWithNibName:@"EditPermissionsViewController" bundle:nil];
338 if (indexPath.row == [permissions count]) {
340 vc.removePermissionsEnabled = NO;
341 vc.navigationItem.title = @"Share";
344 user = [[permissions allKeys] objectAtIndex:indexPath.row];
345 NSString *userPermissions = [permissions objectForKey:user];
346 if ([userPermissions rangeOfString:@"read"].location != NSNotFound)
347 vc.readPermissionSelected = YES;
349 vc.readPermissionSelected = NO;
351 if ([userPermissions rangeOfString:@"write"].location != NSNotFound)
352 vc.writePermissionSelected = YES;
354 vc.writePermissionSelected = NO;
356 vc.removePermissionsEnabled = YES;
357 vc.navigationItem.title = @"Edit Sharing";
361 vc.permissions = permissions;
362 vc.account = account;
363 vc.container = container;
365 vc.objectIsFolder = YES;
366 vc.folderViewController = folderViewController;
367 [self.navigationController pushViewController:vc animated:YES];
373 #pragma mark Helper functions
375 - (void)reloadMetadataSection {
376 NSString *activityMessage = @"Loading metadata...";
377 ActivityIndicatorView *activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
378 [activityIndicatorView addToView:self.view];
379 [[self.account.manager getObjectInfo:container object:object version:nil]
380 success:^(OpenStackRequest *request) {
381 [activityIndicatorView removeFromSuperviewAndRelease];
382 folder.metadata = [NSMutableDictionary dictionary];
383 for (NSString *header in request.responseHeaders) {
384 NSString *metadataKey;
385 NSString *metadataValue;
386 if ([header rangeOfString:@"X-Object-Meta-"].location != NSNotFound) {
387 metadataKey = [NSString decodeFromPercentEscape:[header substringFromIndex:14]];
388 metadataValue = [NSString decodeFromPercentEscape:[request.responseHeaders objectForKey:header]];
389 [folder.metadata setObject:metadataValue forKey:metadataKey];
392 object.metadata = folder.metadata;
393 NSIndexSet *metadataSections = [NSIndexSet indexSetWithIndex:kMetadata];
394 [self.tableView reloadSections:metadataSections withRowAnimation:UITableViewRowAnimationFade];
396 failure:^(OpenStackRequest *request) {
397 [activityIndicatorView removeFromSuperviewAndRelease];
398 [self alert:@"There was a problem retrieving the object's metadata." request:request];