Merge branch 'long_press'
authorDavid A. Velasco <dvelasco@solidgear.es>
Fri, 23 Nov 2012 13:32:58 +0000 (14:32 +0100)
committerDavid A. Velasco <dvelasco@solidgear.es>
Fri, 23 Nov 2012 13:32:58 +0000 (14:32 +0100)
21 files changed:
res/layout/edit_box_dialog.xml
res/menu/file_context_menu.xml [new file with mode: 0644]
res/values-large/bools.xml [new file with mode: 0644]
res/values/bools.xml [new file with mode: 0644]
res/values/strings.xml
src/com/owncloud/android/datamodel/DataStorageManager.java
src/com/owncloud/android/datamodel/FileDataStorageManager.java
src/com/owncloud/android/datamodel/OCFile.java
src/com/owncloud/android/files/services/FileDownloader.java
src/com/owncloud/android/files/services/FileUploader.java
src/com/owncloud/android/operations/RemoveFileOperation.java
src/com/owncloud/android/operations/RenameFileOperation.java
src/com/owncloud/android/operations/SynchronizeFileOperation.java
src/com/owncloud/android/ui/activity/AccountSelectActivity.java
src/com/owncloud/android/ui/activity/FileDetailActivity.java
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/activity/UploadFilesActivity.java
src/com/owncloud/android/ui/adapter/FileListListAdapter.java
src/com/owncloud/android/ui/dialog/EditNameDialog.java
src/com/owncloud/android/ui/fragment/FileDetailFragment.java
src/com/owncloud/android/ui/fragment/OCFileListFragment.java

index c2168ab..f1d541c 100644 (file)
         android:id="@+id/user_input"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:ems="10" >
+        android:ems="10" 
+               android:inputType="textNoSuggestions"
+               >
 
-        <requestFocus />
     </EditText>
 
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal"
-        android:gravity="center_horizontal" >
-
-        <Button
-            android:id="@+id/cancel"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/common_cancel" />
-
-        <Button
-            android:id="@+id/ok"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/common_ok" />
-
-    </LinearLayout>
-
 </LinearLayout>
diff --git a/res/menu/file_context_menu.xml b/res/menu/file_context_menu.xml
new file mode 100644 (file)
index 0000000..622c483
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu  xmlns:android="http://schemas.android.com/apk/res/android">
+    
+       <item   android:id="@+id/open_file_item" 
+               android:title="@string/filedetails_open" 
+               android:icon="@android:drawable/ic_menu_edit"
+       />
+       
+       <item   android:id="@+id/download_file_item" 
+               android:title="@string/filedetails_download" 
+       />
+       
+       <item   android:id="@+id/cancel_download_item" 
+               android:title="@string/common_cancel_download" 
+               android:icon="@android:drawable/ic_menu_close_clear_cancel"
+       />
+       
+       <item   android:id="@+id/cancel_upload_item" 
+               android:title="@string/common_cancel_upload" 
+               android:icon="@android:drawable/ic_menu_close_clear_cancel"
+       />
+       
+       <item   android:id="@+id/rename_file_item" 
+               android:title="@string/common_rename" 
+               android:icon="@android:drawable/ic_menu_set_as"
+       />
+       
+    <item      android:id="@+id/remove_file_item" 
+               android:title="@string/common_remove" 
+               android:icon="@android:drawable/ic_menu_delete"
+       />
+    
+</menu>
diff --git a/res/values-large/bools.xml b/res/values-large/bools.xml
new file mode 100644 (file)
index 0000000..e143605
--- /dev/null
@@ -0,0 +1,4 @@
+<!-- Large screen boolean values -->
+<resources>
+    <bool name="large_layout">true</bool>
+</resources>
\ No newline at end of file
diff --git a/res/values/bools.xml b/res/values/bools.xml
new file mode 100644 (file)
index 0000000..7ca86c6
--- /dev/null
@@ -0,0 +1,4 @@
+<!-- Default boolean values -->
+<resources>
+    <bool name="large_layout">false</bool>
+</resources>
\ No newline at end of file
index 0428f41..378bb00 100644 (file)
@@ -81,7 +81,9 @@
     <string name="common_yes">Yes</string>
     <string name="common_no">No</string>
     <string name="common_ok">OK</string>
-    <string name="common_cancel">Cancel</string>
+    <string name="common_cancel_download">Cancel download</string>
+    <string name="common_cancel_upload">Cancel upload</string>
+       <string name="common_cancel">Cancel</string>
     <string name="common_save_exit">Save &amp; Exit</string>
     <string name="common_exit">Leave ownCloud</string>
     <string name="common_error">Error</string>
     <string name="uploader_upload_failed_content_multiple">Upload failed: %1$d/%2$d files were upload</string>
     <string name="downloader_download_in_progress_ticker">Downloading &#8230;</string>
     <string name="downloader_download_in_progress_content">%1$d%% Downloading %2$s</string>
-    <string name="downloader_download_succeeded_ticker">Download suceeded</string>
+    <string name="downloader_download_succeeded_ticker">Download succeeded</string>
     <string name="downloader_download_succeeded_content">%1$s was successfully download</string>
     <string name="downloader_download_failed_ticker">Download failed</string>
     <string name="downloader_download_failed_content">Download of %1$s could not be completed</string>
     <string name="common_rename">Rename</string>
     <string name="common_remove">Remove</string>
     
-       <string name="confirmation_remove_alert">"Do you really want to remove %1$s ?"</string>
-       <string name="confirmation_remove_local">Local only</string>
-       <string name="confirmation_remove_remote">Remove from server</string>
-       <string name="confirmation_remove_remote_and_local">Remote and local</string>
+         <string name="confirmation_remove_alert">"Do you really want to remove %1$s ?"</string>
+         <string name="confirmation_remove_folder_alert">"Do you really want to remove %1$s and its contents ?"</string>
+         <string name="confirmation_remove_local">Local only</string>
+         <string name="confirmation_remove_folder_local">Local contents only</string>
+         <string name="confirmation_remove_remote">Remove from server</string>
+         <string name="confirmation_remove_remote_and_local">Remote and local</string>
 
     <string name="remove_success_msg">"Successful removal"</string>
     <string name="remove_fail_msg">"Removal could not be completed"</string>
     
+    <string name="rename_dialog_title">Enter a new name</string>
     <string name="rename_local_fail_msg">"Local copy could not be renamed; try a differente new name"</string>
     <string name="rename_server_fail_msg">"Rename could not be completed"</string>
         
index 49a3cd7..0ab0504 100644 (file)
@@ -40,4 +40,8 @@ public interface DataStorageManager {
     public Vector<OCFile> getDirectoryContent(OCFile f);
     
     public void removeFile(OCFile file, boolean removeLocalCopy);
+    
+    public void removeDirectory(OCFile dir, boolean removeDBData, boolean removeLocalContent);
+
+    public void moveDirectory(OCFile dir, String newPath);
 }
index 7d9a678..2640404 100644 (file)
@@ -122,9 +122,14 @@ public class FileDataStorageManager implements DataStorageManager {
         cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
         cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
 
-        if (fileExists(file.getRemotePath())) {
-            OCFile oldFile = getFileByPath(file.getRemotePath());
-            file.setFileId(oldFile.getFileId());
+        boolean sameRemotePath = fileExists(file.getRemotePath());
+        if (sameRemotePath ||
+            fileExists(file.getFileId())        ) {           // for renamed files; no more delete and create
+            
+            if (sameRemotePath) {
+                OCFile oldFile = getFileByPath(file.getRemotePath());
+                file.setFileId(oldFile.getFileId());
+            }
 
             overriden = true;
             if (getContentResolver() != null) {
@@ -207,6 +212,19 @@ public class FileDataStorageManager implements DataStorageManager {
                                         new String[] { String.valueOf(file.getFileId()) })
                         .build());
                 
+            } else if (fileExists(file.getFileId())) {
+                    OCFile oldFile = getFileById(file.getFileId());
+                    if (file.getStoragePath() == null && oldFile.getStoragePath() != null)
+                        file.setStoragePath(oldFile.getStoragePath());
+                    if (!file.isDirectory());
+                        cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
+
+                    operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
+                            withValues(cv).
+                            withSelection(  ProviderTableMeta._ID + "=?", 
+                                            new String[] { String.valueOf(file.getFileId()) })
+                            .build());
+                    
             } else {
                 operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).withValues(cv).build());
             }
@@ -426,6 +444,111 @@ public class FileDataStorageManager implements DataStorageManager {
         if (file.isDown() && removeLocalCopy) {
             new File(file.getStoragePath()).delete();
         }
+        if (file.isDirectory() && removeLocalCopy) {
+            File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
+            if (f.exists() && f.isDirectory() && (f.list() == null || f.list().length == 0)) {
+                f.delete();
+            }
+        }
+    }
+
+    @Override
+    public void removeDirectory(OCFile dir, boolean removeDBData, boolean removeLocalContent) {
+        // TODO consider possible failures
+        if (dir != null && dir.isDirectory() && dir.getFileId() != -1) {
+            Vector<OCFile> children = getDirectoryContent(dir);
+            if (children != null) {
+                OCFile child = null;
+                for (int i=0; i<children.size(); i++) {
+                    child = children.get(i);
+                    if (child.isDirectory()) {
+                        removeDirectory(child, removeDBData, removeLocalContent);
+                    } else {
+                        if (removeDBData) {
+                            removeFile(child, removeLocalContent);
+                        } else if (removeLocalContent) {
+                            if (child.isDown()) {
+                                new File(child.getStoragePath()).delete();
+                            }
+                        }
+                    }
+                }
+                if (removeDBData) {
+                    removeFile(dir, true);
+                }
+            }
+        }
+    }
+    
+    
+    /**
+     * Updates database for a folder that was moved to a different location.
+     * 
+     * TODO explore better (faster) implementations
+     * TODO throw exceptions up !
+     */
+    @Override
+    public void moveDirectory(OCFile dir, String newPath) {
+        // TODO check newPath
+        
+        if (dir != null && dir.isDirectory() && dir.fileExists() && !dir.getFileName().equals(OCFile.PATH_SEPARATOR)) {
+            /// 1. get all the descendants of 'dir' in a single QUERY (including 'dir')
+            Cursor c = null;
+            if (getContentProvider() != null) {
+                try {
+                    c = getContentProvider().query(ProviderTableMeta.CONTENT_URI, 
+                                                    null,
+                                                    ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ?",
+                                                    new String[] { mAccount.name, dir.getRemotePath() + "%" }, null);
+                } catch (RemoteException e) {
+                    Log.e(TAG, e.getMessage());
+                }
+            } else {
+                c = getContentResolver().query(ProviderTableMeta.CONTENT_URI, 
+                                                null,
+                                                ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ?",
+                                                new String[] { mAccount.name, dir.getRemotePath() + "%" }, null);
+            }
+
+            /// 2. prepare a batch of update operations to change all the descendants
+            ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(c.getCount());
+            int lengthOfOldPath = dir.getRemotePath().length();
+            String defaultSavePath = FileStorageUtils.getSavePath(mAccount.name);
+            int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
+            if (c.moveToFirst()) {
+                do {
+                    ContentValues cv = new ContentValues(); // don't take the constructor out of the loop and clear the object
+                    OCFile child = createFileInstance(c);
+                    cv.put(ProviderTableMeta.FILE_PATH, newPath + child.getRemotePath().substring(lengthOfOldPath));
+                    if (child.getStoragePath() != null && child.getStoragePath().startsWith(defaultSavePath)) {
+                        cv.put(ProviderTableMeta.FILE_STORAGE_PATH, defaultSavePath + newPath + child.getStoragePath().substring(lengthOfOldStoragePath));
+                    }
+                    operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
+                                                                        withValues(cv).
+                                                                        withSelection(  ProviderTableMeta._ID + "=?", 
+                                                                                new String[] { String.valueOf(child.getFileId()) })
+                                                                                .build());
+                } while (c.moveToNext());
+            }
+            c.close();
+            
+            /// 3. apply updates in batch
+            try {
+                if (getContentResolver() != null) {
+                    getContentResolver().applyBatch(ProviderMeta.AUTHORITY_FILES, operations);
+                
+                } else {
+                    getContentProvider().applyBatch(operations);
+                }
+                
+            } catch (OperationApplicationException e) {
+                Log.e(TAG, "Fail to update descendants of " + dir.getFileId() + " in database", e);
+                
+            } catch (RemoteException e) {
+                Log.e(TAG, "Fail to update desendants of " + dir.getFileId() + " in database", e);
+            }
+            
+        }
     }
 
 }
index 766a832..ec4e749 100644 (file)
@@ -22,6 +22,7 @@ import java.io.File;
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Log;
 
 public class OCFile implements Parcelable, Comparable<OCFile> {
 
@@ -38,6 +39,8 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
     };
 
     public static final String PATH_SEPARATOR = "/";
+
+    private static final String TAG = OCFile.class.getSimpleName();
     
     private long mId;
     private long mParentId;
@@ -217,7 +220,25 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
      */
     public String getFileName() {
         File f = new File(getRemotePath());
-        return f.getName().length() == 0 ? "/" : f.getName();
+        return f.getName().length() == 0 ? PATH_SEPARATOR : f.getName();
+    }
+    
+    /**
+     * Sets the name of the file
+     * 
+     * Does nothing if the new name is null, empty or includes "/" ; or if the file is the root directory 
+     */
+    public void setFileName(String name) {
+        Log.d(TAG, "OCFile name changin from " + mRemotePath);
+        if (name != null && name.length() > 0 && !name.contains(PATH_SEPARATOR) && !mRemotePath.equals(PATH_SEPARATOR)) {
+            String parent = (new File(getRemotePath())).getParent();
+            parent = (parent.endsWith(PATH_SEPARATOR)) ? parent : parent + PATH_SEPARATOR;
+            mRemotePath =  parent + name;
+            if (isDirectory()) {
+                mRemotePath += PATH_SEPARATOR;
+            }
+            Log.d(TAG, "OCFile name changed to " + mRemotePath);
+        }
     }
 
     /**
@@ -384,7 +405,7 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
     @Override
     public String toString() {
         String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, parentId=%s, keepInSinc=%s]";
-        asString = String.format(asString, new Long(mId), getFileName(), mMimeType, isDown(), mLocalPath, mRemotePath, new Long(mParentId), new Boolean(mKeepInSync));
+        asString = String.format(asString, Long.valueOf(mId), getFileName(), mMimeType, isDown(), mLocalPath, mRemotePath, Long.valueOf(mParentId), Boolean.valueOf(mKeepInSync));
         return asString;
     }
 
index f58e563..5e80f5d 100644 (file)
@@ -190,14 +190,27 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         \r
         \r
         /**\r
-         * Returns True when the file described by 'file' in the ownCloud account 'account' is downloading or waiting to download\r
+         * Returns True when the file described by 'file' in the ownCloud account 'account' is downloading or waiting to download.\r
+         * \r
+         * If 'file' is a directory, returns 'true' if some of its descendant files is downloading or waiting to download. \r
          * \r
          * @param account       Owncloud account where the remote file is stored.\r
          * @param file          A file that could be in the queue of downloads.\r
          */\r
         public boolean isDownloading(Account account, OCFile file) {\r
+            String targetKey = buildRemoteName(account, file);\r
             synchronized (mPendingDownloads) {\r
-                return (mPendingDownloads.containsKey(buildRemoteName(account, file)));\r
+                if (file.isDirectory()) {\r
+                    // this can be slow if there are many downloads :(\r
+                    Iterator<String> it = mPendingDownloads.keySet().iterator();\r
+                    boolean found = false;\r
+                    while (it.hasNext() && !found) {\r
+                        found = it.next().startsWith(targetKey);\r
+                    }\r
+                    return found;\r
+                } else {\r
+                    return (mPendingDownloads.containsKey(targetKey));\r
+                }\r
             }\r
         }\r
     }\r
index 1847a96..958036a 100644 (file)
@@ -71,7 +71,6 @@ import eu.alefzero.webdav.WebdavClient;
 public class FileUploader extends Service implements OnDatatransferProgressListener {
 
     public static final String UPLOAD_FINISH_MESSAGE = "UPLOAD_FINISH";
-    public static final String EXTRA_PARENT_DIR_ID = "PARENT_DIR_ID";
     public static final String EXTRA_UPLOAD_RESULT = "RESULT";
     public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";
     public static final String EXTRA_OLD_REMOTE_PATH = "OLD_REMOTE_PATH";
@@ -79,8 +78,8 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     public static final String ACCOUNT_NAME = "ACCOUNT_NAME";    
     
     public static final String KEY_FILE = "FILE";
-    public static final String KEY_LOCAL_FILE = "LOCAL_FILE";       // TODO remove this as a possible input argument ; use KEY_FILE everywhere
-    public static final String KEY_REMOTE_FILE = "REMOTE_FILE";     // TODO remove this as a possible input argument ; use KEY_FILE everywhere
+    public static final String KEY_LOCAL_FILE = "LOCAL_FILE";
+    public static final String KEY_REMOTE_FILE = "REMOTE_FILE";
     public static final String KEY_MIME_TYPE = "MIME_TYPE";
 
     public static final String KEY_ACCOUNT = "ACCOUNT";
@@ -313,12 +312,25 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         /**
          * Returns True when the file described by 'file' is being uploaded to the ownCloud account 'account' or waiting for it
          * 
+         * If 'file' is a directory, returns 'true' if some of its descendant files is downloading or waiting to download. 
+         * 
          * @param account       Owncloud account where the remote file will be stored.
          * @param file          A file that could be in the queue of pending uploads
          */
         public boolean isUploading(Account account, OCFile file) {
+            String targetKey = buildRemoteName(account, file);
             synchronized (mPendingUploads) {
-                return (mPendingUploads.containsKey(buildRemoteName(account, file)));
+                if (file.isDirectory()) {
+                    // this can be slow if there are many downloads :(
+                    Iterator<String> it = mPendingUploads.keySet().iterator();
+                    boolean found = false;
+                    while (it.hasNext() && !found) {
+                        found = it.next().startsWith(targetKey);
+                    }
+                    return found;
+                } else {
+                    return (mPendingUploads.containsKey(targetKey));
+                }
             }
         }
     }
@@ -541,7 +553,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         
         // parent dir
         String parentPath = new File(remotePath).getParent();
-        parentPath = parentPath.endsWith("/")?parentPath:parentPath+"/" ;
+        parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR ;
         OCFile parentDir = storageManager.getFileByPath(parentPath);
         if (parentDir == null) {
             throw new IllegalStateException("Can not upload a file to a non existing remote location: " + parentPath);
@@ -682,7 +694,6 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         end.putExtra(EXTRA_FILE_PATH, upload.getStoragePath());
         end.putExtra(ACCOUNT_NAME, upload.getAccount().name);
         end.putExtra(EXTRA_UPLOAD_RESULT, uploadResult.isSuccess());
-        end.putExtra(EXTRA_PARENT_DIR_ID, upload.getFile().getParentId());
         sendStickyBroadcast(end);
     }
 
index f1a28ba..bfc063f 100644 (file)
@@ -18,6 +18,7 @@
 
 package com.owncloud.android.operations;
 
+import org.apache.commons.httpclient.HttpStatus;
 import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
 
 import android.util.Log;
@@ -60,6 +61,16 @@ public class RemoveFileOperation extends RemoteOperation {
     
     
     /**
+     * Getter for the file to remove (or removed, if the operation was successfully performed).
+     * 
+     * @return      File to remove or already removed.
+     */
+    public OCFile getFile() {
+        return mFileToRemove;
+    }
+    
+    
+    /**
      * Performs the remove operation
      * 
      * @param   client      Client object to communicate with the remote ownCloud server.
@@ -71,11 +82,15 @@ public class RemoveFileOperation extends RemoteOperation {
         try {
             delete = new DeleteMethod(client.getBaseUri() + WebdavUtils.encodePath(mFileToRemove.getRemotePath()));
             int status = client.executeMethod(delete, REMOVE_READ_TIMEOUT, REMOVE_CONNECTION_TIMEOUT);
-            if (delete.succeeded()) {
-                mDataStorageManager.removeFile(mFileToRemove, mDeleteLocalCopy);
+            if (delete.succeeded() || status == HttpStatus.SC_NOT_FOUND) {
+                if (mFileToRemove.isDirectory()) {
+                    mDataStorageManager.removeDirectory(mFileToRemove, true, mDeleteLocalCopy);
+                } else {
+                    mDataStorageManager.removeFile(mFileToRemove, mDeleteLocalCopy);
+                }
             }
             delete.getResponseBodyAsString();   // exhaust the response, although not interesting
-            result = new RemoteOperationResult(delete.succeeded(), status);
+            result = new RemoteOperationResult((delete.succeeded() || status == HttpStatus.SC_NOT_FOUND), status);
             Log.i(TAG, "Remove " + mFileToRemove.getRemotePath() + ": " + result.getLogMessage());
             
         } catch (Exception e) {
index 483a312..f4ec7b0 100644 (file)
@@ -24,6 +24,7 @@ import java.io.IOException;
 import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
 //import org.apache.jackrabbit.webdav.client.methods.MoveMethod;
 
+import android.accounts.Account;
 import android.util.Log;
 
 import com.owncloud.android.datamodel.DataStorageManager;
@@ -48,7 +49,9 @@ public class RenameFileOperation extends RemoteOperation {
     
 
     private OCFile mFile;
+    private Account mAccount;
     private String mNewName;
+    private String mNewRemotePath;
     private DataStorageManager mStorageManager;
     
     
@@ -56,12 +59,15 @@ public class RenameFileOperation extends RemoteOperation {
      * Constructor
      * 
      * @param file                  OCFile instance describing the remote file or folder to rename
+     * @param account               OwnCloud account containing the remote file 
      * @param newName               New name to set as the name of file.
      * @param storageManager        Reference to the local database corresponding to the account where the file is contained. 
      */
-    public RenameFileOperation(OCFile file, String newName, DataStorageManager storageManager) {
+    public RenameFileOperation(OCFile file, Account account, String newName, DataStorageManager storageManager) {
         mFile = file;
+        mAccount = account;
         mNewName = newName;
+        mNewRemotePath = null;
         mStorageManager = storageManager;
     }
   
@@ -80,60 +86,63 @@ public class RenameFileOperation extends RemoteOperation {
         RemoteOperationResult result = null;
         
         LocalMoveMethod move = null;
-        //MoveMethod move = null;   // TODO find out why not use this
-        String newRemotePath = null;
+        mNewRemotePath = null;
         try {
             if (mNewName.equals(mFile.getFileName())) {
                 return new RemoteOperationResult(ResultCode.OK);
             }
         
-            newRemotePath = (new File(mFile.getRemotePath())).getParent() + mNewName;
+            String parent = (new File(mFile.getRemotePath())).getParent();
+            parent = (parent.endsWith(OCFile.PATH_SEPARATOR)) ? parent : parent + OCFile.PATH_SEPARATOR; 
+            mNewRemotePath =  parent + mNewName;
+            if (mFile.isDirectory()) {
+                mNewRemotePath += OCFile.PATH_SEPARATOR;
+            }
             
             // check if the new name is valid in the local file system
             if (!isValidNewName()) {
                 return new RemoteOperationResult(ResultCode.INVALID_LOCAL_FILE_NAME);
             }
         
-            // check if a remote file with the new name already exists
-            if (client.existsFile(newRemotePath)) {
+            // check if a file with the new name already exists
+            if (client.existsFile(mNewRemotePath) ||                             // remote check could fail by network failure, or by indeterminate behavior of HEAD for folders ... 
+                    mStorageManager.getFileByPath(mNewRemotePath) != null) {     // ... so local check is convenient
                 return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
             }
-            /*move = new MoveMethod( client.getBaseUri() + WebdavUtils.encodePath(mFile.getRemotePath()), 
-                                                client.getBaseUri() + WebdavUtils.encodePath(newRemotePath),
-                                                false);*/
             move = new LocalMoveMethod( client.getBaseUri() + WebdavUtils.encodePath(mFile.getRemotePath()),
-                                        client.getBaseUri() + WebdavUtils.encodePath(newRemotePath));
+                                        client.getBaseUri() + WebdavUtils.encodePath(mNewRemotePath));
             int status = client.executeMethod(move, RENAME_READ_TIMEOUT, RENAME_CONNECTION_TIMEOUT);
             if (move.succeeded()) {
 
-                // create new OCFile instance for the renamed file
-                OCFile newFile = obtainUpdatedFile();
-                OCFile oldFile = mFile;
-                mFile = newFile; 
-                
-                // try to rename the local copy of the file
-                if (oldFile.isDown()) {
-                    File f = new File(oldFile.getStoragePath());
-                    String newStoragePath = f.getParent() + mNewName;
-                    if (f.renameTo(new File(newStoragePath))) {
-                        mFile.setStoragePath(newStoragePath);
-                    }
-                    // else - NOTHING: the link to the local file is kept although the local name can't be updated
-                    // TODO - study conditions when this could be a problem
+                if (mFile.isDirectory()) {
+                    saveLocalDirectory();
+                    
+                } else {
+                    saveLocalFile();
+                    
                 }
-                
-                mStorageManager.removeFile(oldFile, false);
-                mStorageManager.saveFile(mFile);
+             
+            /* 
+             *} else if (mFile.isDirectory() && (status == 207 || status >= 500)) {
+             *   // TODO 
+             *   // if server fails in the rename of a folder, some children files could have been moved to a folder with the new name while some others
+             *   // stayed in the old folder;
+             *   //
+             *   // easiest and heaviest solution is synchronizing the parent folder (or the full account);
+             *   //
+             *   // a better solution is synchronizing the folders with the old and new names;
+             *}
+             */
                 
             }
             
             move.getResponseBodyAsString(); // exhaust response, although not interesting
             result = new RemoteOperationResult(move.succeeded(), status);
-            Log.i(TAG, "Rename " + mFile.getRemotePath() + " to " + newRemotePath + ": " + result.getLogMessage());
+            Log.i(TAG, "Rename " + mFile.getRemotePath() + " to " + mNewRemotePath + ": " + result.getLogMessage());
             
         } catch (Exception e) {
             result = new RemoteOperationResult(e);
-            Log.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((newRemotePath==null) ? mNewName : newRemotePath) + ": " + result.getLogMessage(), e);
+            Log.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " + result.getLogMessage(), e);
             
         } finally {
             if (move != null)
@@ -143,6 +152,35 @@ public class RenameFileOperation extends RemoteOperation {
     }
 
     
+    private void saveLocalDirectory() {
+        mStorageManager.moveDirectory(mFile, mNewRemotePath);
+        String localPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile);
+        File localDir = new File(localPath);
+        if (localDir.exists()) {
+            localDir.renameTo(new File(FileStorageUtils.getSavePath(mAccount.name) + mNewRemotePath));
+            // TODO - if renameTo fails, children files that are already down will result unlinked
+        }
+    }
+
+    private void saveLocalFile() {
+        mFile.setFileName(mNewName);
+        
+        // try to rename the local copy of the file
+        if (mFile.isDown()) {
+            File f = new File(mFile.getStoragePath());
+            String parentStoragePath = f.getParent();
+            if (!parentStoragePath.endsWith(File.separator))
+                parentStoragePath += File.separator;
+            if (f.renameTo(new File(parentStoragePath + mNewName))) {
+                mFile.setStoragePath(parentStoragePath + mNewName);
+            }
+            // else - NOTHING: the link to the local file is kept although the local name can't be updated
+            // TODO - study conditions when this could be a problem
+        }
+        
+        mStorageManager.saveFile(mFile);
+    }
+
     /**
      * Checks if the new name to set is valid in the file system 
      * 
@@ -180,27 +218,7 @@ public class RenameFileOperation extends RemoteOperation {
     }
 
 
-    /**
-     * Creates a new OCFile for the new remote name of the renamed file.
-     * 
-     * @return      OCFile object with the same information than mFile, but the renamed remoteFile and the storagePath (empty)
-     */
-    private OCFile obtainUpdatedFile() {
-        OCFile file = new OCFile(mStorageManager.getFileById(mFile.getParentId()).getRemotePath() + mNewName);
-        file.setCreationTimestamp(mFile.getCreationTimestamp());
-        file.setFileId(mFile.getFileId());
-        file.setFileLength(mFile.getFileLength());
-        file.setKeepInSync(mFile.keepInSync());
-        file.setLastSyncDateForProperties(mFile.getLastSyncDateForProperties());
-        file.setLastSyncDateForData(mFile.getLastSyncDateForData());
-        file.setMimetype(mFile.getMimetype());
-        file.setModificationTimestamp(mFile.getModificationTimestamp());
-        file.setParentId(mFile.getParentId());
-        return file;
-    }
-
-
-    // move operation - TODO: find out why org.apache.jackrabbit.webdav.client.methods.MoveMethod is not used instead Â¿?
+    // move operation
     private class LocalMoveMethod extends DavMethodBase {
 
         public LocalMoveMethod(String uri, String dest) {
index f98de11..312fa0c 100644 (file)
@@ -223,4 +223,9 @@ public class SynchronizeFileOperation extends RemoteOperation {
         return mTransferWasRequested;
     }
 
+
+    public OCFile getLocalFile() {
+        return mLocalFile;
+    }
+
 }
index b99283e..21736e1 100644 (file)
@@ -166,7 +166,7 @@ public class AccountSelectActivity extends SherlockListActivity implements
             }
         }
 
-        return false;
+        return true;
     }
 
     private void populateAccountList() {
index aade565..ee23ca3 100644 (file)
@@ -114,7 +114,7 @@ public class FileDetailActivity extends SherlockFragmentActivity implements File
             }\r
             FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
             if (fragment != null)\r
-                fragment.updateFileDetails();   // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais())\r
+                fragment.updateFileDetails(false);   // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais())\r
         }\r
 \r
         @Override\r
@@ -152,6 +152,9 @@ public class FileDetailActivity extends SherlockFragmentActivity implements File
         case android.R.id.home:\r
             backToDisplayActivity();\r
             returnValue = true;\r
+            break;\r
+        default:\r
+               returnValue = super.onOptionsItemSelected(item);\r
         }\r
         \r
         return returnValue;\r
@@ -165,7 +168,7 @@ public class FileDetailActivity extends SherlockFragmentActivity implements File
         super.onResume();\r
         if (!mConfigurationChangedToLandscape) { \r
             FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-            fragment.updateFileDetails();\r
+            fragment.updateFileDetails(false);\r
         }\r
     }\r
     \r
index 1f34ae5..4a5b5cb 100644 (file)
@@ -74,7 +74,13 @@ import com.owncloud.android.files.services.FileObserverService;
 import com.owncloud.android.files.services.FileUploader;\r
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;\r
 import com.owncloud.android.network.OwnCloudClientUtils;\r
+import com.owncloud.android.operations.OnRemoteOperationListener;\r
+import com.owncloud.android.operations.RemoteOperation;\r
 import com.owncloud.android.operations.RemoteOperationResult;\r
+import com.owncloud.android.operations.RemoveFileOperation;\r
+import com.owncloud.android.operations.RenameFileOperation;\r
+import com.owncloud.android.operations.SynchronizeFileOperation;\r
+import com.owncloud.android.operations.RemoteOperationResult.ResultCode;\r
 import com.owncloud.android.syncadapter.FileSyncService;\r
 import com.owncloud.android.ui.dialog.SslValidatorDialog;\r
 import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;\r
@@ -92,7 +98,7 @@ import eu.alefzero.webdav.WebdavClient;
  */\r
 \r
 public class FileDisplayActivity extends SherlockFragmentActivity implements\r
-    OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener {\r
+    OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, OnRemoteOperationListener {\r
     \r
     private ArrayAdapter<String> mDirectories;\r
     private OCFile mCurrentDir = null;\r
@@ -332,7 +338,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
                 break;\r
             }\r
             default:\r
-                retval = false;\r
+                retval = super.onOptionsItemSelected(item);\r
         }\r
         return retval;\r
     }\r
@@ -896,16 +902,11 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
          */\r
         @Override\r
         public void onReceive(Context context, Intent intent) {\r
-            long parentDirId = intent.getLongExtra(FileUploader.EXTRA_PARENT_DIR_ID, -1);\r
-            OCFile parentDir = mStorageManager.getFileById(parentDirId);\r
+            String uploadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);\r
             String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);\r
-\r
-            if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name) &&\r
-                    parentDir != null && \r
-                    (   (mCurrentDir == null && parentDir.getFileName().equals("/")) ||\r
-                            parentDir.equals(mCurrentDir)\r
-                    )\r
-                ) {\r
+            boolean sameAccount = accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name);\r
+            boolean isDescendant = (mCurrentDir != null) && (uploadedRemotePath != null) && (uploadedRemotePath.startsWith(mCurrentDir.getRemotePath()));\r
+            if (sameAccount && isDescendant) {\r
                 OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
                 if (fileListFragment != null) { \r
                     fileListFragment.listDirectory();\r
@@ -924,9 +925,9 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         public void onReceive(Context context, Intent intent) {\r
             String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);\r
             String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);\r
-\r
-            if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name) &&\r
-                     mCurrentDir != null && mCurrentDir.getFileId() == mStorageManager.getFileByPath(downloadedRemotePath).getParentId()) {\r
+            boolean sameAccount = accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name);\r
+            boolean isDescendant = (mCurrentDir != null) && (downloadedRemotePath != null) && (downloadedRemotePath.startsWith(mCurrentDir.getRemotePath()));\r
+            if (sameAccount && isDescendant) {\r
                 OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
                 if (fileListFragment != null) { \r
                     fileListFragment.listDirectory();\r
@@ -1051,7 +1052,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
             if (mDualPane) {\r
                 FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
                 if (fragment != null)\r
-                    fragment.updateFileDetails();\r
+                    fragment.updateFileDetails(false);\r
             }\r
         }\r
 \r
@@ -1096,4 +1097,151 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
     }\r
 \r
 \r
+    /**\r
+     * Updates the view associated to the activity after the finish of some operation over files\r
+     * in the current account.\r
+     * \r
+     * @param operation     Removal operation performed.\r
+     * @param result        Result of the removal.\r
+     */\r
+    @Override\r
+    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {\r
+        if (operation instanceof RemoveFileOperation) {\r
+            onRemoveFileOperationFinish((RemoveFileOperation)operation, result);\r
+                \r
+        } else if (operation instanceof RenameFileOperation) {\r
+            onRenameFileOperationFinish((RenameFileOperation)operation, result);\r
+            \r
+        } else if (operation instanceof SynchronizeFileOperation) {\r
+            onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);\r
+        }\r
+    }\r
+\r
+\r
+    /**\r
+     * Updates the view associated to the activity after the finish of an operation trying to remove a \r
+     * file. \r
+     * \r
+     * @param operation     Removal operation performed.\r
+     * @param result        Result of the removal.\r
+     */\r
+    private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {\r
+        dismissDialog(DIALOG_SHORT_WAIT);\r
+        if (result.isSuccess()) {\r
+            Toast msg = Toast.makeText(this, R.string.remove_success_msg, Toast.LENGTH_LONG);\r
+            msg.show();\r
+            OCFile removedFile = operation.getFile();\r
+            if (mDualPane) {\r
+                FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
+                if (details != null && removedFile.equals(details.getDisplayedFile()) ) {\r
+                    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
+                    transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment\r
+                    transaction.commit();\r
+                }\r
+            }\r
+            if (mStorageManager.getFileById(removedFile.getParentId()).equals(mCurrentDir)) {\r
+                mFileList.listDirectory();\r
+            }\r
+                \r
+        } else {\r
+            Toast msg = Toast.makeText(this, R.string.remove_fail_msg, Toast.LENGTH_LONG); \r
+            msg.show();\r
+            if (result.isSslRecoverableException()) {\r
+                mLastSslUntrustedServerResult = result;\r
+                showDialog(DIALOG_SSL_VALIDATOR); \r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Updates the view associated to the activity after the finish of an operation trying to rename a \r
+     * file. \r
+     * \r
+     * @param operation     Renaming operation performed.\r
+     * @param result        Result of the renaming.\r
+     */\r
+    private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) {\r
+        dismissDialog(DIALOG_SHORT_WAIT);\r
+        OCFile renamedFile = operation.getFile();\r
+        if (result.isSuccess()) {\r
+            if (mDualPane) {\r
+                FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
+                if (details != null && renamedFile.equals(details.getDisplayedFile()) ) {\r
+                    details.updateFileDetails(renamedFile, AccountUtils.getCurrentOwnCloudAccount(this));\r
+                }\r
+            }\r
+            if (mStorageManager.getFileById(renamedFile.getParentId()).equals(mCurrentDir)) {\r
+                mFileList.listDirectory();\r
+            }\r
+            \r
+        } else {\r
+            if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {\r
+                Toast msg = Toast.makeText(this, R.string.rename_local_fail_msg, Toast.LENGTH_LONG); \r
+                msg.show();\r
+                // TODO throw again the new rename dialog\r
+            } else {\r
+                Toast msg = Toast.makeText(this, R.string.rename_server_fail_msg, Toast.LENGTH_LONG); \r
+                msg.show();\r
+                if (result.isSslRecoverableException()) {\r
+                    mLastSslUntrustedServerResult = result;\r
+                    showDialog(DIALOG_SSL_VALIDATOR); \r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+\r
+    private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {\r
+        dismissDialog(DIALOG_SHORT_WAIT);\r
+        OCFile syncedFile = operation.getLocalFile();\r
+        if (!result.isSuccess()) {\r
+            if (result.getCode() == ResultCode.SYNC_CONFLICT) {\r
+                Intent i = new Intent(this, ConflictsResolveActivity.class);\r
+                i.putExtra(ConflictsResolveActivity.EXTRA_FILE, syncedFile);\r
+                i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));\r
+                startActivity(i);\r
+                \r
+            } else {\r
+                Toast msg = Toast.makeText(this, R.string.sync_file_fail_msg, Toast.LENGTH_LONG); \r
+                msg.show();\r
+            }\r
+            \r
+        } else {\r
+            if (operation.transferWasRequested()) {\r
+                mFileList.listDirectory();\r
+                onTransferStateChanged(syncedFile, true, true);\r
+                \r
+            } else {\r
+                Toast msg = Toast.makeText(this, R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); \r
+                msg.show();\r
+            }\r
+        }\r
+    }\r
+\r
+\r
+    /**\r
+     * {@inheritDoc}\r
+     */\r
+    @Override\r
+    public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {\r
+        /*OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
+        if (fileListFragment != null) { \r
+            fileListFragment.listDirectory();\r
+        }*/\r
+        if (mDualPane) {\r
+            FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
+            if (details != null && file.equals(details.getDisplayedFile()) ) {\r
+                if (downloading || uploading) {\r
+                    details.updateFileDetails(file, AccountUtils.getCurrentOwnCloudAccount(this));\r
+                } else {\r
+                    details.updateFileDetails(downloading || uploading);\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+\r
+    \r
+\r
+\r
 }\r
index 7382d79..a75d2c2 100644 (file)
@@ -118,7 +118,7 @@ public class UploadFilesActivity extends SherlockFragmentActivity implements
                 break;
             }
             default:
-                retval = false;
+                retval = onOptionsItemSelected(item);
         }
         return retval;
     }
index 8717289..503dfff 100644 (file)
@@ -121,7 +121,6 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                 fileIcon.setImageResource(R.drawable.ic_menu_archive);\r
             }\r
             ImageView localStateView = (ImageView) view.findViewById(R.id.imageView2);\r
-            //if (FileDownloader.isDownloading(mAccount, file.getRemotePath())) {\r
             FileDownloaderBinder downloaderBinder = mTransferServiceGetter.getFileDownloaderBinder();\r
             FileUploaderBinder uploaderBinder = mTransferServiceGetter.getFileUploaderBinder();\r
             if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)) {\r
index 8ee6af6..41d65d4 100644 (file)
 
 package com.owncloud.android.ui.dialog;
 
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.View.OnClickListener;
 import android.view.WindowManager.LayoutParams;
-import android.widget.Button;
 import android.widget.TextView;
 
 import com.actionbarsherlock.app.SherlockDialogFragment;
@@ -33,50 +33,93 @@ import com.owncloud.android.R;
 
 
 /**
- * Dialog to request the user about a certificate that could not be validated with the certificates store in the system.
+ * Dialog to request the user to input a name, optionally initialized with a former name.
  * 
  * @author Bartek Przybylski
+ * @author David A. Velasco
  */
-public class EditNameDialog extends SherlockDialogFragment implements OnClickListener {
+public class EditNameDialog extends SherlockDialogFragment implements DialogInterface.OnClickListener {
 
+    public static final String TAG = EditNameDialog.class.getSimpleName();
+    
+    protected static final String ARG_TITLE = "title";
+    protected static final String ARG_NAME = "name";
+    
     private String mNewFilename;
     private boolean mResult;
     private EditNameDialogListener mListener;
     
-    static public EditNameDialog newInstance(String filename) {
+    /**
+     * Public factory method to get dialog instances.
+     * 
+     * @param title         Text to show as title in the dialog.
+     * @param name          Optional text to include in the text input field when the dialog is shown.
+     * @param listener      Instance to notify when the dialog is dismissed.
+     * @return              New dialog instance, ready to show.
+     */
+    static public EditNameDialog newInstance(String title, String name, EditNameDialogListener listener) {
         EditNameDialog f = new EditNameDialog();
         Bundle args = new Bundle();
-        args.putString("filename", filename);
+        args.putString(ARG_TITLE, title);
+        args.putString(ARG_NAME, name);
         f.setArguments(args);
+        f.setOnDismissListener(listener);
         return f;
     }
     
+    
+    /**
+     * {@inheritDoc}
+     */
     @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-        View v = inflater.inflate(R.layout.edit_box_dialog, container, false);
-
-        String currentName = getArguments().getString("filename");
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        String currentName = getArguments().getString(ARG_NAME);
         if (currentName == null)
             currentName = "";
+        String title = getArguments().getString(ARG_TITLE);
         
-        ((Button)v.findViewById(R.id.cancel)).setOnClickListener(this);
-        ((Button)v.findViewById(R.id.ok)).setOnClickListener(this);
-        ((TextView)v.findViewById(R.id.user_input)).setText(currentName);
-        ((TextView)v.findViewById(R.id.user_input)).requestFocus();
-        getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+        // Inflate the layout for the dialog
+        LayoutInflater inflater = getSherlockActivity().getLayoutInflater();
+        View v = inflater.inflate(R.layout.edit_box_dialog, null);  // null parent view because it will go in the dialog layout
+        TextView inputText = ((TextView)v.findViewById(R.id.user_input));
+        inputText.setText(currentName);
+        
+        // Set it to the dialog 
+        AlertDialog.Builder builder = new AlertDialog.Builder(getSherlockActivity());
+        builder.setView(v)
+               .setPositiveButton(R.string.common_ok, this)
+               .setNegativeButton(R.string.common_cancel, this);
 
+        if (title != null) {
+            builder.setTitle(title);
+        }
+        
         mResult = false;
-        return v;
-    }
+        
+        Dialog d = builder.create();
+
+        inputText.requestFocus();
+        d.getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+        return d;
+    }    
+
     
+    /**
+     * Performs the corresponding action when a dialog button is clicked.
+     * 
+     * Saves the text in the input field to be accessed through {@link #getNewFilename()} when the positive
+     * button is clicked.
+     * 
+     * Notify the current listener in any case.
+     */
     @Override
-    public void onClick(View view) {
-        switch (view.getId()) {
-            case R.id.ok: {
-                mNewFilename = ((TextView)getView().findViewById(R.id.user_input)).getText().toString();
+    public void onClick(DialogInterface dialog, int which) {
+        switch (which) {
+            case AlertDialog.BUTTON_POSITIVE: {
+                mNewFilename = ((TextView)(getDialog().findViewById(R.id.user_input))).getText().toString();
                 mResult = true;
             }
-            case R.id.cancel: { // fallthought
+            case AlertDialog.BUTTON_NEGATIVE: { // fall through
                 dismiss();
                 if (mListener != null)
                     mListener.onDismiss(this);
@@ -84,23 +127,35 @@ public class EditNameDialog extends SherlockDialogFragment implements OnClickLis
         }
     }
     
-    public void setOnDismissListener(EditNameDialogListener listener) {
+    protected void setOnDismissListener(EditNameDialogListener listener) {
         mListener = listener;
     }
     
+    /**
+     * Returns the text in the input field after the user clicked the positive button.
+     * 
+     * @return      Text in the input field.
+     */
     public String getNewFilename() {
         return mNewFilename;
     }
     
-    // true if user clicked ok
+    /**
+     * 
+     * @return      True when the user clicked the positive button.
+     */
     public boolean getResult() {
         return mResult;
     }
 
     
+    /**
+     * Interface to receive a notification when any button in the dialog is clicked.
+     */
     public interface EditNameDialogListener {
         public void onDismiss(EditNameDialog dialog);
     }
-    
+
+
 }
 
index 9338b93..47e75d3 100644 (file)
@@ -191,7 +191,7 @@ public class FileDetailFragment extends SherlockFragment implements
             mPreview = (ImageView)mView.findViewById(R.id.fdPreview);\r
         }\r
         \r
-        updateFileDetails();\r
+        updateFileDetails(false);\r
         return view;\r
     }\r
     \r
@@ -274,7 +274,6 @@ public class FileDetailFragment extends SherlockFragment implements
     public void onClick(View v) {\r
         switch (v.getId()) {\r
             case R.id.fdDownloadBtn: {\r
-                //if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath())) {\r
                 FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();\r
                 FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();\r
                 if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {\r
@@ -342,8 +341,7 @@ public class FileDetailFragment extends SherlockFragment implements
                 break;\r
             }\r
             case R.id.fdRenameBtn: {\r
-                EditNameDialog dialog = EditNameDialog.newInstance(mFile.getFileName());\r
-                dialog.setOnDismissListener(this);\r
+                EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), mFile.getFileName(), this);\r
                 dialog.show(getFragmentManager(), "nameeditdialog");\r
                 break;\r
             }   \r
@@ -374,8 +372,13 @@ public class FileDetailFragment extends SherlockFragment implements
                     try {\r
                         Intent i = new Intent(Intent.ACTION_VIEW);\r
                         mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));\r
-                        if (mimeType != null && !mimeType.equals(mFile.getMimetype())) {\r
-                            i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);\r
+                        if (mimeType == null || !mimeType.equals(mFile.getMimetype())) {\r
+                            if (mimeType != null) {\r
+                                i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);\r
+                            } else {\r
+                                // desperate try\r
+                                i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*/*");\r
+                            }\r
                             i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
                             startActivity(i);\r
                             toastIt = false;\r
@@ -475,14 +478,21 @@ public class FileDetailFragment extends SherlockFragment implements
             mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());\r
         }\r
         mAccount = ocAccount;\r
-        updateFileDetails();\r
+        updateFileDetails(false);\r
     }\r
     \r
 \r
     /**\r
      * Updates the view with all relevant details about that file.\r
+     *\r
+     * TODO Remove parameter when the transferring state of files is kept in database. \r
+     * \r
+     * @param transferring      Flag signaling if the file should be considered as downloading or uploading, \r
+     *                          although {@link FileDownloaderBinder#isDownloading(Account, OCFile)}  and \r
+     *                          {@link FileUploaderBinder#isUploading(Account, OCFile)} return false.\r
+     * \r
      */\r
-    public void updateFileDetails() {\r
+    public void updateFileDetails(boolean transferring) {\r
 \r
         if (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment) {\r
             \r
@@ -504,7 +514,7 @@ public class FileDetailFragment extends SherlockFragment implements
             //if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath()) || FileUploader.isUploading(mAccount, mFile.getRemotePath())) {\r
             FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();\r
             FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();\r
-            if ((downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) || (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile))) {\r
+            if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) || (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile))) {\r
                 setButtonsForTransferring();\r
                 \r
             } else if (mFile.isDown()) {\r
@@ -517,9 +527,11 @@ public class FileDetailFragment extends SherlockFragment implements
                 setButtonsForDown();\r
                 \r
             } else {\r
+                // TODO load default preview image; when the local file is removed, the preview remains there\r
                 setButtonsForRemote();\r
             }\r
         }\r
+        getView().invalidate();\r
     }\r
     \r
     \r
@@ -602,7 +614,6 @@ public class FileDetailFragment extends SherlockFragment implements
         if (!isEmpty()) {\r
             Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
             downloadButton.setText(R.string.filedetails_sync_file);\r
-            //downloadButton.setEnabled(true);\r
         \r
             ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(true);\r
             ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);\r
@@ -687,7 +698,7 @@ public class FileDetailFragment extends SherlockFragment implements
                     if (downloadWasFine) {\r
                         mFile = mStorageManager.getFileByPath(downloadedRemotePath);\r
                     }\r
-                    updateFileDetails();    // it updates the buttons; must be called although !downloadWasFine\r
+                    updateFileDetails(false);    // it updates the buttons; must be called although !downloadWasFine\r
                 }\r
             }\r
         }\r
@@ -707,7 +718,6 @@ public class FileDetailFragment extends SherlockFragment implements
     private class UploadFinishReceiver extends BroadcastReceiver {\r
         @Override\r
         public void onReceive(Context context, Intent intent) {\r
-            Log.d(TAG, "Received broacast! : " + intent.getStringExtra(FileUploader.EXTRA_REMOTE_PATH));\r
             String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);\r
 \r
             if (!isEmpty() && accountName.equals(mAccount.name)) {\r
@@ -724,7 +734,7 @@ public class FileDetailFragment extends SherlockFragment implements
                         Toast msg = Toast.makeText(getActivity().getApplicationContext(), String.format(getString(R.string.filedetails_renamed_in_upload_msg), newName), Toast.LENGTH_LONG);\r
                         msg.show();\r
                     }\r
-                    updateFileDetails();    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server\r
+                    updateFileDetails(false);    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server\r
                 }\r
             }\r
         }\r
@@ -840,6 +850,7 @@ public class FileDetailFragment extends SherlockFragment implements
             String newFilename = dialog.getNewFilename();\r
             Log.d(TAG, "name edit dialog dismissed with new name " + newFilename);\r
             mLastRemoteOperation = new RenameFileOperation( mFile, \r
+                                                            mAccount, \r
                                                             newFilename, \r
                                                             new FileDataStorageManager(mAccount, getActivity().getContentResolver()));\r
             WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());\r
index ec040b5..4074784 100644 (file)
  */
 package com.owncloud.android.ui.fragment;
 
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.owncloud.android.AccountUtils;
+import com.owncloud.android.R;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.network.OwnCloudClientUtils;
+import com.owncloud.android.operations.OnRemoteOperationListener;
+import com.owncloud.android.operations.RemoteOperation;
+import com.owncloud.android.operations.RemoveFileOperation;
+import com.owncloud.android.operations.RenameFileOperation;
+import com.owncloud.android.operations.SynchronizeFileOperation;
 import com.owncloud.android.ui.FragmentListView;
+import com.owncloud.android.ui.activity.FileDisplayActivity;
 import com.owncloud.android.ui.activity.TransferServiceGetter;
 import com.owncloud.android.ui.adapter.FileListListAdapter;
+import com.owncloud.android.ui.dialog.EditNameDialog;
+import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
+import com.owncloud.android.ui.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
+
+import eu.alefzero.webdav.WebdavClient;
+import eu.alefzero.webdav.WebdavUtils;
 
+import android.accounts.Account;
 import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
 import android.util.Log;
+import android.view.ContextMenu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
 import android.view.View;
+import android.webkit.MimeTypeMap;
 import android.widget.AdapterView;
+import android.widget.Toast;
+import android.widget.AdapterView.AdapterContextMenuInfo;
 
 /**
  * A Fragment that lists all files and folders in a given path.
@@ -35,7 +67,7 @@ import android.widget.AdapterView;
  * @author Bartek Przybylski
  * 
  */
-public class OCFileListFragment extends FragmentListView {
+public class OCFileListFragment extends FragmentListView implements EditNameDialogListener, ConfirmationDialogFragmentListener {
     private static final String TAG = "FileListFragment";
     private static final String SAVED_LIST_POSITION = "LIST_POSITION"; 
     
@@ -43,6 +75,9 @@ public class OCFileListFragment extends FragmentListView {
     
     private OCFile mFile = null;
     private FileListListAdapter mAdapter;
+    
+    private Handler mHandler;
+    private OCFile mTargetFile;
 
     
     /**
@@ -76,6 +111,11 @@ public class OCFileListFragment extends FragmentListView {
             setReferencePosition(position);
         }
         
+        registerForContextMenu(getListView());
+        getListView().setOnCreateContextMenuListener(this);        
+        
+        mHandler = new Handler();
+        
         Log.i(TAG, "onActivityCreated() stop");
     }
     
@@ -112,6 +152,197 @@ public class OCFileListFragment extends FragmentListView {
         }
         
     }
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onCreateContextMenu (ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+        super.onCreateContextMenu(menu, v, menuInfo);
+        MenuInflater inflater = getActivity().getMenuInflater();
+        inflater.inflate(R.menu.file_context_menu, menu);
+        AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
+        OCFile targetFile = (OCFile) mAdapter.getItem(info.position);
+        List<Integer> toHide = new ArrayList<Integer>();    
+        List<Integer> toDisable = new ArrayList<Integer>();  
+        
+        MenuItem item = null;
+        if (targetFile.isDirectory()) {
+            // contextual menu for folders
+            toHide.add(R.id.open_file_item);
+            toHide.add(R.id.download_file_item);
+            toHide.add(R.id.cancel_download_item);
+            toHide.add(R.id.cancel_upload_item);
+            if (    mContainerActivity.getFileDownloaderBinder().isDownloading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile) ||
+                    mContainerActivity.getFileUploaderBinder().isUploading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile)           ) {
+                toDisable.add(R.id.rename_file_item);
+                toDisable.add(R.id.remove_file_item);
+                
+            }
+            
+        } else {
+            // contextual menu for regular files
+            if (targetFile.isDown()) {
+                toHide.add(R.id.cancel_download_item);
+                toHide.add(R.id.cancel_upload_item);
+                item = menu.findItem(R.id.download_file_item);
+                if (item != null) {
+                    item.setTitle(R.string.filedetails_sync_file);
+                }
+            } else {
+                toHide.add(R.id.open_file_item);
+            }
+            if ( mContainerActivity.getFileDownloaderBinder().isDownloading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile)) {
+                toHide.add(R.id.download_file_item);
+                toHide.add(R.id.cancel_upload_item);
+                toDisable.add(R.id.open_file_item);
+                toDisable.add(R.id.rename_file_item);
+                toDisable.add(R.id.remove_file_item);
+                    
+            } else if ( mContainerActivity.getFileUploaderBinder().isUploading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile)) {
+                toHide.add(R.id.download_file_item);
+                toHide.add(R.id.cancel_download_item);
+                toDisable.add(R.id.open_file_item);
+                toDisable.add(R.id.rename_file_item);
+                toDisable.add(R.id.remove_file_item);
+                    
+            } else {
+                toHide.add(R.id.cancel_download_item);
+                toHide.add(R.id.cancel_upload_item);
+            }
+        }
+
+        for (int i : toHide) {
+            item = menu.findItem(i);
+            if (item != null) {
+                item.setVisible(false);
+                item.setEnabled(false);
+            }
+        }
+        
+        for (int i : toDisable) {
+            item = menu.findItem(i);
+            if (item != null) {
+                item.setEnabled(false);
+            }
+        }
+    }
+    
+    
+    /**
+     * {@inhericDoc}
+     */
+    @Override
+    public boolean onContextItemSelected (MenuItem item) {
+        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();        
+        mTargetFile = (OCFile) mAdapter.getItem(info.position);
+        switch (item.getItemId()) {
+            case R.id.rename_file_item: {
+                EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), mTargetFile.getFileName(), this);
+                dialog.show(getFragmentManager(), EditNameDialog.TAG);
+                return true;
+            }
+            case R.id.remove_file_item: {
+                int messageStringId = R.string.confirmation_remove_alert;
+                int posBtnStringId = R.string.confirmation_remove_remote;
+                int neuBtnStringId = -1;
+                if (mTargetFile.isDirectory()) {
+                    messageStringId = R.string.confirmation_remove_folder_alert;
+                    posBtnStringId = R.string.confirmation_remove_remote_and_local;
+                    neuBtnStringId = R.string.confirmation_remove_folder_local;
+                } else if (mTargetFile.isDown()) {
+                    posBtnStringId = R.string.confirmation_remove_remote_and_local;
+                    neuBtnStringId = R.string.confirmation_remove_local;
+                }
+                ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
+                        messageStringId,
+                        new String[]{mTargetFile.getFileName()},
+                        posBtnStringId,
+                        neuBtnStringId,
+                        R.string.common_cancel);
+                confDialog.setOnConfirmationListener(this);
+                confDialog.show(getFragmentManager(), FileDetailFragment.FTAG_CONFIRMATION);
+                return true;
+            }
+            case R.id.open_file_item: {
+                String storagePath = mTargetFile.getStoragePath();
+                String encodedStoragePath = WebdavUtils.encodePath(storagePath);
+                try {
+                    Intent i = new Intent(Intent.ACTION_VIEW);
+                    i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mTargetFile.getMimetype());
+                    i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                    startActivity(i);
+                    
+                } catch (Throwable t) {
+                    Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mTargetFile.getMimetype());
+                    boolean toastIt = true; 
+                    String mimeType = "";
+                    try {
+                        Intent i = new Intent(Intent.ACTION_VIEW);
+                        mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
+                        if (mimeType == null || !mimeType.equals(mTargetFile.getMimetype())) {
+                            if (mimeType != null) {
+                                i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);
+                            } else {
+                                // desperate try
+                                i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*/*");
+                            }
+                            i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                            startActivity(i);
+                            toastIt = false;
+                        }
+                        
+                    } catch (IndexOutOfBoundsException e) {
+                        Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
+                        
+                    } catch (ActivityNotFoundException e) {
+                        Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
+                        
+                    } catch (Throwable th) {
+                        Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);
+                        
+                    } finally {
+                        if (toastIt) {
+                            Toast.makeText(getActivity(), "There is no application to handle file " + mTargetFile.getFileName(), Toast.LENGTH_SHORT).show();
+                        }
+                    }
+                    
+                }
+                return true;
+            }
+            case R.id.download_file_item: {
+                Account account = AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity());
+                RemoteOperation operation = new SynchronizeFileOperation(mTargetFile, null, mContainerActivity.getStorageManager(), account, true, false, getSherlockActivity());
+                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getSherlockActivity().getApplicationContext());
+                operation.execute(wc, mContainerActivity, mHandler);
+                getSherlockActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT);
+                return true;
+            }
+            case R.id.cancel_download_item: {
+                FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
+                Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());
+                if (downloaderBinder != null && downloaderBinder.isDownloading(account, mTargetFile)) {
+                    downloaderBinder.cancel(account, mTargetFile);
+                    listDirectory();
+                    mContainerActivity.onTransferStateChanged(mTargetFile, false, false);
+                }
+                return true;
+            }
+            case R.id.cancel_upload_item: {
+                FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
+                Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());
+                if (uploaderBinder != null && uploaderBinder.isUploading(account, mTargetFile)) {
+                    uploaderBinder.cancel(account, mTargetFile);
+                    listDirectory();
+                    mContainerActivity.onTransferStateChanged(mTargetFile, false, false);
+                }
+                return true;
+            }
+            default:
+                return super.onContextItemSelected(item); 
+        }
+    }
+    
 
     /**
      * Call this, when the user presses the up button
@@ -186,7 +417,7 @@ public class OCFileListFragment extends FragmentListView {
      * 
      * @author David A. Velasco
      */
-    public interface ContainerActivity extends TransferServiceGetter {
+    public interface ContainerActivity extends TransferServiceGetter, OnRemoteOperationListener {
 
         /**
          * Callback method invoked when a directory is clicked by the user on the files list
@@ -216,6 +447,77 @@ public class OCFileListFragment extends FragmentListView {
         public OCFile getInitialDirectory();
         
         
+        /**
+         * Callback method invoked when a the 'transfer state' of a file changes.
+         * 
+         * This happens when a download or upload is started or ended for a file.
+         * 
+         * This method is necessary by now to update the user interface of the double-pane layout in tablets
+         * because methods {@link FileDownloaderBinder#isDownloading(Account, OCFile)} and {@link FileUploaderBinder#isUploading(Account, OCFile)}
+         * won't provide the needed response before the method where this is called finishes. 
+         * 
+         * TODO Remove this when the transfer state of a file is kept in the database (other thing TODO)
+         * 
+         * @param file          OCFile which state changed.
+         * @param downloading   Flag signaling if the file is now downloading.
+         * @param uploading     Flag signaling if the file is now uploading.
+         */
+        public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading);
+        
     }
+    
+    
+    @Override
+    public void onDismiss(EditNameDialog dialog) {
+        if (dialog.getResult()) {
+            String newFilename = dialog.getNewFilename();
+            Log.d(TAG, "name edit dialog dismissed with new name " + newFilename);
+            RemoteOperation operation = new RenameFileOperation(mTargetFile, 
+                                                                AccountUtils.getCurrentOwnCloudAccount(getActivity()), 
+                                                                newFilename, 
+                                                                mContainerActivity.getStorageManager());
+            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity().getApplicationContext());
+            operation.execute(wc, mContainerActivity, mHandler);
+            getActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT);
+        }
+    }
+
+    
+    @Override
+    public void onConfirmation(String callerTag) {
+        if (callerTag.equals(FileDetailFragment.FTAG_CONFIRMATION)) {
+            if (mContainerActivity.getStorageManager().getFileById(mTargetFile.getFileId()) != null) {
+                RemoteOperation operation = new RemoveFileOperation( mTargetFile, 
+                                                                    true, 
+                                                                    mContainerActivity.getStorageManager());
+                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity().getApplicationContext());
+                operation.execute(wc, mContainerActivity, mHandler);
+                
+                getActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT);
+            }
+        }
+    }
+    
+    @Override
+    public void onNeutral(String callerTag) {
+        File f = null;
+        if (mTargetFile.isDirectory()) {
+            // TODO run in a secondary thread?
+            mContainerActivity.getStorageManager().removeDirectory(mTargetFile, false, true);
+            
+        } else if (mTargetFile.isDown() && (f = new File(mTargetFile.getStoragePath())).exists()) {
+            f.delete();
+            mTargetFile.setStoragePath(null);
+            mContainerActivity.getStorageManager().saveFile(mTargetFile);
+        }
+        listDirectory();
+        mContainerActivity.onTransferStateChanged(mTargetFile, false, false);
+    }
+    
+    @Override
+    public void onCancel(String callerTag) {
+        Log.d(TAG, "REMOVAL CANCELED");
+    }
+
 
 }