In folder view controller in iPhone, select file cell to open, or select cell disclos...
[pithos-ios] / Classes / StorageObjectViewController.m
index 8fa0d76..8f68994 100755 (executable)
 #import "TextViewCell.h"
 #import "NSString+Conveniences.h"
 #import "APICallback.h"
+#import "ObjectVersionsViewController.h"
+#import <MediaPlayer/MPMoviePlayerController.h>
+#import <MessageUI/MessageUI.h>
+#import "ActivityIndicatorView.h"
 
 #define kDetails 0
-#define kMetadata 1
-#define kPublic 2
-#define kPermissions 3
+#define kActions 1
+#define kMetadata 2
 
 #define maxMetadataViewableLength 12
 
-
 // TODO: use etag to reset download
 // TODO: try downloading directly to the file to save memory.  don't use object.data
 
 /*
- Name                           whatever.txt
- Full Path
- Size                           123 KB
- Content Type                   text/plain
- Metadata
- Key                            Value -> tap goes to a metadata item VC to edit or delete
- Key                            Value
- Add Metadata... (if max not already reached)
- CDN URL sections (action sheet to copy, open in safari, and email link)
+Name                            whatever.txt
+Full Path                       folder/whatever.txt
+Size                            123 KB
+Type                            text/plain
+Last Modified                   2012-12-21 11:11:00
+
+Download File (if downloaded, Open File and Mail File as Attachment)
+"After you download the file, you'll be able to attempt to open it and mail is as an attachment."
+
+Metadata
+Key                             Value -> tap goes to a metadata item VC to edit or delete
+Key                             Value
+Add Metadata... (if max not already reached)
+
+Public URL                      On/Off
+
+Share
  
- Download File (if downloaded, Open File and Mail File as Attachment)
- "After you download the file, you'll be able to attempt to open it and mail is as an attachment."
+Versions
  
- Delete Object
- */
+Delete Object
+*/
 
 @implementation StorageObjectViewController
 
-@synthesize account, container, folder, object, tableView, folderViewController;
-@synthesize oldPubicURI, documentInteractionController;
+@synthesize account, container, folder, object, folderViewController;
+@synthesize oldPubicURI, documentInteractionController, actionSelectedIndexPath, objectIsReadOnly, versionID;
 
-- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
-    return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
-}
+#pragma mark - View lifecycle
 
-- (void)setBackgroundView {
-    
-    UIImageView *logo = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cloudfiles-large.png"]];
-    
-    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
-        UIView *backgroundContainer = [[UIView alloc] init];
-        backgroundContainer.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
-        backgroundContainer.backgroundColor = [UIColor iPadTableBackgroundColor];
-        logo.contentMode = UIViewContentModeScaleAspectFit;
-        logo.frame = CGRectMake(100.0, 100.0, 1000.0, 1000.0);
-        logo.alpha = 0.5;        
-        [backgroundContainer addSubview:logo];
-        tableView.backgroundView = backgroundContainer;
-        [backgroundContainer release];
-    } else {        
-        self.tableView.backgroundView = nil;
-    }
-    [logo release];    
-}
-
-- (IBAction)homeButtonPressed:(id)sender {
-    [self.navigationController popToRootViewControllerAnimated:YES];
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
+    return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
 }
 
-#pragma mark -
-#pragma mark View lifecycle
-
 - (void)viewDidLoad {
     [super viewDidLoad];
+    
     objectIsPublicSwitch = [[UISwitch alloc] init];
     [objectIsPublicSwitch addTarget:self action:@selector(objectIsPublicSwitchChanged:) forControlEvents:UIControlEventValueChanged];
     
-    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];
     permissions = [[NSMutableDictionary alloc] init];
     if (object.sharing.length > 0) {
         NSArray *sharingArray = [object.sharing componentsSeparatedByString:@";"];
         }
         objectIsPublicSwitch.enabled = NO;
     }
+    
+    downloadProgressView = [[AnimatedProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
+    fileDownloading = ([self.account.manager.objectDownloadRequests objectForKey:object.fullPath] != nil) ? YES : NO;
+    if (fileDownloading) {
+        OpenStackRequest *request = [self.account.manager.objectDownloadRequests objectForKey:object.fullPath];
+        self.actionSelectedIndexPath = [request.userInfo objectForKey:@"actionSelectedIndexPath"];
+        [request setDownloadProgressDelegate:self];
+    }
 }
 
 - (void)viewWillAppear:(BOOL)animated {
     NSIndexPath *selection = [self.tableView indexPathForSelectedRow];
        if (selection)
                [self.tableView deselectRowAtIndexPath:selection animated:YES];
+    OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate];
+    if ([app.cachedObjectsDictionary objectForKey:object.hash] != nil) {
+        if ([[NSFileManager defaultManager] fileExistsAtPath:[app.cachedObjectsDictionary objectForKey:object.hash]]) {
+            fileDownloaded = YES;
+        } else {
+            fileDownloaded = NO;
+            [app.cachedObjectsDictionary removeObjectForKey:object.hash];
+            [app saveCacheDictionary];
+        }
+    } else {
+        fileDownloaded = NO;
+    }
     
-    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
-    NSString *documentsDirectory = [paths objectAtIndex:0];        
-    NSString *shortPath = [NSString stringWithFormat:@"/%@/%@", self.container.name, self.object.fullPath];
-    NSString *filePath = [documentsDirectory stringByAppendingString:shortPath];
-    
-    NSFileManager *fileManager = [NSFileManager defaultManager];
-    fileDownloaded = [fileManager fileExistsAtPath:filePath];
-    
-    downloadProgressView = [[AnimatedProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
-    
-    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
+    if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
         CGRect rect = downloadProgressView.frame;
         rect.size.width = 440.0;
         downloadProgressView.frame = rect;
     }
     
-    //[self setBackgroundView];
-    if (self.container.cdnEnabled) {
-        cdnURLSection = 4;
-        actionsSection = 5;
-        deleteSection = 6;
-    } else {
-        cdnURLSection = -1;
-        actionsSection = 4;
-        deleteSection = 5;
-    }
+    publicLinkSection = 3;
+    permissionsSection = 4;
+    versionsSection = 5;
+    deleteSection = 6;
     
+    if (versionID) {
+        publicLinkSection = -1;
+        permissionsSection = -1;
+        versionsSection = -1;
+        deleteSection = -1;
+        objectIsReadOnly = YES;
+    }
     if (account.sharingAccount || account.shared) {
+        versionsSection = -1;
         deleteSection = -1;
     }
     
-    // let's see if we can tweet
-    UIApplication *app = [UIApplication sharedApplication];
-    NSURL *twitterURL = [NSURL URLWithString:@"twitter://post?message=test"];
-
-    if ([app canOpenURL:twitterURL]) {
-        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];
-    } else {
-        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];
-    }
     objectIsPublic = ([object.publicURI length]);
     objectIsPublicSwitch.on = objectIsPublic;
     [self.tableView reloadData];
 }
 
-#pragma mark -
-#pragma mark Table view data source
+- (void)viewDidAppear:(BOOL)animated {
+    if (object.metadata == nil) {
+        [self reloadMetadataSection];
+    }
+}
+
+#pragma mark - Memory management
+
+- (void)dealloc {
+    if (fileDownloading) {
+        OpenStackRequest *request = [self.account.manager.objectDownloadRequests objectForKey:object.fullPath];
+        [request setDownloadProgressDelegate:nil];
+    }
+    [account release];
+    [downloadProgressView release];
+    [cdnURLActionSheet release];
+    [folderViewController release];
+    [objectIsPublicSwitch release];
+    [permissions release];
+    [documentInteractionController release];
+    [actionSelectedIndexPath release];
+    [versionID release];
+    [super dealloc];
+}
+
+#pragma mark - Internal
+
+- (void)objectIsPublicSwitchChanged:(id)sender {
+    NSString *activityMessage = [NSString stringWithFormat:@"Enabling public link.."];
+    self.oldPubicURI = object.publicURI;
+    
+    if (objectIsPublic) {
+        activityMessage = [NSString stringWithFormat:@"Disabling public link.."];
+        object.publicURI = @"";
+    } else {
+        object.publicURI = @"TRUE";
+    }
+    __block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:activityMessage
+                                                                                                   andAddToView:self.view
+                                                                                                   scrollOffset:self.tableView.contentOffset.y];
+    objectIsPublic = !objectIsPublic;
+    [[self.account.manager writeObjectMetadata:container object:object]
+     success:^(OpenStackRequest *request) {
+         NSIndexPath *publicURICellIndexPath = [NSIndexPath indexPathForRow:1 inSection:publicLinkSection];
+         if (objectIsPublic) {
+             [[self.account.manager getObjectInfo:container object:object version:versionID]
+              success:^(OpenStackRequest *request) {
+                  [activityIndicatorView removeFromSuperview];
+                  object.publicURI = [request.responseHeaders objectForKey:@"X-Object-Public"];
+                  NSIndexPath *publicURICellIndexPath = [NSIndexPath indexPathForRow:1 inSection:publicLinkSection];
+                  [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:publicURICellIndexPath]
+                                        withRowAnimation:UITableViewRowAnimationBottom];
+              }
+              failure:^(OpenStackRequest *request) {
+                  [activityIndicatorView removeFromSuperview];
+                  [self alert:@"There was a problem retrieving the public link from the server." request:request];
+              }];
+         } else {
+             [activityIndicatorView removeFromSuperview];
+             [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:publicURICellIndexPath]
+                                   withRowAnimation:UITableViewRowAnimationTop];
+         }
+     }
+     failure:^(OpenStackRequest *request) {
+         [activityIndicatorView removeFromSuperview];
+         objectIsPublic = !objectIsPublic;
+         objectIsPublicSwitch.on = !objectIsPublicSwitch.on;
+         object.publicURI = oldPubicURI;
+         [self alert:@"There was a problem enabling the public link." request:request];
+     }];
+}
+
+#pragma mark - Actions
+
+- (void)reloadMetadataSection {
+    __block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Loading metadata..."
+                                                                                                   andAddToView:self.view];
+    [[self.account.manager getObjectInfo:container object:object version:versionID]
+     success:^(OpenStackRequest *request) {
+         [activityIndicatorView removeFromSuperview];
+         object.metadata = [NSMutableDictionary dictionary];
+         for (NSString *header in request.responseHeaders) {
+             NSString *metadataKey;
+             NSString *metadataValue;
+             if ([header rangeOfString:@"X-Object-Meta-"].location != NSNotFound) {
+                 metadataKey = [NSString decodeFromPercentEscape:[header substringFromIndex:14]];
+                 metadataValue = [NSString decodeFromPercentEscape:[request.responseHeaders objectForKey:header]];
+                 [object.metadata setObject:metadataValue forKey:metadataKey];
+             }
+         }
+         NSIndexSet *metadataSections = [NSIndexSet indexSetWithIndex:kMetadata];
+         [self.tableView reloadSections:metadataSections withRowAnimation:UITableViewRowAnimationFade];
+     }
+     failure:^(OpenStackRequest *request) {
+         [activityIndicatorView removeFromSuperview];
+         [self alert:@"There was a problem retrieving the object's metadata." request:request];
+     }];
+}
+
+#pragma mark - UITableViewDataSource
 
 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
-    if (account.sharingAccount || account.shared)
-        return self.container.cdnEnabled ? 6 : 5;
-    else
-        return self.container.cdnEnabled ? 7 : 6;
+    int numberOfSections = 7;
+    if (publicLinkSection < 0)
+        numberOfSections--;
+    if (permissionsSection < 0)
+        numberOfSections--;
+    if (versionsSection < 0)
+        numberOfSections--;
+    if (deleteSection < 0)
+        numberOfSections--;
+
+    return numberOfSections;
 }
 
 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
     if (section == kDetails) {
-        return 4;
+        return (object.lastModifiedString ? 5: 4);
+    } else if (section == kActions) {
+        return 2;
     } else if (section == kMetadata) {
-        if (objectIsReadOnly)
+        if (objectIsReadOnly) {
             return [object.metadata count];
-        else
+        } else {
             return 1 + [object.metadata count];
-    } else if (section == cdnURLSection) {
-        return 1;
-    } else if (section == actionsSection) {
-        return fileDownloaded ? 2 : 1;
-    } else if (section == kPublic) {
+        }
+    } else if (section == publicLinkSection) {
         return objectIsPublic ? 2 : 1;
-    } else if (section == kPermissions) {
-        if (account.sharingAccount)
+    } else if (section == permissionsSection) {
+        if (account.sharingAccount || objectIsReadOnly) {
             return [permissions count];
-        else
+        } else {
             return 1 + [permissions count];
+        }
     } else {
         return 1;
     }
 }
 
-- (CGFloat)findLabelHeight:(NSString*)text font:(UIFont *)font {
-    CGSize textLabelSize;    
-    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
-        // 616, 678
-        textLabelSize = CGSizeMake(596.0, 9000.0f);
-    } else {
-        textLabelSize = CGSizeMake(280.0, 9000.0f);
-    }
-    CGSize stringSize = [text sizeWithFont:font constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeCharacterWrap];
-    return stringSize.height;
-}
-
 - (CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
     CGFloat result = aTableView.rowHeight;
-    
-    if (indexPath.section == cdnURLSection) {
-        result = 22.0 + [self findLabelHeight:[[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] font:[UIFont systemFontOfSize:18.0]];
-    } else if (indexPath.section == kDetails && indexPath.row == 1) {
-        CGSize textLabelSize;
-        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
-            textLabelSize = CGSizeMake(537.0, 9000.0f);
-        } else {
-            textLabelSize = CGSizeMake(221.0, 9000.0f);
-        }
-        CGSize stringSize = [object.fullPath sizeWithFont:[UIFont systemFontOfSize:18.0] constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeWordWrap];
-        return 22.0 + stringSize.height;
-    } else if (indexPath.section == kDetails && indexPath.row == 0) {
-        CGSize textLabelSize;
-        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
-            textLabelSize = CGSizeMake(537.0, 9000.0f);
-        } else {
-            textLabelSize = CGSizeMake(221.0, 9000.0f);
+    if ((indexPath.section == kDetails) && ((indexPath.row == 0) || (indexPath.row == 1))) {
+        NSString *text;
+        if (indexPath.row == 0) {
+            text = object.name;
+        } else if (indexPath.row == 1) {
+            text = object.fullPath;
         }
-        CGSize stringSize = [object.name sizeWithFont:[UIFont systemFontOfSize:18.0] constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeWordWrap];
-        return 22.0 + stringSize.height;
-    } else if (indexPath.section == kPublic && indexPath.row == 1) {
-        NSString *publicLinkUrl = [NSString stringWithFormat:@"%@%@",
-                                   account.pithosPublicLinkURLPrefix,
-                                   self.object.publicURI];
-                                   
-        result = 30.0 + [self findLabelHeight:publicLinkUrl font:[UIFont systemFontOfSize:15.0]];
+        result = 22.0 + [text sizeWithFont:[UIFont systemFontOfSize:18.0]
+                         constrainedToSize:(([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) ?
+                                            CGSizeMake(537.0, 9000.0) :
+                                            CGSizeMake(221.0, 9000.0))
+                             lineBreakMode:UILineBreakModeCharacterWrap].height;
+    } else if ((indexPath.section == publicLinkSection) && (indexPath.row == 1)) {
+        NSURL *publicLinkURL = [account.pithosPublicLinkURLPrefix URLByAppendingPathComponent:
+                                [NSString encodeToPercentEscape:[self.object.publicURI substringFromIndex:1]
+                                             charactersToEncode:@"!*'();:@&=+$,?%#[]"]];
+        result = 30.0 + [[publicLinkURL description] sizeWithFont:[UIFont systemFontOfSize:18.0]
+                                                constrainedToSize:(([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) ?
+                                                                   CGSizeMake(596.0, 9000.0) :
+                                                                   CGSizeMake(280.0, 9000.0))
+                                                    lineBreakMode:UILineBreakModeCharacterWrap].height;
     }
     return MAX(aTableView.rowHeight, result);
 }
 
 - (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
-    
-    static NSString *CellIdentifier = @"Cell";
-    static NSString *TextViewCellIdentifier = @"TextViewCell";
-    
-    if (indexPath.section == kPublic) {
-        if (indexPath.row == 1) {
-            TextViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:TextViewCellIdentifier];
-            if (cell == nil) {
-                cell = [[[TextViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TextViewCellIdentifier] autorelease];
-                cell.textView.frame = cell.contentView.frame;
+    if ((indexPath.section == publicLinkSection) && (indexPath.row == 1)) {
+        static NSString *CellIdentifier = @"TextViewCell";
+        TextViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
+        if (cell == nil) {
+            cell = [[[TextViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
+            cell.textView.frame = cell.contentView.frame;
 
-            }
-            cell.selectionStyle = UITableViewCellSelectionStyleNone;
-            cell.textView.backgroundColor = [UIColor clearColor];
-            cell.textView.font = [UIFont systemFontOfSize:15.0];
-            cell.textView.dataDetectorTypes = UIDataDetectorTypeLink;
-            cell.textView.text = [NSString stringWithFormat:@"%@%@",
-                                  account.pithosPublicLinkURLPrefix,
-                                  [NSString encodeToPercentEscape:self.object.publicURI charactersToEncode:@"!*'();:@&=+$,?%#[]"]];
-            
-            cell.selectionStyle = UITableViewCellSelectionStyleNone;
-            cell.accessoryView = UITableViewCellAccessoryNone;
-            return cell;
         }
+        cell.selectionStyle = UITableViewCellSelectionStyleNone;
+        cell.textView.backgroundColor = [UIColor clearColor];
+        cell.textView.font = [UIFont systemFontOfSize:15.0];
+        cell.textView.dataDetectorTypes = UIDataDetectorTypeLink;
+        cell.textView.text = [[account.pithosPublicLinkURLPrefix URLByAppendingPathComponent:
+                               [NSString encodeToPercentEscape:[self.object.publicURI substringFromIndex:1]
+                                            charactersToEncode:@"!*'();:@&=+$,?%#[]"]] description];
+        cell.selectionStyle = UITableViewCellSelectionStyleNone;
+        cell.accessoryView = UITableViewCellAccessoryNone;
+        return cell;
     }
     
+    if (indexPath.section == deleteSection) {
+        static NSString *CellIdentifier = @"DeleteCell";
+        UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+        if (cell == nil) {
+            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
+            cell.selectionStyle = UITableViewCellSelectionStyleBlue;
+            cell.textLabel.textAlignment = UITextAlignmentCenter;
+            cell.textLabel.text = @"Delete Object";
+        }
+        return cell;
+    }
+    
+    static NSString *CellIdentifier = @"Cell";
     UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
     if (cell == nil) {
         cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
         cell.textLabel.backgroundColor = [UIColor clearColor];
         cell.detailTextLabel.backgroundColor = [UIColor clearColor];
-        cell.detailTextLabel.numberOfLines = 0;
         cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
     }
-    
-    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
+    cell.textLabel.textColor = [UIColor blackColor];
+    cell.detailTextLabel.numberOfLines = 0;
+    if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
         cell.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.8];
     }
     cell.userInteractionEnabled = YES;
         } else if (indexPath.row == 3) {
             cell.textLabel.text = @"Type";
             cell.detailTextLabel.text = object.contentType;
+        } else if (indexPath.row == 4) {
+            cell.textLabel.text = @"Last Modified";
+            cell.detailTextLabel.text = object.lastModifiedString;
         }
     } else if (indexPath.section == kMetadata) {
         if (objectIsReadOnly) {
             cell.textLabel.text = metadataKeyCellText;
             cell.detailTextLabel.text = metadataValueCellText;
         }
-    } else if (indexPath.section == kPublic) {
+    } else if (indexPath.section == publicLinkSection) {
         if (indexPath.row == 0) {
             cell.textLabel.text = @"Public URL";        
             cell.detailTextLabel.text = @"";
             cell.accessoryType = UITableViewCellAccessoryNone;
             cell.selectionStyle = UITableViewCellSelectionStyleNone;
         }
-    } else if (indexPath.section == kPermissions) {
+    } else if (indexPath.section == permissionsSection) {
         if (account.sharingAccount) {
             cell.accessoryType = UITableViewCellAccessoryNone;
             cell.selectionStyle = UITableViewCellSelectionStyleNone;
         cell.accessoryView = nil;
         
         if (indexPath.row == [permissions count]) {
-            cell.textLabel.text = @"Add Permissions";
+            cell.textLabel.text = @"Share";
             cell.detailTextLabel.text = @""; 
-        }
-        else {
+        } else {
             NSString *user = [[permissions allKeys] objectAtIndex:indexPath.row];
             cell.textLabel.text = user;
-            cell.detailTextLabel.text = [permissions objectForKey:user];
+            NSString *accessType;
+            if ([[permissions objectForKey:user] isEqualToString:@"write"])
+                accessType = @"Read/Write";
+            else
+                accessType = @"Read Only";
+            cell.detailTextLabel.numberOfLines = 1;
+            cell.detailTextLabel.lineBreakMode = UILineBreakModeTailTruncation;
+            cell.detailTextLabel.text = accessType;
         }
-    } else if (indexPath.section == cdnURLSection) {
-        cell.detailTextLabel.textAlignment = UITextAlignmentLeft;
-        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
-        cell.textLabel.text = @"";
-        cell.detailTextLabel.text = [[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
-    } else if (indexPath.section == actionsSection) {
-        cell.accessoryView = nil;
-        if (performingAction) {
-            cell.textLabel.textColor = [UIColor grayColor];
-            cell.selectionStyle = UITableViewCellSelectionStyleNone;
-            cell.accessoryType = UITableViewCellAccessoryNone;
+    } else if (indexPath.section == kActions) {
+        if (fileDownloading) {
+            if (actionSelectedIndexPath.row == indexPath.row) {
+                cell.accessoryView = downloadProgressView;
+            } else {
+                cell.textLabel.textColor = [UIColor grayColor];
+                cell.selectionStyle = UITableViewCellSelectionStyleNone;
+            }
         } else {
-            cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
-            cell.selectionStyle = UITableViewCellSelectionStyleNone;
+            cell.selectionStyle = UITableViewCellSelectionStyleBlue;
+            cell.accessoryView = nil;
         }
-
         if (indexPath.row == 0) {
-            if (fileDownloaded) {
-                cell.textLabel.text = @"Open File"; 
-                cell.accessoryType = UITableViewCellAccessoryNone;
-                cell.selectionStyle = UITableViewCellSelectionStyleBlue;
-            } else {
-                if (fileDownloading) {
-                    cell.accessoryView = downloadProgressView;
-                    // TODO: if you leave this view while downloading, there's EXC_BAD_ACCESS
-                    cell.textLabel.text = @"Downloading";
-                } else {
-                    cell.textLabel.text = @"Download File";
-                }
-            }
+            cell.textLabel.text = @"Open File"; 
+            cell.accessoryType = UITableViewCellAccessoryNone;
             cell.detailTextLabel.text = @"";
             
         } else if (indexPath.row == 1) {
             cell.textLabel.text = @"Email File as Attachment";
             cell.detailTextLabel.text = @"";
-            cell.selectionStyle = UITableViewCellSelectionStyleBlue;
+            cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
         }
-    } else if (indexPath.section == deleteSection) {
+    } else if (indexPath.section == versionsSection) {
         cell.selectionStyle = UITableViewCellSelectionStyleBlue;
         cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
-        cell.textLabel.text = @"Delete Object";
+        cell.textLabel.text = @"Versions";
         cell.detailTextLabel.text = @"";
-        
     }
     
     return cell;
 }
 
-
-
-#pragma mark -
-#pragma mark Table view delegate
-
-- (void)reloadActionsTitleRow:(NSTimer *)timer {
-    [[timer.userInfo objectForKey:@"tableView"] reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationNone];
-}
+#pragma mark - UITableViewDelegate
 
 - (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
     if (indexPath.section == kMetadata) {
             metadataValue = @"";
             vc.removeMetadataEnabled = FALSE;
             vc.navigationItem.title = @"Add Metadata";
-        }
-        else {
+        } else {
             metadataKey = [[self.object.metadata allKeys] objectAtIndex:indexPath.row];
             metadataValue = [self.object.metadata objectForKey:metadataKey];
             vc.removeMetadataEnabled = YES;
         vc.object = object;
         [self.navigationController pushViewController:vc animated:YES];
         [vc release];
-    } else if (indexPath.section == kPermissions) {
+    } else if (indexPath.section == permissionsSection) {
         EditPermissionsViewController *vc = [[EditPermissionsViewController alloc] initWithNibName:@"EditPermissionsViewController" bundle:nil];
         NSString *user;
         
         if (indexPath.row == [permissions count]) {
             user = @"";
             vc.removePermissionsEnabled = NO;
-            vc.navigationItem.title = @"Add Permissions";
-        }
-        else {
+            vc.navigationItem.title = @"Share";
+        } else {
             user = [[permissions allKeys] objectAtIndex:indexPath.row];
             NSString *userPermissions = [permissions objectForKey:user];
             if ([userPermissions rangeOfString:@"read"].location != NSNotFound)
                 vc.writePermissionSelected = NO;
             
             vc.removePermissionsEnabled = YES;
-            vc.navigationItem.title = @"Edit Permissions";
+            vc.navigationItem.title = @"Edit Sharing";
         }
         
         vc.user = user;
         vc.folderViewController = folderViewController;
         [self.navigationController pushViewController:vc animated:YES];
         [vc release];
-    } else if (indexPath.section == cdnURLSection) {
-        [cdnURLActionSheet showInView:self.view];
-    } else if (indexPath.section == actionsSection) {
-        if (indexPath.row == 0) {
+    } else if (indexPath.section == kActions) {
+        if (!fileDownloaded) {
+            if (!fileDownloading) {
+                // download the file
+                fileDownloading = YES;
+                self.actionSelectedIndexPath = indexPath;
+                [self.tableView reloadData];
+                NSMutableDictionary *requestUserInfo = [NSDictionary dictionaryWithObject:indexPath forKey:@"actionSelectedIndexPath"];
+                [[self.account.manager getObject:self.container object:self.object downloadProgressDelegate:self requestUserInfo:requestUserInfo version:versionID]
+                 success:^(OpenStackRequest *request) {
+                     fileDownloaded = YES;
+                     fileDownloading = NO;
+                     if ([self.navigationController.visibleViewController isEqual:self])
+                         [self.tableView.delegate tableView:self.tableView didSelectRowAtIndexPath:indexPath]; 
+                     [self.tableView reloadData];
+                     [self.folderViewController reloadData];
+                 }
+                 failure:^(OpenStackRequest *request) {
+                     fileDownloaded = NO;
+                     fileDownloading = NO;
+                     [self alert:@"File failed to download." request:request];
+                     [self.tableView reloadData];
+                 }];
+                [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:indexPath.row inSection:kActions]] withRowAnimation:UITableViewRowAnimationNone];
+            }
+        } else if (indexPath.row == 0) {        
             if (fileDownloaded) {
-                NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
-                NSString *documentsDirectory = [paths objectAtIndex:0];        
-                NSString *shortPath = [NSString stringWithFormat:@"/%@/%@", self.container.name, self.object.fullPath];
-                NSString *filePath = [documentsDirectory stringByAppendingString:shortPath];
-                                
+                OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate];
+                NSString *filePath = [app.cachedObjectsDictionary objectForKey:object.hash];
                 self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];
                 self.documentInteractionController.delegate = self;
+                self.documentInteractionController.name = object.name;
 
                 UITableViewCell *openFileCell = [self.tableView cellForRowAtIndexPath:indexPath];
-                if (![self.documentInteractionController presentOptionsMenuFromRect:openFileCell.frame inView:self.view animated:YES]) {
+                CGRect frameToPresentMenuFrom = CGRectMake(openFileCell.frame.origin.x,
+                                                           openFileCell.frame.origin.y - self.tableView.contentOffset.y,
+                                                           openFileCell.frame.size.width, 
+                                                           openFileCell.frame.size.height);
+                if (![self.documentInteractionController presentOptionsMenuFromRect:frameToPresentMenuFrom inView:self.view animated:YES]) {
                     if ([self.object isPlayableMedia]) {
                         MediaViewController *vc = [[MediaViewController alloc] initWithNibName:@"MediaViewController" bundle:nil];
                         vc.container = self.container;
                     }
                 } 
                 
-                [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:actionsSection] animated:YES];                
-                
-            } else {                
-                if (!fileDownloading) {
-                    // download the file
-                    fileDownloading = YES;
-                    [self.account.manager getObject:self.container object:self.object downloadProgressDelegate:self];
-                    [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationNone];
-                }
+                [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:kActions] animated:YES];
                 
-            }
+            } 
         } else if (indexPath.row == 1) {
             
             NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
             if (![MFMailComposeViewController canSendMail]) {
                 [self alert:@"Cannot send mail" message:@"Your device has not been configured for sending email"];
                 [self.tableView deselectRowAtIndexPath:indexPath animated:NO];
-            }
-            else {
+            } else {
                 MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init];
             
                 vc.mailComposeDelegate = self;         
                 [vc setSubject:self.object.name];
                 [vc addAttachmentData:data mimeType:self.object.contentType fileName:self.object.name];
                 [vc setMessageBody:@"" isHTML:NO];    
-                if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
+                if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
                     vc.modalPresentationStyle = UIModalPresentationPageSheet;
                 }                
                 [self presentModalViewController:vc animated:YES];
             }
         }
     } else if (indexPath.section == deleteSection) {
+        UIActionSheet *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] autorelease];
         [deleteActionSheet showInView:self.view];
+    } else if (indexPath.section == versionsSection) {
+        ObjectVersionsViewController *vc = [[ObjectVersionsViewController alloc] initWithNibName:@"ObjectVersionsViewController" bundle:nil];
+        vc.account = account;
+        vc.container = container;
+        vc.object = object;
+        [self.navigationController pushViewController:vc animated:YES];
+        [vc release];
     }
 }
 
     if (newProgress >= 1.0) {
         fileDownloading = NO;
         fileDownloaded = YES;
-        
-        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:1 inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationBottom];
-        [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationNone];
+        [self.tableView reloadData];
     }
 }
 
-
-#pragma mark -
-#pragma mark Document Interation Controller Delegate
+#pragma mark - UIDocumentInteractionControllerDelegate
 
 - (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *) controller {
     return self.navigationController;
 }
 
-- (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controllers {
-    [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:actionsSection] animated:YES];
-}
-
-#pragma mark -
-#pragma mark Action Sheet Delegate
-
-- (void)deleteObjectRow {
-    [self.folderViewController.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:selectedIndexPath] withRowAnimation:UITableViewRowAnimationLeft];
-}
+#pragma mark - UIActionSheetDelegate
 
 - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
-    if ([actionSheet isEqual:deleteActionSheet]) {
-        if (buttonIndex == 0) {
-            // delete the file and pop out
-            
-            NSString *activityMessage = @"Deleting file";
-            
-            activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
-            [activityIndicatorView addToView:self.view];
-
-            
-            [[self.account.manager deleteObject:self.container object:self.object] 
-             success:^(OpenStackRequest *request) {
-                 [activityIndicatorView removeFromSuperviewAndRelease];
-                 performingAction = NO;
-                 [self.folder.objects removeObjectForKey:self.object.name];
-                 
-                 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
-                     [self.navigationController popViewControllerAnimated:YES];
-                     if (account.shared)
-                         self.folderViewController.needsRefreshing = YES;
-                 } else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
-                     if (!account.shared)
-                         [self.folderViewController setDetailViewController];
-                     else 
-                         if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
-                             [self.folderViewController refreshButtonPressed:nil];
-                 }
-                 
-                 if ([self.folder.objects count] + [self.folder.folders count] == 0) {
-                     [self.folderViewController.tableView reloadData];
-                 } else {
-                     [self.folderViewController.tableView selectRowAtIndexPath:selectedIndexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
-                     [NSTimer scheduledTimerWithTimeInterval:0.75 target:self selector:@selector(deleteObjectRow) userInfo:nil repeats:NO];
-                 }
+    if (buttonIndex == 0) {
+        // delete the file and pop out
+        self.folderViewController.refreshButton.enabled = NO;
+        __block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Deleting file..."
+                                                                                                       andAddToView:self.view];
+        [[self.account.manager deleteObject:self.container object:self.object] 
+         success:^(OpenStackRequest *request) {
+             [activityIndicatorView removeFromSuperview];
+             if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
+                 [self.navigationController popViewControllerAnimated:YES];
+                 if (account.shared)
+                     self.folderViewController.needsRefreshing = YES;
+             } else if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
+                 self.folderViewController.selectedObjectViewController = nil;
+                 if (!account.shared)
+                     [self.folderViewController setDetailViewController];
+                 else 
+                    [self.folderViewController refreshButtonPressed:nil];
+//                 self.folderViewController.refreshButton.enabled = YES;
              }
-             failure:^(OpenStackRequest *request) {
-                 [activityIndicatorView removeFromSuperviewAndRelease];
-                 [self hideToolbarActivityMessage];
-                 performingAction = NO;
-                 [self alert:@"There was a problem deleting this file." request:request]; 
-             }];
-        }
-        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:deleteSection];
-        [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
-    } else if ([actionSheet isEqual:cdnURLActionSheet]) {
-        NSURL *url = [NSURL URLWithString:[[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
-
-        if (buttonIndex == 0) {
-            // copy to pasteboard
-            UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
-            [pasteboard setString:[url description]];
-        } else if (buttonIndex == 1) {
-            // open in safari
-            UIApplication *application = [UIApplication sharedApplication];
-            if ([application canOpenURL:url]) {
-                [application openURL:url];
-            } else {
-                [self alert:@"Error" message:[NSString stringWithFormat:@"This URL cannot be opened.\n%@", url]];
-            }
-        } else if (buttonIndex == 2) {
-            // email link to file
-            MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init];
-            vc.mailComposeDelegate = self;             
-            [vc setSubject:self.object.name];
-            [vc setMessageBody:[url description] isHTML:NO];
-            if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
-                vc.modalPresentationStyle = UIModalPresentationPageSheet;
-            }                
-            [self presentModalViewController:vc animated:YES];
-            [vc release];        
-        } else if (buttonIndex == 3) {
-            // tweet link to file
-            UIApplication *app = [UIApplication sharedApplication];            
-            NSURL *twitterURL = [NSURL URLWithString:[NSString stringWithFormat:@"twitter://post?message=%@", [[url description] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
-            if ([app canOpenURL:twitterURL]) {
-                [app openURL:twitterURL];
-            }
-        }
-        [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:cdnURLSection] animated:YES];
+             if (self.folder.objectsAndFoldersCount == 1) {
+                 [self.folder removeObject:self.object];
+                 self.folderViewController.folder = self.folderViewController.folder;
+             } else {
+                 [self.folderViewController deleteAnimatedObject:self.object];
+             }
+             self.folderViewController.refreshButton.enabled = YES;
+         }
+         failure:^(OpenStackRequest *request) {
+             [activityIndicatorView removeFromSuperview];
+             [self alert:@"There was a problem deleting this file." request:request];
+             self.folderViewController.refreshButton.enabled = YES;
+         }];
     }
+    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:deleteSection];
+    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
 }
 
-#pragma mark -
-#pragma mark Mail Composer Delegate
+#pragma mark - MFMailComposeViewControllerDelegate
 
 // Dismisses the email composition interface when users tap Cancel or Send.
 - (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error { 
        [self dismissModalViewControllerAnimated:YES];
-    [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:actionsSection] animated:YES];
-}
-
-#pragma mark -
-#pragma mark Switches
-
-- (void)objectIsPublicSwitchChanged:(id)sender
-{
-    NSString *activityMessage = [NSString stringWithFormat:@"Enabling public link.."];
-    self.oldPubicURI = object.publicURI;
-    
-    if (objectIsPublic) {
-        activityMessage = [NSString stringWithFormat:@"Disabling public link.."];
-        object.publicURI = @"";
-    }
-    else {
-        object.publicURI = @"TRUE";
-    }
-    
-    activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
-    [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];    
-    
-    objectIsPublic = !objectIsPublic;
-    [[self.account.manager writeObjectMetadata:container object:object] 
-     success:^(OpenStackRequest *request) {
-         NSIndexPath *publicURICellIndexPath = [NSIndexPath indexPathForRow:1 inSection:kPublic];
-         if (objectIsPublic) {
-             [[self.account.manager getObjectInfo:container object:object] 
-              success:^(OpenStackRequest *request) {
-                  [activityIndicatorView removeFromSuperviewAndRelease];
-                  object.publicURI = [request.responseHeaders objectForKey:@"X-Object-Public"];
-                  NSIndexPath *publicURICellIndexPath = [NSIndexPath indexPathForRow:1 inSection:kPublic];
-                  [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:publicURICellIndexPath]
-                                        withRowAnimation:UITableViewRowAnimationBottom];
-              }
-              failure:^(OpenStackRequest *request) {
-                  [activityIndicatorView removeFromSuperviewAndRelease];
-                  [self alert:@"There was a problem retrieving the public link from the server." request:request]; 
-              }];
-         }
-         else {
-             [activityIndicatorView removeFromSuperviewAndRelease];
-             [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:publicURICellIndexPath]
-                                   withRowAnimation:UITableViewRowAnimationTop];
-         }
-     }
-     failure:^(OpenStackRequest *request) {
-         [activityIndicatorView removeFromSuperviewAndRelease];
-         objectIsPublic = !objectIsPublic;
-         objectIsPublicSwitch.on = !objectIsPublicSwitch.on;
-         object.publicURI = oldPubicURI;
-         [self alert:@"There was a problem enabling the public link." request:request];           
-
-     }];    
+    [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:kActions] animated:YES];
 }
 
-
-
-#pragma mark -
-#pragma mark Memory management
-
-- (void)dealloc {
-    [account release];
-    [downloadProgressView release];
-    [deleteActionSheet release];
-    [cdnURLActionSheet release];
-    [tableView release];
-    [folderViewController release];
-    [objectIsPublicSwitch release];
-    [permissions release];
-    [documentInteractionController release];
-
-    [super dealloc];
-}
-
-
 @end