2 // EditAccountGroupsViewController.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 "EditAccountGroupsViewController.h"
39 #import "OpenStackAccount.h"
40 #import "ActivityIndicatorView.h"
41 #import "UIViewController+Conveniences.h"
42 #import "AccountManager.h"
43 #import "OpenStackRequest.h"
44 #import "APICallback.h"
46 #define kGroupDetails 0
50 @implementation EditAccountGroupsViewController
53 @synthesize groupName, groupUsers, removeGroupEnabled;
54 @synthesize groups,metadata;
56 #pragma mark - View lifecycle
58 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
59 return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
62 #pragma mark - Memory management
73 #pragma mark - Internal
75 - (BOOL)userInputIsValid:(NSString *)input fieldName:(NSString *)fieldName {
76 if (![input length] || ![[input stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length]) {
77 [self alert:@"Invalid input" message:[NSString stringWithFormat:@"%@ field cannot be empty", fieldName]];
80 NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@"= "];
81 if ([input rangeOfCharacterFromSet:set].location != NSNotFound) {
82 [self alert:@"Invalid input" message:[NSString stringWithFormat:@"%@ field cannot contain '=' or whitespace characters", fieldName]];
88 #pragma mark - UITableViewDataSource
90 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
91 if (removeGroupEnabled)
97 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
98 if (section == kGroupDetails)
104 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
105 static NSString *CellIdentifier = @"Cell";
107 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
109 cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
112 cell.textLabel.text = @"";
113 cell.accessoryType = UITableViewCellAccessoryNone;
114 if (indexPath.section == kGroupDetails) {
115 UITextField *textField = nil;
116 for (id subView in cell.contentView.subviews) {
117 if ([subView isKindOfClass:[UITextField class]]) {
118 textField = (UITextField *)subView;
122 if (textField == nil) {
123 CGRect bounds = [cell.contentView bounds];
124 CGRect rect = CGRectInset(bounds, 10.0, 10.0);
125 textField = [[UITextField alloc] initWithFrame:rect];
126 [textField setFrame:rect];
129 [textField setClearButtonMode:UITextFieldViewModeWhileEditing];
130 [textField setBackgroundColor:[UIColor clearColor]];
131 [textField setOpaque:YES];
132 [textField setAutocorrectionType:UITextAutocorrectionTypeNo];
133 [textField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
134 [textField setDelegate:self];
135 textField.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
137 if (indexPath.row == 0) {
138 textField.returnKeyType = UIReturnKeyNext;
139 textField.placeholder = @"Group name";
140 textField.text = self.groupName;
142 } else if (indexPath.row == 1) {
143 textField.returnKeyType = UIReturnKeyDefault;
144 textField.placeholder = @"Group users";
145 textField.text = self.groupUsers;
148 cell.selectionStyle = UITableViewCellSelectionStyleNone;
149 [cell.contentView addSubview:textField];
150 } else if (indexPath.section == kSave) {
151 cell.textLabel.text = @"Save";
152 } else if (indexPath.section == kRemove) {
153 cell.textLabel.text = @"Remove";
159 #pragma mark - UITableViewDelegate
161 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
162 NSIndexPath *keyCellIndexPath;
163 NSIndexPath *valueCellIndexPath;
164 UITableViewCell *cell;
166 if (indexPath.section != kGroupDetails)
167 [self.view endEditing:YES];
169 if (indexPath.section == kSave) {
170 keyCellIndexPath = [NSIndexPath indexPathForRow:0 inSection:kGroupDetails];
171 cell = [self.tableView cellForRowAtIndexPath:keyCellIndexPath];
172 UITextField *textField = [[cell.contentView subviews] objectAtIndex:0];
173 NSString *newGroupName = textField.text;
175 if (![self userInputIsValid:newGroupName fieldName:@"Group name"]) {
176 [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
180 valueCellIndexPath = [NSIndexPath indexPathForRow:1 inSection:kGroupDetails];
181 cell = [self.tableView cellForRowAtIndexPath:valueCellIndexPath];
182 textField = [[cell.contentView subviews] objectAtIndex:0];
183 NSString *newGroupUsers = textField.text;
185 if (![self userInputIsValid:newGroupUsers fieldName:@"Group users"]) {
186 [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
190 [groups removeObjectForKey:groupName];
191 [groups setObject:newGroupUsers forKey:newGroupName];
192 NSDictionary *accountInfo = [NSDictionary dictionaryWithObjectsAndKeys:groups, @"groups",
193 metadata, @"metadata",
196 __block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Saving group..."
197 andAddToView:self.view];
198 [[self.account.manager writeAccountMetadata:accountInfo]
199 success:^(OpenStackRequest *request) {
200 [activityIndicatorView removeFromSuperview];
201 self.groupName = newGroupName;
202 self.groupUsers = newGroupUsers;
203 self.removeGroupEnabled = YES;
204 self.navigationItem.title = @"Edit Group";
205 [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
206 [self.tableView reloadData];
208 failure:^(OpenStackRequest *request) {
209 [activityIndicatorView removeFromSuperview];
210 [groups removeObjectForKey:newGroupName];
211 [groups setObject:self.groupUsers forKey:self.groupName];
212 [self.tableView reloadData];
213 [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
214 [self alert:@"There was a problem saving the group information." request:request];
216 } else if (indexPath.section == kRemove) {
217 [groups removeObjectForKey:groupName];
218 NSDictionary *accountInfo = [NSDictionary dictionaryWithObjectsAndKeys:groups, @"groups",
219 metadata, @"metadata",
222 __block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Removing group..."
223 andAddToView:self.view];
224 [[self.account.manager writeAccountMetadata:accountInfo]
225 success:^(OpenStackRequest *request) {
226 [activityIndicatorView removeFromSuperview];
227 self.groupName = @"";
228 self.groupUsers = @"";
229 self.removeGroupEnabled = NO;
230 [self.tableView reloadData];
231 [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
233 failure:^(OpenStackRequest *request) {
234 [activityIndicatorView removeFromSuperview];
235 [groups setObject:groupUsers forKey:groupName];
236 [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
237 [self alert:@"There was a problem removing the group information." request:request];
242 #pragma mark - UITextFieldDelegate
244 - (BOOL)textFieldShouldReturn:(UITextField *)textField {
245 if ([textField returnKeyType] == UIReturnKeyNext) {
246 [self userInputIsValid:textField.text fieldName:@"Group name"];
248 NSInteger nextTag = [textField tag] + 1;
249 UIView *nextTextField = [self.tableView viewWithTag:nextTag];
250 [nextTextField becomeFirstResponder];
252 [self userInputIsValid:textField.text fieldName:@"Group users"];
253 [textField resignFirstResponder];