// // EditMetadataViewController.m // pithos-ios // // Copyright 2011 GRNET S.A. All rights reserved. // // Redistribution and use in source and binary forms, with or // without modification, are permitted provided that the following // conditions are met: // // 1. Redistributions of source code must retain the above // copyright notice, this list of conditions and the following // disclaimer. // // 2. Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials // provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // The views and conclusions contained in the software and // documentation are those of the authors and should not be // interpreted as representing official policies, either expressed // or implied, of GRNET S.A. #import "EditMetadataViewController.h" #import "AccountManager.h" #import "UIViewController+Conveniences.h" #import "FolderViewController.h" #import "Folder.h" #import "PithosUtilities.h" #import "APICallback.h" @implementation EditMetadataViewController @synthesize container, account, object; @synthesize metadataKey; @synthesize metadataValue; @synthesize userInputMetaKey, userInputMetaValue; @synthesize removeMetadataEnabled, objectIsFolder, folderViewController, objectIsContainer; #define kMetadata 0 #define kSaveMedata 1 #define kDeleteMetadata 2 - (void)dealloc { [account release]; [container release]; [object release]; [metadataKey release]; [metadataValue release]; [userInputMetaKey release]; [userInputMetaValue release]; [activityIndicatorView release]; [super dealloc]; } - (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } #pragma mark - View lifecycle - (void)viewDidLoad { [super viewDidLoad]; } - (void)viewDidUnload { [super viewDidUnload]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait); } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return (removeMetadataEnabled)? 3:2; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (section == kMetadata) return 2; else return 1; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; } if (indexPath.section == kMetadata) { UITextField *textField = nil; for (id subView in cell.contentView.subviews) { if ([subView isKindOfClass:[UITextField class]]) { textField = (UITextField *)subView; } } if (textField == nil) { CGRect bounds = [cell.contentView bounds]; CGRect rect = CGRectInset(bounds, 10.0, 10.0); textField = [[UITextField alloc] initWithFrame:rect]; [textField setFrame:rect]; } [textField setClearButtonMode:UITextFieldViewModeWhileEditing]; [textField setBackgroundColor:[UIColor clearColor]]; [textField setOpaque:YES]; [textField setAutocorrectionType:UITextAutocorrectionTypeNo]; [textField setAutocapitalizationType:UITextAutocapitalizationTypeNone]; [textField setDelegate:self]; textField.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; if (indexPath.row == 0) { [textField setReturnKeyType:UIReturnKeyNext]; textField.placeholder = @"Key"; textField.text = self.metadataKey; textField.tag = 0; } else if (indexPath.row == 1) { textField.placeholder = @"Value"; textField.text = self.metadataValue; textField.tag = 1; } cell.selectionStyle = UITableViewCellSelectionStyleNone; [cell.contentView addSubview:textField]; } else if (indexPath.section == kSaveMedata) cell.textLabel.text = @"Save"; else if (indexPath.section == kDeleteMetadata) cell.textLabel.text = @"Remove"; return cell; } #pragma mark - Table view delegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section != kMetadata) [self.view endEditing:YES]; NSString *activityMessage; NSIndexPath *keyCellIndexPath; NSIndexPath *valueCellIndexPath; UITableViewCell *cell; switch (indexPath.section) { case kSaveMedata: keyCellIndexPath = [NSIndexPath indexPathForRow:0 inSection:kMetadata]; cell = [self.tableView cellForRowAtIndexPath:keyCellIndexPath]; UITextField *textField = [[cell.contentView subviews] objectAtIndex:0]; self.userInputMetaKey = textField.text; if ([userInputMetaKey length] == 0 || [[userInputMetaKey stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0) { [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; [self alert:@"Invalid input" message:@"Metadata key cannot be empty"]; return; } valueCellIndexPath = [NSIndexPath indexPathForRow:1 inSection:kMetadata]; cell = [self.tableView cellForRowAtIndexPath:valueCellIndexPath]; textField = [[cell.contentView subviews] objectAtIndex:0]; self.userInputMetaValue = textField.text; [object.metadata removeObjectForKey:metadataKey]; [object.metadata setObject:userInputMetaValue forKey:userInputMetaKey]; if (objectIsFolder && ![PithosUtilities isContentTypeDirectory:object.contentType]) { if (((UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) && [folderViewController.parentFolderViewController.folder.objects objectForKey:object.name]) || ((UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) && [folderViewController.folder.objects objectForKey:object.name])) { NSString *alertMessage = [NSString stringWithFormat:@"In order to apply the changes in '%@', the object at the same path must be replaced. Continue?",object.name]; NSString *alertTitle = @"Apply changes"; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:alertTitle message:alertMessage delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil]; [alert show]; [alert release]; return; } else { activityMessage = @"Saving metadata..."; [activityIndicatorView release]; activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage]; [activityIndicatorView addToView:self.view]; object.name = object.fullPath; object.contentType = @"application/directory"; object.data = [NSData data]; [self createNewFolder]; return; } } activityMessage = @"Saving metadata"; [activityIndicatorView release]; activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage]; [activityIndicatorView addToView:self.view]; [[self.account.manager writeObjectMetadata:container object:object] success:^(OpenStackRequest *request) { self.metadataKey = userInputMetaKey; self.metadataValue = userInputMetaValue; removeMetadataEnabled = YES; [self.tableView reloadData]; [activityIndicatorView removeFromSuperview]; [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; if (objectIsContainer) { container.metadata = object.metadata; [self.account.containers setObject:container forKey:container.name]; } } failure:^(OpenStackRequest *request) { [object.metadata removeObjectForKey:userInputMetaKey]; [object.metadata setObject:metadataValue forKey:metadataKey]; [activityIndicatorView removeFromSuperview]; [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; [self alert:@"There was a problem saving the metadata." request:request]; }]; break; case kDeleteMetadata: activityMessage = @"Deleting metadata"; [activityIndicatorView release]; activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage]; [activityIndicatorView addToView:self.view]; [object.metadata removeObjectForKey:metadataKey]; [[self.account.manager writeObjectMetadata:container object:object] success:^(OpenStackRequest *request) { [activityIndicatorView removeFromSuperview]; [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; self.metadataKey = @""; self.metadataValue = @""; removeMetadataEnabled = NO; [self.tableView reloadData]; if (objectIsContainer) { container.metadata = object.metadata; [self.account.containers setObject:container forKey:container.name]; } } failure:^(OpenStackRequest *request) { [object.metadata setObject:metadataValue forKey:metadataKey]; [activityIndicatorView removeFromSuperview]; [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; [self alert:@"There was a problem saving the metadata." request:request]; }]; break; } } #pragma mark - Alertview delegate - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { if (buttonIndex == 1) { NSString *activityMessage = @"Applying permissions..."; [activityIndicatorView release]; activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage]; [activityIndicatorView addToView:self.view]; object.name = object.fullPath; object.contentType = @"application/directory"; object.data = [NSData data]; [self createNewFolder]; } else { [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES]; } } #pragma mark - Textfield delegate - (BOOL)textFieldShouldReturn:(UITextField *)textField { if ([textField returnKeyType] == UIReturnKeyNext) { if ([textField.text length] == 0 || [[textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0) { [self alert:@"Invalid input" message:@"Metadata key cannot be empty"]; } NSInteger nextTag = [textField tag] + 1; UIView *nextTextField = [self.tableView viewWithTag:nextTag]; [nextTextField becomeFirstResponder]; } else { [textField resignFirstResponder]; } return YES; } #pragma mark - add observers - (void)createNewFolder { [[self.account.manager writeObject:container object:object downloadProgressDelegate:nil] success:^(OpenStackRequest *request) { Folder *newFolder = [[Folder alloc] init]; newFolder.name = [[object.name componentsSeparatedByString:@"/"] lastObject]; newFolder.parent = folderViewController.folder; newFolder.sharing = folderViewController.folder.sharing; newFolder.metadata = object.metadata; [folderViewController.folder addFolder:newFolder]; [activityIndicatorView removeFromSuperview]; [newFolder release]; self.metadataKey = userInputMetaKey; self.metadataValue = userInputMetaValue; removeMetadataEnabled = YES; [self.tableView reloadData]; [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES]; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { [self.folderViewController refreshButtonPressed:nil]; } else { self.folderViewController.needsRefreshing = YES; self.folderViewController.refreshWhenAppeared = YES; } } failure:^(OpenStackRequest *request) { [object.metadata removeObjectForKey:userInputMetaKey]; [object.metadata setObject:metadataValue forKey:metadataKey]; [activityIndicatorView removeFromSuperview]; [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES]; [self.tableView reloadData]; [self alert:@"There was a problem saving the metadata." request:request]; }]; } @end