Statistics
| Branch: | Tag: | Revision:

root / Classes / EditMetadataViewController.m @ ea3a6bba

History | View | Annotate | Download (14 kB)

1
//
2
//  EditMetadataViewController.m
3
//  pithos-ios
4
//
5
// Copyright 2011-2012 GRNET S.A. All rights reserved.
6
//
7
// Redistribution and use in source and binary forms, with or
8
// without modification, are permitted provided that the following
9
// conditions are met:
10
// 
11
//   1. Redistributions of source code must retain the above
12
//      copyright notice, this list of conditions and the following
13
//      disclaimer.
14
// 
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.
19
// 
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.
32
// 
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.
37

    
38
#import "EditMetadataViewController.h"
39
#import "AccountManager.h"
40
#import "UIViewController+Conveniences.h"
41
#import "FolderViewController.h"
42
#import "OpenStackAccount.h"
43
#import "Container.h"
44
#import "Folder.h"
45
#import "StorageObject.h"
46
#import "ActivityIndicatorView.h"
47
#import "PithosUtilities.h"
48
#import "APICallback.h"
49

    
50
@implementation EditMetadataViewController
51

    
52
@synthesize container, account, object;
53

    
54
@synthesize metadataKey;
55
@synthesize metadataValue;
56
@synthesize userInputMetaKey, userInputMetaValue;
57
@synthesize removeMetadataEnabled, objectIsFolder, folderViewController, objectIsContainer;
58

    
59
#define kMetadata 0 
60
#define kSaveMedata 1
61
#define kDeleteMetadata 2
62

    
63

    
64
- (void)dealloc {
65
    [account release];
66
    [container release];
67
    [object release];
68
    [metadataKey release];
69
    [metadataValue release];
70
    [userInputMetaKey release];
71
    [userInputMetaValue release];
72
    [super dealloc];
73
}
74

    
75
#pragma mark - View lifecycle
76

    
77
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
78
    return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
79
}
80

    
81
#pragma mark - Internal
82

    
83
- (void)createNewFolder {
84
    __block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Saving metadata..."
85
                                                                                                   andAddToView:self.view];
86
    [[self.account.manager writeObject:container object:object downloadProgressDelegate:nil]
87
     success:^(OpenStackRequest *request) {
88
         Folder *newFolder = [[Folder alloc] init];
89
         newFolder.name = [[object.name componentsSeparatedByString:@"/"] lastObject];
90
         newFolder.parent = folderViewController.folder;
91
         newFolder.sharing = folderViewController.folder.sharing;
92
         newFolder.metadata = object.metadata;
93
         [folderViewController.folder addFolder:newFolder];
94
         // XXX increase container.count if in rootFolder?
95
         [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
96
         [newFolder release];
97
         self.metadataKey = userInputMetaKey;
98
         self.metadataValue = userInputMetaValue;
99
         removeMetadataEnabled = YES;
100
         [self.tableView reloadData];
101
         [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
102
         if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
103
             [self.folderViewController refreshButtonPressed:nil];
104
         } else {
105
             self.folderViewController.refreshWhenAppeared = YES;
106
         }
107
     }
108
     failure:^(OpenStackRequest *request) {
109
         [object.metadata removeObjectForKey:userInputMetaKey];
110
         [object.metadata setObject:metadataValue forKey:metadataKey];
111
         [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
112
         [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
113
         [self.tableView reloadData];
114
         [self alert:@"There was a problem saving the metadata." request:request];
115
     }];
116
}
117

    
118
#pragma mark - Table view data source
119

    
120
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
121
    return (removeMetadataEnabled ? 3 : 2);
122
}
123

    
124
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
125
    return ((section == kMetadata) ? 2 : 1);
126
}
127

    
128
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
129
    static NSString *CellIdentifier = @"Cell";
130
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
131
    if (cell == nil) {
132
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
133
    }
134
                
135
    if (indexPath.section == kMetadata) {
136
        UITextField *textField = nil;
137
        for (id subView in cell.contentView.subviews) {
138
            if ([subView isKindOfClass:[UITextField class]]) {
139
                textField = (UITextField *)subView;
140
            }
141
        }
142
        
143
        if (textField == nil) {
144
            CGRect bounds = [cell.contentView bounds];
145
            CGRect rect = CGRectInset(bounds, 10.0, 10.0);                        
146
            textField = [[UITextField alloc] initWithFrame:rect];
147
            [textField setFrame:rect];
148
        }
149
        [textField setClearButtonMode:UITextFieldViewModeWhileEditing];
150
        [textField setBackgroundColor:[UIColor clearColor]];
151
        [textField setOpaque:YES];
152
        [textField setAutocorrectionType:UITextAutocorrectionTypeNo];
153
        [textField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
154
        [textField setDelegate:self];
155
        textField.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
156

    
157
        if (indexPath.row == 0) {
158
            [textField setReturnKeyType:UIReturnKeyNext];
159
            textField.placeholder = @"Key";
160
            textField.text = self.metadataKey;
161
            textField.tag = 0;
162
        } else if (indexPath.row == 1) {
163
            textField.placeholder = @"Value";
164
            textField.text = self.metadataValue;
165
            textField.tag = 1;
166
        }
167
            
168
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
169
        [cell.contentView addSubview:textField];
170
    } else if (indexPath.section == kSaveMedata) {
171
        cell.textLabel.text = @"Save";
172
    } else if (indexPath.section == kDeleteMetadata) {
173
        cell.textLabel.text = @"Remove";
174
    }
175

    
176
    return cell;
177
}
178

    
179
#pragma mark - Table view delegate
180

    
181
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
182
    if (indexPath.section != kMetadata)
183
        [self.view endEditing:YES];
184
    
185
    NSIndexPath *keyCellIndexPath;
186
    NSIndexPath *valueCellIndexPath;
187
    UITableViewCell *cell;
188
    
189
    if (indexPath.section == kSaveMedata) {
190
        keyCellIndexPath = [NSIndexPath indexPathForRow:0 inSection:kMetadata];
191
        cell = [self.tableView cellForRowAtIndexPath:keyCellIndexPath];
192
        UITextField *textField = [[cell.contentView subviews] objectAtIndex:0];
193
        self.userInputMetaKey = textField.text;
194
    
195
        if (!userInputMetaKey.length || ![userInputMetaKey stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length) {
196
            [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
197
            [self alert:@"Invalid input" message:@"Metadata key cannot be empty"];
198
        } else {
199
            valueCellIndexPath = [NSIndexPath indexPathForRow:1 inSection:kMetadata];
200
            cell = [self.tableView cellForRowAtIndexPath:valueCellIndexPath];
201
            textField = [[cell.contentView subviews] objectAtIndex:0];
202
            self.userInputMetaValue = textField.text;
203
            [object.metadata removeObjectForKey:metadataKey];
204
            [object.metadata setObject:userInputMetaValue forKey:userInputMetaKey];
205
            
206
            if (objectIsFolder && ![PithosUtilities isContentTypeDirectory:object.contentType]) {
207
                if ((([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) &&
208
                     [folderViewController.parentFolderViewController.folder.objects objectForKey:object.name]) ||
209
                    (([UIDevice currentDevice].userInterfaceIdiom != UIUserInterfaceIdiomPad) &&
210
                     [folderViewController.folder.objects objectForKey:object.name])) {
211
                    NSString *alertMessage = [NSString stringWithFormat:@"In order to apply the changes in '%@', the object at the same path must be replaced. Continue?", object.name];
212
                    NSString *alertTitle = @"Apply changes";
213
                    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:alertTitle
214
                                                                    message:alertMessage
215
                                                                   delegate:self
216
                                                          cancelButtonTitle:@"Cancel"
217
                                                          otherButtonTitles:@"OK", nil];
218
                    [alert show];
219
                    [alert release];
220
                } else {
221
                    object.name = object.fullPath;
222
                    object.contentType = @"application/directory";
223
                    object.data = [NSData data];
224
                    [self createNewFolder];
225
                }
226
            } else {
227
                __block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Saving metadata..."
228
                                                                                                               andAddToView:self.view];
229
                [[self.account.manager writeObjectMetadata:container object:object]
230
                 success:^(OpenStackRequest *request) {
231
                     self.metadataKey = userInputMetaKey;
232
                     self.metadataValue = userInputMetaValue;
233
                     removeMetadataEnabled = YES;
234
                     [self.tableView reloadData];
235
                     [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
236
                     [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
237
                     if (objectIsContainer) {
238
                         container.metadata = object.metadata;
239
                         [self.account.containers setObject:container forKey:container.name];
240
                     }
241
                 }
242
                 failure:^(OpenStackRequest *request) { 
243
                     [object.metadata removeObjectForKey:userInputMetaKey];
244
                     [object.metadata setObject:metadataValue forKey:metadataKey];
245
                     [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
246
                     [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
247
                     [self alert:@"There was a problem saving the metadata." request:request];
248
                 }];
249
            }
250
        }
251
    } else if (indexPath.section == kDeleteMetadata) {
252
        __block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Deleting metadata..."
253
                                                                                                       andAddToView:self.view];
254
            [object.metadata removeObjectForKey:metadataKey];
255
            [[self.account.manager writeObjectMetadata:container object:object]
256
             success:^(OpenStackRequest *request) {
257
                 [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
258
                 [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
259
                 self.metadataKey = @"";
260
                 self.metadataValue = @"";
261
                 removeMetadataEnabled = NO;
262
                 [self.tableView reloadData];
263
                 if (objectIsContainer) {
264
                     container.metadata = object.metadata;
265
                     [self.account.containers setObject:container forKey:container.name];
266
                 }
267
             }
268
             failure:^(OpenStackRequest *request) {
269
                 [object.metadata setObject:metadataValue forKey:metadataKey];
270
                 [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
271
                 [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
272
                 [self alert:@"There was a problem saving the metadata." request:request];
273

    
274
             }];
275
    }
276
}
277

    
278
#pragma mark - Alertview delegate
279

    
280
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
281
    if (buttonIndex == 1) {
282
        object.name = object.fullPath;
283
        object.contentType = @"application/directory";
284
        object.data = [NSData data];
285
        [self createNewFolder];      
286
    } else {
287
        [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
288
    }
289
}
290

    
291
#pragma mark - Textfield delegate
292

    
293
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
294
    if ([textField returnKeyType] == UIReturnKeyNext) {
295
        if (!textField.text.length || ![textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]) {
296
            [self alert:@"Invalid input" message:@"Metadata key cannot be empty"];
297
        }
298

    
299
        NSInteger nextTag = [textField tag] + 1;
300
        UIView *nextTextField = [self.tableView viewWithTag:nextTag];
301
        [nextTextField becomeFirstResponder];
302
    } else {
303
        [textField resignFirstResponder];
304
    }
305
    
306
    return YES;
307
}
308

    
309
@end