Statistics
| Branch: | Tag: | Revision:

root / Classes / StorageObjectViewController.m @ 38d59b6c

History | View | Annotate | Download (24.3 kB)

1
//
2
//  StorageObjectViewController.m
3
//  OpenStack
4
//
5
//  Created by Mike Mayo on 12/19/10.
6
//  The OpenStack project is provided under the Apache 2.0 license.
7
//
8

    
9
#import "StorageObjectViewController.h"
10
#import "OpenStackAccount.h"
11
#import "Container.h"
12
#import "Folder.h"
13
#import "StorageObject.h"
14
#import "AccountManager.h"
15
#import "AnimatedProgressView.h"
16
#import "UIViewController+Conveniences.h"
17
#import "MediaViewController.h"
18
#import "FolderViewController.h"
19
#import "UIColor+MoreColors.h"
20
#import "OpenStackAppDelegate.h"
21
#import "EditMetadataViewController.h"
22

    
23
#define kDetails 0
24
#define kMetadata 1
25

    
26
#define maxMetadataViewableLength 12
27

    
28

    
29
// TODO: use etag to reset download
30
// TODO: try downloading directly to the file to save memory.  don't use object.data
31

    
32
/*
33
 Name                           whatever.txt
34
 Full Path
35
 Size                           123 KB
36
 Content Type                   text/plain
37
 
38
 Metadata
39
 Key                            Value -> tap goes to a metadata item VC to edit or delete
40
 Key                            Value
41
 Add Metadata... (if max not already reached)
42
 
43
 CDN URL sections (action sheet to copy, open in safari, and email link)
44
 
45
 Download File (if downloaded, Open File and Mail File as Attachment)
46
 "After you download the file, you'll be able to attempt to open it and mail is as an attachment."
47
 
48
 Delete Object
49
 */
50

    
51
@implementation StorageObjectViewController
52

    
53
@synthesize account, container, folder, object, tableView, folderViewController;
54

    
55
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
56
    return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
57
}
58

    
59
- (void)setBackgroundView {
60
    
61
    UIImageView *logo = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cloudfiles-large.png"]];
62
    
63
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
64
        UIView *backgroundContainer = [[UIView alloc] init];
65
        backgroundContainer.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
66
        backgroundContainer.backgroundColor = [UIColor iPadTableBackgroundColor];
67
        logo.contentMode = UIViewContentModeScaleAspectFit;
68
        logo.frame = CGRectMake(100.0, 100.0, 1000.0, 1000.0);
69
        logo.alpha = 0.5;        
70
        [backgroundContainer addSubview:logo];
71
        tableView.backgroundView = backgroundContainer;
72
        [backgroundContainer release];
73
    } else {        
74
        self.tableView.backgroundView = nil;
75
    }
76
    [logo release];    
77
}
78

    
79

    
80
#pragma mark -
81
#pragma mark View lifecycle
82

    
83
- (void)viewDidLoad {
84
    [super viewDidLoad];
85
    deleteActionSheet = [[UIActionSheet alloc] initWithTitle:@"Are you sure you want to delete this file?  This operation cannot be undone." delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete File" otherButtonTitles:nil];
86
}
87

    
88
- (void)viewWillAppear:(BOOL)animated {
89
    [super viewWillAppear:animated];
90
    self.navigationItem.title = object.name;
91
    
92
    NSIndexPath*	selection = [self.tableView indexPathForSelectedRow];
93
	if (selection)
94
		[self.tableView deselectRowAtIndexPath:selection animated:YES];
95
    
96
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
97
    NSString *documentsDirectory = [paths objectAtIndex:0];        
98
    NSString *shortPath = [NSString stringWithFormat:@"/%@/%@", self.container.name, self.object.fullPath];
99
    NSString *filePath = [documentsDirectory stringByAppendingString:shortPath];
100
    
101
    NSFileManager *fileManager = [NSFileManager defaultManager];
102
    fileDownloaded = [fileManager fileExistsAtPath:filePath];
103
    
104
    downloadProgressView = [[AnimatedProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
105
    
106
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
107
        CGRect rect = downloadProgressView.frame;
108
        rect.size.width = 440.0;
109
        downloadProgressView.frame = rect;
110
    }
111
    
112
    [self setBackgroundView];
113
    if (self.container.cdnEnabled) {
114
        cdnURLSection = 2;
115
        actionsSection = 3;
116
        deleteSection = 4;
117
    } else {
118
        cdnURLSection = -1;
119
        actionsSection = 2;
120
        deleteSection = 3;
121
    }
122
    
123
    // let's see if we can tweet
124
    UIApplication *app = [UIApplication sharedApplication];
125
    NSURL *twitterURL = [NSURL URLWithString:@"twitter://post?message=test"];
126

    
127
    if ([app canOpenURL:twitterURL]) {
128
        cdnURLActionSheet = [[UIActionSheet alloc] initWithTitle:[[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Copy to Pasteboard", @"Open in Safari", @"Email Link to File", @"Tweet Link to File", nil];
129
    } else {
130
        cdnURLActionSheet = [[UIActionSheet alloc] initWithTitle:[[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Copy to Pasteboard", @"Open in Safari", @"Email Link to File", nil];
131
    }
132
    
133
    [self.tableView reloadData];
134
}
135

    
136
#pragma mark -
137
#pragma mark Table view data source
138

    
139
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
140
    return self.container.cdnEnabled ? 5 : 4;
141
}
142

    
143
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
144
    if (section == kDetails) {
145
        return 4;
146
    } else if (section == kMetadata) {
147
        return 1 + [object.metadata count];
148
    } else if (section == cdnURLSection) {
149
        return 1;
150
    } else if (section == actionsSection) {
151
        return fileDownloaded ? 2 : 1;
152
    } else if (section == deleteSection) {
153
        return 1;
154
    } else {
155
        return 1;
156
    }
157
}
158

    
159
/*
160
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
161
    if (section == actionsSection) {
162
        return @"After you download the file, you'll be able to attempt to open it and mail it as an attachment.";
163
    } else {
164
        return @"";
165
    }
166
}
167
*/
168

    
169
- (CGFloat)findLabelHeight:(NSString*)text font:(UIFont *)font {
170
    CGSize textLabelSize;    
171
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
172
        // 616, 678
173
        textLabelSize = CGSizeMake(596.0, 9000.0f);
174
    } else {
175
        textLabelSize = CGSizeMake(280.0, 9000.0f);
176
    }
177
    CGSize stringSize = [text sizeWithFont:font constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeCharacterWrap];
178
    return stringSize.height;
179
}
180

    
181
- (CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
182
    CGFloat result = aTableView.rowHeight;
183
    
184
    if (indexPath.section == cdnURLSection) {
185
        result = 22.0 + [self findLabelHeight:[[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] font:[UIFont systemFontOfSize:18.0]];
186
    } else if (indexPath.section == kDetails && indexPath.row == 1) {
187
        CGSize textLabelSize;
188
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
189
            textLabelSize = CGSizeMake(537.0, 9000.0f);
190
        } else {
191
            textLabelSize = CGSizeMake(221.0, 9000.0f);
192
        }
193
        CGSize stringSize = [object.fullPath sizeWithFont:[UIFont systemFontOfSize:18.0] constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeWordWrap];
194
        return 22.0 + stringSize.height;
195
    } else if (indexPath.section == kDetails && indexPath.row == 0) {
196
        CGSize textLabelSize;
197
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
198
            textLabelSize = CGSizeMake(537.0, 9000.0f);
199
        } else {
200
            textLabelSize = CGSizeMake(221.0, 9000.0f);
201
        }
202
        CGSize stringSize = [object.name sizeWithFont:[UIFont systemFontOfSize:18.0] constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeWordWrap];
203
        return 22.0 + stringSize.height;
204
    }
205
    
206
    return MAX(aTableView.rowHeight, result);
207
}
208

    
209
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
210
    
211
    static NSString *CellIdentifier = @"Cell";
212
    
213
    UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
214
    if (cell == nil) {
215
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
216
        //cell.backgroundColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.93];
217
        cell.textLabel.backgroundColor = [UIColor clearColor];
218
        cell.detailTextLabel.backgroundColor = [UIColor clearColor];
219
        cell.detailTextLabel.numberOfLines = 0;
220
        cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
221
    }
222
    
223
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
224
        cell.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.8];
225
    }
226
    
227
    cell.detailTextLabel.textAlignment = UITextAlignmentRight;
228
    
229
    // Configure the cell...
230
    if (indexPath.section == kDetails) {
231
        cell.accessoryType = UITableViewCellAccessoryNone;
232
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
233
        cell.accessoryView = nil;
234
        if (indexPath.row == 0) {
235
            cell.textLabel.text = @"Name";
236
            cell.detailTextLabel.text = object.name;
237
        } else if (indexPath.row == 1) {
238
            cell.textLabel.text = @"Full Path";
239
            cell.detailTextLabel.text = object.fullPath;
240
        } else if (indexPath.row == 2) {
241
            cell.textLabel.text = @"Size";
242
            cell.detailTextLabel.text = [object humanizedBytes];
243
        } else if (indexPath.row == 3) {
244
            cell.textLabel.text = @"Type";
245
            cell.detailTextLabel.text = object.contentType;
246
        }
247
    } else if (indexPath.section == kMetadata) {
248
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
249
        cell.selectionStyle = UITableViewCellSelectionStyleBlue;
250
        cell.accessoryView = nil;
251
        if (indexPath.row == [object.metadata count]) {
252
            cell.textLabel.text = @"Add Metadata";
253
            cell.detailTextLabel.text = @"";
254
        } else {
255
            NSString *key = [[object.metadata allKeys] objectAtIndex:indexPath.row];
256
            NSString *value = [object.metadata objectForKey:key];
257
            NSString *metadataKeyCellText = key;
258
            NSString *metadataValueCellText = value;
259
            if ([metadataKeyCellText length] > maxMetadataViewableLength) {
260
                metadataKeyCellText = [metadataKeyCellText substringToIndex:(maxMetadataViewableLength - 3)];
261
                metadataKeyCellText = [metadataKeyCellText stringByAppendingString:@"..."];
262
            }
263
            if ([metadataValueCellText length] > maxMetadataViewableLength) {
264
                metadataValueCellText = [metadataValueCellText substringToIndex:(maxMetadataViewableLength - 3)];
265
                metadataValueCellText = [metadataValueCellText stringByAppendingString:@"..."];
266
            }
267
            
268
            cell.textLabel.text = metadataKeyCellText;
269
            cell.detailTextLabel.text = metadataValueCellText;
270
        }
271
    } else if (indexPath.section == cdnURLSection) {
272
        cell.detailTextLabel.textAlignment = UITextAlignmentLeft;
273
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
274
        cell.textLabel.text = @"";
275
        cell.detailTextLabel.text = [[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
276
    } else if (indexPath.section == actionsSection) {
277
        cell.accessoryView = nil;
278
        if (performingAction) {
279
            cell.textLabel.textColor = [UIColor grayColor];
280
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
281
            cell.accessoryType = UITableViewCellAccessoryNone;
282
        } else {
283
            cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
284
            cell.selectionStyle = UITableViewCellSelectionStyleBlue;
285
        }
286

    
287
        if (indexPath.row == 0) {
288
            if (fileDownloaded) {
289
                cell.textLabel.text = @"Open File";
290
            } else {
291
                if (fileDownloading) {
292
                    cell.accessoryView = downloadProgressView;
293
                    // TODO: if you leave this view while downloading, there's EXC_BAD_ACCESS
294
                    cell.textLabel.text = @"Downloading";
295
                } else {
296
                    cell.textLabel.text = @"Download File";
297
                }
298
            }
299
            cell.detailTextLabel.text = @"";
300
            
301
        } else if (indexPath.row == 1) {
302
            cell.textLabel.text = @"Email File as Attachment";
303
            cell.detailTextLabel.text = @"";
304
        }
305
    } else if (indexPath.section == deleteSection) {
306
        cell.textLabel.text = @"Delete Object";
307
        cell.detailTextLabel.text = @"";
308
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
309
        cell.selectionStyle = UITableViewCellSelectionStyleBlue;
310
    }
311
    
312
    return cell;
313
}
314

    
315

    
316
#pragma mark -
317
#pragma mark Table view delegate
318

    
319
- (void)reloadActionsTitleRow:(NSTimer *)timer {
320
    [[timer.userInfo objectForKey:@"tableView"] reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationNone];
321
}
322

    
323
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
324
    if (indexPath.section == kMetadata) {
325
        EditMetadataViewController *vc = [[EditMetadataViewController alloc] initWithNibName:@"EditMetadataViewController" bundle:nil];
326
        NSString *metadataKey;
327
        NSString *metadataValue;
328
        
329
        if (indexPath.row == [self.object.metadata count]) {
330
            metadataKey = @"";
331
            metadataValue = @"";
332
            vc.deleteEnabled = FALSE;
333
            vc.navigationItem.title = @"Add Metadata";
334
        }
335
        else {
336
            metadataKey = [[self.object.metadata allKeys] objectAtIndex:indexPath.row];
337
            metadataValue = [self.object.metadata objectForKey:metadataKey];
338
            vc.deleteEnabled = YES;
339
            vc.navigationItem.title = @"Edit Metadata";
340
        }
341

    
342
        vc.metadataKey = metadataKey;
343
        vc.metadataValue = metadataValue;
344
        vc.account = account;
345
        vc.container = container;
346
        vc.object = object;
347
        [self.navigationController pushViewController:vc animated:YES];
348
        [vc release];
349
    } else if (indexPath.section == cdnURLSection) {
350
        [cdnURLActionSheet showInView:self.view];
351
    } else if (indexPath.section == actionsSection) {
352
        if (indexPath.row == 0) {
353
            if (fileDownloaded) {
354
                NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
355
                NSString *documentsDirectory = [paths objectAtIndex:0];        
356
                NSString *shortPath = [NSString stringWithFormat:@"/%@/%@", self.container.name, self.object.fullPath];
357
                NSString *filePath = [documentsDirectory stringByAppendingString:shortPath];
358
                                
359
                UIDocumentInteractionController *vc = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];
360
                vc.delegate = self;
361
                
362
                if (![vc presentPreviewAnimated:YES]) {
363
                    
364
                    if ([self.object isPlayableMedia]) {
365
                        MediaViewController *vc = [[MediaViewController alloc] initWithNibName:@"MediaViewController" bundle:nil];
366
                        vc.container = self.container;
367
                        vc.object = self.object;
368
                        [self.navigationController pushViewController:vc animated:YES];
369
                        [vc release];
370
                    } else {
371
                        [self alert:@"Error" message:@"This file could not be opened."];
372
                        [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
373
                    }
374
                }
375
                
376
                [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:actionsSection] animated:YES];                
377
                
378
            } else {                
379
                if (!fileDownloading) {
380
                    // download the file
381
                    fileDownloading = YES;
382
                    [self.account.manager getObject:self.container object:self.object downloadProgressDelegate:self];
383
                    [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationNone];
384
                }
385
                
386
            }
387
        } else if (indexPath.row == 1) {
388
            
389
            NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
390
            NSString *documentsDirectory = [paths objectAtIndex:0];        
391
            NSString *shortPath = @"";
392
            
393
            if (self.container && [self.container respondsToSelector:@selector(name)] && self.object && [self.object respondsToSelector:@selector(fullPath)]) {
394
                shortPath = [NSString stringWithFormat:@"/%@/%@", self.container.name, self.object.fullPath];
395
            }
396
            
397
            NSString *filePath = [documentsDirectory stringByAppendingString:shortPath];
398
            NSData *data = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:filePath]];
399
            
400
            MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init];
401
            vc.mailComposeDelegate = self;		
402
            [vc setSubject:self.object.name];
403
            [vc addAttachmentData:data mimeType:self.object.contentType fileName:self.object.name];
404
            [vc setMessageBody:@"" isHTML:NO];    
405
            if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
406
                vc.modalPresentationStyle = UIModalPresentationPageSheet;
407
            }                
408
            [self presentModalViewController:vc animated:YES];
409
            [vc release];        
410
        }
411
    } else if (indexPath.section == deleteSection) {
412
        [deleteActionSheet showInView:self.view];
413
    }
414
}
415

    
416
- (void)setProgress:(float)newProgress {
417
    [downloadProgressView setProgress:newProgress animated:YES];    
418
    if (newProgress >= 1.0) {
419
        fileDownloading = NO;
420
        fileDownloaded = YES;
421
        
422
        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:1 inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationBottom];
423
        [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationNone];
424
    }
425
}
426

    
427
#pragma mark -
428
#pragma mark Document Interation Controller Delegate
429

    
430
- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *) controller {
431
    return self.navigationController;
432
}
433

    
434
- (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controllers {
435
    [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:actionsSection] animated:YES];
436
}
437

    
438
#pragma mark -
439
#pragma mark Action Sheet Delegate
440

    
441
- (void)deleteObjectRow {
442
    [self.folderViewController.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:selectedIndexPath] withRowAnimation:UITableViewRowAnimationLeft];
443
}
444

    
445
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
446
    if ([actionSheet isEqual:deleteActionSheet]) {
447
        if (buttonIndex == 0) {
448
            // delete the file and pop out
449
            [self showToolbarActivityMessage:@"Deleting file..."];
450
            
451
            [self.account.manager deleteObject:self.container object:self.object];
452
            
453
            deleteSuccessObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"deleteObjectSucceeded" object:self.object
454
                                                                                               queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
455
            {
456
                [self hideToolbarActivityMessage];
457
                performingAction = NO;
458
                [self.folder.objects removeObjectForKey:self.object.name];
459
                [self.navigationController popViewControllerAnimated:YES];
460
                if ([self.folder.objects count] + [self.folder.folders count] == 0) {
461
                    [self.folderViewController.tableView reloadData];
462
                } else {
463
                    [self.folderViewController.tableView selectRowAtIndexPath:selectedIndexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
464
                    [NSTimer scheduledTimerWithTimeInterval:0.75 target:self selector:@selector(deleteObjectRow) userInfo:nil repeats:NO];
465
                }
466
                [[NSNotificationCenter defaultCenter] removeObserver:deleteSuccessObserver];
467
            }];
468

    
469
            deleteFailureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"deleteObjectFailed" object:self.object
470
                                                                                       queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
471
            {
472
                [self hideToolbarActivityMessage];
473
                performingAction = NO;
474
                [self alert:@"There was a problem deleting this file." request:[notification.userInfo objectForKey:@"request"]];
475

    
476
                [[NSNotificationCenter defaultCenter] removeObserver:deleteFailureObserver];
477

    
478
            }];
479
            
480
        }
481
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:deleteSection];
482
        [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
483
    } else if ([actionSheet isEqual:cdnURLActionSheet]) {
484
        NSURL *url = [NSURL URLWithString:[[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
485

    
486
        if (buttonIndex == 0) {
487
            // copy to pasteboard
488
            UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
489
            [pasteboard setString:[url description]];
490
        } else if (buttonIndex == 1) {
491
            // open in safari
492
            UIApplication *application = [UIApplication sharedApplication];
493
            if ([application canOpenURL:url]) {
494
                [application openURL:url];
495
            } else {
496
                [self alert:@"Error" message:[NSString stringWithFormat:@"This URL cannot be opened.\n%@", url]];
497
            }
498
        } else if (buttonIndex == 2) {
499
            // email link to file
500
            MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init];
501
            vc.mailComposeDelegate = self;		
502
            [vc setSubject:self.object.name];
503
            [vc setMessageBody:[url description] isHTML:NO];
504
            if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
505
                vc.modalPresentationStyle = UIModalPresentationPageSheet;
506
            }                
507
            [self presentModalViewController:vc animated:YES];
508
            [vc release];        
509
        } else if (buttonIndex == 3) {
510
            // tweet link to file
511
            UIApplication *app = [UIApplication sharedApplication];            
512
            NSURL *twitterURL = [NSURL URLWithString:[NSString stringWithFormat:@"twitter://post?message=%@", [[url description] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
513
            if ([app canOpenURL:twitterURL]) {
514
                [app openURL:twitterURL];
515
            }
516
        }
517
        [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:cdnURLSection] animated:YES];
518
    }
519
}
520

    
521
#pragma mark -
522
#pragma mark Mail Composer Delegate
523

    
524
// Dismisses the email composition interface when users tap Cancel or Send.
525
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {	
526
	[self dismissModalViewControllerAnimated:YES];
527
    [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:actionsSection] animated:YES];
528
}
529

    
530
#pragma mark -
531
#pragma mark Memory management
532

    
533
- (void)dealloc {
534
    [account release];
535
    [downloadProgressView release];
536
    [deleteActionSheet release];
537
    [cdnURLActionSheet release];
538
    [tableView release];
539
    [folderViewController release];
540
    [super dealloc];
541
}
542

    
543

    
544
@end
545