2 // AccountGroupsViewController.m
5 // Copyright 2011-2013 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 "AccountGroupsViewController.h"
39 #import "OpenStackAccount.h"
40 #import "ActivityIndicatorView.h"
41 #import "AccountManager.h"
42 #import "OpenStackRequest.h"
43 #import "EditAccountGroupsViewController.h"
44 #import "UIViewController+Conveniences.h"
45 #import "NSString+Conveniences.h"
46 #import "APICallback.h"
48 @implementation AccountGroupsViewController
50 @synthesize account, groups, metadata;
52 #pragma mark - View lifecycle
54 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
55 return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
58 - (void)viewWillAppear:(BOOL)animated {
59 [super viewWillAppear:animated];
60 self.navigationItem.title = @"Groups";
63 - (void)viewDidAppear:(BOOL)animated {
64 [super viewDidAppear:animated];
65 __block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Loading groups..."
66 andAddToView:self.view];
67 [[self.account.manager getStorageAccountInfo]
68 success:^(OpenStackRequest *request) {
69 self.groups = [NSMutableDictionary dictionary];
70 self.metadata = [NSMutableDictionary dictionary];
72 for (NSString *headerName in request.responseHeaders) {
73 if ([headerName hasPrefix:@"X-Account-Group-"]) {
74 [groups setObject:[[NSString decodeFromPercentEscape:[request.responseHeaders objectForKey:headerName]] componentsSeparatedByString:@","]
75 forKey:[NSString decodeFromPercentEscape:[headerName substringFromIndex:16]]];
76 } else if ([headerName hasPrefix:@"X-Account-Meta-"]) {
77 [metadata setObject:[NSString decodeFromPercentEscape:[request.responseHeaders objectForKey:headerName]]
78 forKey:[NSString decodeFromPercentEscape:[headerName substringFromIndex:15]]];
82 NSMutableArray *UUIDs = [NSMutableArray array];
83 for (NSString *groupName in groups) {
84 [UUIDs addObjectsFromArray:[groups objectForKey:groupName]];
87 [[self.account.manager userCatalogForDisplaynames:nil UUIDs:UUIDs]
88 success:^(OpenStackRequest *request) {
89 [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
90 [self.tableView reloadData];
92 failure:^(OpenStackRequest *request) {
93 [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
94 [self.tableView reloadData];
95 if (request.responseStatusCode != 404) {
96 // Don't show alert on 404, since it can be a pre-UUID server.
97 [self alert:@"Failed to translate group UUIDs." request:request];
101 [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
102 [self.tableView reloadData];
105 failure:^(OpenStackRequest *request) {
106 [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
107 [self alert:@"Failed to get account information." request:request];
111 #pragma mark - Internal
113 - (NSMutableArray *)groupUsersForGroupName:(NSString *)groupName {
114 NSArray *groupUUIDs = [groups objectForKey:groupName];
115 NSMutableArray *groupUsers = [NSMutableArray arrayWithCapacity:groupUUIDs.count];
116 for (NSString *UUID in groupUUIDs) {
117 [groupUsers addObject:[self.account displaynameForUUID:UUID safe:YES]];
122 - (NSMutableString *)groupUsersStringForGroupName:(NSString *)groupName {
123 NSMutableArray *groupUsers = [self groupUsersForGroupName:groupName];
124 NSMutableString *groupUsersString = [NSMutableString string];
125 for (NSUInteger index = 0; index < groupUsers.count; index++) {
127 [groupUsersString appendString:@","];
129 [groupUsersString appendString:[groupUsers objectAtIndex:index]];
131 return groupUsersString;
134 #pragma mark - Memory management
143 #pragma mark - UITableViewDataSource
145 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
146 return (groups.count + 1);
149 - (CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
151 if (indexPath.row < groups.count) {
152 NSString *groupName = [[[groups allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] objectAtIndex:indexPath.row];
153 result = 22.0 + [[self groupUsersStringForGroupName:groupName] sizeWithFont:[UIFont systemFontOfSize:18.0]
154 constrainedToSize:(([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) ?
155 CGSizeMake(596.0, 9000.0) :
156 CGSizeMake(280.0, 9000.0))
157 lineBreakMode:UILineBreakModeCharacterWrap].height;
158 return MAX(aTableView.rowHeight, result);
160 return aTableView.rowHeight;
164 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
165 static NSString *CellIdentifier = @"Cell";
166 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
168 cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
171 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
172 if (indexPath.row < groups.count) {
173 NSString *groupName = [[[groups allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] objectAtIndex:indexPath.row];
174 cell.textLabel.text = groupName;
175 cell.detailTextLabel.text = [self groupUsersStringForGroupName:groupName];
176 cell.detailTextLabel.numberOfLines = 0;
177 cell.detailTextLabel.lineBreakMode = UILineBreakModeCharacterWrap;
179 cell.textLabel.text = @"Add Group";
180 cell.detailTextLabel.text = @"";
187 #pragma mark - UITableViewDelegate
189 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
190 EditAccountGroupsViewController *vc = [[EditAccountGroupsViewController alloc] initWithNibName:@"EditAccountGroupsViewController" bundle:nil];
191 vc.account = self.account;
192 vc.metadata = metadata;
194 if (indexPath.row < groups.count) {
195 NSString *groupName = [[[groups allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] objectAtIndex:indexPath.row];
196 vc.removeGroupEnabled = YES;
197 vc.groupName = groupName;
198 vc.navigationItem.title = @"Edit Group";
200 vc.removeGroupEnabled = NO;
202 vc.navigationItem.title = @"Add Group";
205 [self.navigationController pushViewController:vc animated:YES];