Merge remote-tracking branch 'remotes/upstream/master' into switchListVsGridMaster
authortobiasKaminsky <tobias@kaminsky.me>
Thu, 29 Oct 2015 16:55:13 +0000 (17:55 +0100)
committertobiasKaminsky <tobias@kaminsky.me>
Thu, 29 Oct 2015 16:55:13 +0000 (17:55 +0100)
1  2 
res/menu/file_actions_menu.xml
res/values/strings.xml
src/com/owncloud/android/datamodel/OCFile.java
src/com/owncloud/android/files/FileMenuFilter.java
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/adapter/FileListListAdapter.java
src/com/owncloud/android/ui/fragment/ExtendedListFragment.java
src/com/owncloud/android/ui/fragment/OCFileListFragment.java
src/com/owncloud/android/utils/DisplayUtils.java

@@@ -1,5 -1,4 +1,5 @@@
 -<?xml version="1.0" encoding="utf-8"?><!--
 +<?xml version="1.0" encoding="utf-8"?>
 +<!--
    ownCloud Android client application
  
    Copyright (C) 2012  Bartek Przybylski
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  -->
- <menu         xmlns:android="http://schemas.android.com/apk/res/android">
+ <menu xmlns:android="http://schemas.android.com/apk/res/android">
  
-       <item   android:id="@+id/action_share_file"                             android:title="@string/action_share_file"                       android:icon="@android:drawable/ic_menu_share"                                  android:orderInCategory="1" />
-       <item   android:id="@+id/action_unshare_file"               android:title="@string/action_unshare_file"                 android:icon="@android:drawable/ic_menu_share"                                  android:orderInCategory="1" />
-     <item     android:id="@+id/action_open_file_with"                 android:title="@string/actionbar_open_with"                     android:icon="@android:drawable/ic_menu_set_as"                                 android:orderInCategory="1" /> 
-       <item   android:id="@+id/action_download_file"                  android:title="@string/filedetails_download"            android:icon="@drawable/ic_action_download"                                             android:orderInCategory="1" />
-     <item     android:id="@+id/action_sync_file"                              android:title="@string/filedetails_sync_file"           android:icon="@drawable/ic_action_refresh"                                              android:orderInCategory="1" />
-       <item   android:id="@+id/action_cancel_download"                android:title="@string/common_cancel_download"          android:icon="@android:drawable/ic_menu_close_clear_cancel"             android:orderInCategory="1" />
-       <item   android:id="@+id/action_cancel_upload"                  android:title="@string/common_cancel_upload"            android:icon="@android:drawable/ic_menu_close_clear_cancel"             android:orderInCategory="1" />
-       <item   android:id="@+id/action_rename_file"                    android:title="@string/common_rename"                           android:icon="@android:drawable/ic_menu_edit"                                   android:orderInCategory="1" />
-     <item     android:id="@+id/action_move"                                   android:title="@string/actionbar_move"                          android:icon="@android:drawable/ic_menu_set_as"                                 android:orderInCategory="1" />
-     <item     android:id="@+id/action_remove_file"                    android:title="@string/common_remove"                           android:icon="@android:drawable/ic_menu_delete"                                 android:orderInCategory="1" />
-     <item     android:id="@+id/action_send_file"                              android:title="@string/actionbar_send_file"                     android:icon="@android:drawable/ic_menu_set_as"                                 android:orderInCategory="1" />
-     <item     android:id="@+id/action_favorite_file"                  android:title="@string/favorite"                        android:icon="@android:drawable/ic_menu_set_as"                                 android:orderInCategory="1" />
-     <item     android:id="@+id/action_unfavorite_file"                android:title="@string/unfavorite"                          android:icon="@android:drawable/ic_menu_set_as"                                     android:orderInCategory="1" />
-     <item     android:id="@+id/action_see_details"                    android:title="@string/actionbar_see_details"           android:icon="@android:drawable/ic_menu_info_details"                   android:orderInCategory="1" />
+     <item
+         android:id="@+id/action_share_file"
+         android:title="@string/action_share_file"
+         android:icon="@android:drawable/ic_menu_share"
+         android:orderInCategory="1" />
+     <item
+         android:id="@+id/action_unshare_file"
+         android:title="@string/action_unshare_file"
+         android:icon="@android:drawable/ic_menu_share"
+         android:orderInCategory="1" />
+     <item
+         android:id="@+id/action_open_file_with"
+         android:title="@string/actionbar_open_with"
+         android:icon="@android:drawable/ic_menu_set_as"
+         android:orderInCategory="1" />
+     <item
+         android:id="@+id/action_download_file"
+         android:title="@string/filedetails_download"
+         android:icon="@drawable/ic_action_download"
+         android:orderInCategory="1" />
+     <item
+         android:id="@+id/action_sync_file"
+         android:title="@string/filedetails_sync_file"
+         android:icon="@drawable/ic_action_refresh"
+         android:orderInCategory="1" />
+     <item
+         android:id="@+id/action_cancel_download"
+         android:title="@string/common_cancel_download"
+         android:icon="@android:drawable/ic_menu_close_clear_cancel"
+         android:orderInCategory="1" />
+     <item
+         android:id="@+id/action_cancel_upload"
+         android:title="@string/common_cancel_upload"
+         android:icon="@android:drawable/ic_menu_close_clear_cancel"
+         android:orderInCategory="1" />
+     <item
+         android:id="@+id/action_rename_file"
+         android:title="@string/common_rename"
+         android:icon="@android:drawable/ic_menu_edit"
+         android:orderInCategory="1" />
+     <item
+         android:id="@+id/action_move"
+         android:title="@string/actionbar_move"
+         android:icon="@android:drawable/ic_menu_set_as"
+         android:orderInCategory="1" />
+     <item
+         android:id="@+id/action_copy"
+         android:title="@android:string/copy"
+         android:icon="@android:drawable/ic_menu_set_as"
+         android:orderInCategory="1" />
+     <item
+         android:id="@+id/action_remove_file"
+         android:title="@string/common_remove"
+         android:icon="@android:drawable/ic_menu_delete"
+         android:orderInCategory="1" />
+     <item
+         android:id="@+id/action_send_file"
+         android:title="@string/actionbar_send_file"
+         android:icon="@android:drawable/ic_menu_set_as"
+         android:orderInCategory="1" />
+     <item
+         android:id="@+id/action_favorite_file"
+         android:title="@string/favorite"
+         android:icon="@android:drawable/ic_menu_set_as"
+         android:orderInCategory="1" />
+     <item
+         android:id="@+id/action_unfavorite_file"
+         android:title="@string/unfavorite"
+         android:icon="@android:drawable/ic_menu_set_as"
+         android:orderInCategory="1" />
+     <item
+         android:id="@+id/action_see_details"
+         android:title="@string/actionbar_see_details"
+         android:icon="@android:drawable/ic_menu_info_details"
+         android:orderInCategory="1" />
  
  </menu>
diff --combined res/values/strings.xml
@@@ -74,6 -74,7 +74,7 @@@
      <string name="file_list_seconds_ago">seconds ago</string>
      <string name="file_list_empty">Nothing in here. Upload something!</string>
      <string name="file_list_loading">Loading&#8230;</string>
+     <string name="file_list_no_app_for_file_type">No App found for file type!</string>
      <string name="local_file_list_empty">There are no files in this folder.</string>
      <string name="filedetails_select_file">Tap on a file to display additional information.</string>
      <string name="filedetails_size">Size:</string>
      <string name="sync_fail_ticker_unauthorized">Synchronization failed, you need to relogin</string>
      <string name="sync_fail_content">Synchronization of %1$s could not be completed</string>
      <string name="sync_fail_content_unauthorized">Invalid password for %1$s</string>
-       <string name="sync_conflicts_in_favourites_ticker">Conflicts found</string>
-       <string name="sync_conflicts_in_favourites_content">%1$d kept-in-sync files could not be sync\'ed</string>
+     <string name="sync_conflicts_in_favourites_ticker">Conflicts found</string>
+     <string name="sync_conflicts_in_favourites_content">%1$d kept-in-sync files could not be sync\'ed</string>
      <string name="sync_fail_in_favourites_ticker">Kept-in-sync files failed</string>
      <string name="sync_fail_in_favourites_content">Contents of %1$d files could not be sync\'ed (%2$d conflicts)</string>
      <string name="sync_foreign_files_forgotten_ticker">Some local files were forgotten</string>
      <string name="sync_foreign_files_forgotten_content">%1$d files out of the %2$s folder could not be copied into</string>
      <string name="sync_foreign_files_forgotten_explanation">As of version 1.3.16, files uploaded from this device are copied into the local %1$s folder to prevent data loss when a single file is synced with multiple accounts.\n\nDue to this change, all files uploaded in previous versions of this app were copied into the %2$s folder. However, an error prevented the completion of this operation during account synchronization. You may either leave the file(s) as is and remove the link to %3$s, or move the file(s) into the %1$s folder and retain the link to %4$s.\n\nListed below are the local file(s), and the remote file(s) in %5$s they were linked to.</string>
-       <string name="sync_current_folder_was_removed">Folder %1$s does not exist anymore</string>    
+     <string name="sync_current_folder_was_removed">Folder %1$s does not exist anymore</string>
      <string name="foreign_files_move">"Move all"</string>
      <string name="foreign_files_success">"All files were moved"</string>
      <string name="foreign_files_fail">"Some files could not be moved"</string>
      <string name="media_state_loading">"%1$s (loading)"</string>
      <string name="media_event_done">"%1$s playback finished"</string>
      <string name="media_err_nothing_to_play">No media file found</string>
-       <string name="media_err_no_account">No account provided</string>
-       <string name="media_err_not_in_owncloud">File not in a valid account</string>
-       <string name="media_err_unsupported">Unsupported media codec</string>
-       <string name="media_err_io">Media file could not be read</string>
-       <string name="media_err_malformed">Media file not correctly encoded</string>
-       <string name="media_err_timeout">Timed out while trying to play</string>
-       <string name="media_err_invalid_progressive_playback">Media file cannot be streamed</string>
-       <string name="media_err_unknown">Media file cannot be played with the stock media player</string>
-       <string name="media_err_security_ex">Security error trying to play %1$s</string>
-       <string name="media_err_io_ex">Input error trying to play %1$s</string>
-       <string name="media_err_unexpected">Unexpected error trying to play %1$s</string>
-       <string name="media_rewind_description">Rewind button</string>
-       <string name="media_play_pause_description">Play or pause button</string>
-       <string name="media_forward_description">Fast forward button</string>
+     <string name="media_err_no_account">No account provided</string>
+     <string name="media_err_not_in_owncloud">File not in a valid account</string>
+     <string name="media_err_unsupported">Unsupported media codec</string>
+     <string name="media_err_io">Media file could not be read</string>
+     <string name="media_err_malformed">Media file not correctly encoded</string>
+     <string name="media_err_timeout">Timed out while trying to play</string>
+     <string name="media_err_invalid_progressive_playback">Media file cannot be streamed</string>
+     <string name="media_err_unknown">Media file cannot be played with the stock media player</string>
+     <string name="media_err_security_ex">Security error trying to play %1$s</string>
+     <string name="media_err_io_ex">Input error trying to play %1$s</string>
+     <string name="media_err_unexpected">Unexpected error trying to play %1$s</string>
+     <string name="media_rewind_description">Rewind button</string>
+     <string name="media_play_pause_description">Play or pause button</string>
+     <string name="media_forward_description">Fast forward button</string>
  
        <string name="auth_getting_authorization">Getting authorization&#8230;</string>
        <string name="auth_trying_to_login">Trying to login&#8230;</string>
      <string name="ssl_validator_label_L">Location:</string>
      <string name="ssl_validator_label_validity">Validity:</string>
      <string name="ssl_validator_label_validity_from">From:</string>
-       <string name="ssl_validator_label_validity_to">To:</string>
-       <string name="ssl_validator_label_signature">Signature:</string>
-       <string name="ssl_validator_label_signature_algorithm">Algorithm:</string>
-       <string name="ssl_validator_null_cert">The certificate could not be shown.</string>
-       <string name="ssl_validator_no_info_about_error">- No information about the error</string>
-                       
+     <string name="ssl_validator_label_validity_to">To:</string>
+     <string name="ssl_validator_label_signature">Signature:</string>
+     <string name="ssl_validator_label_signature_algorithm">Algorithm:</string>
+     <string name="ssl_validator_null_cert">The certificate could not be shown.</string>
+     <string name="ssl_validator_no_info_about_error">- No information about the error</string>
      <string name="placeholder_sentence">This is a placeholder</string>
      <string name="placeholder_filename">placeholder.txt</string>
      <string name="placeholder_filetype">PNG Image</string>
      <string name="placeholder_filesize">389 KB</string>
      <string name="placeholder_timestamp">2012/05/18 12:23 PM</string>
      <string name="placeholder_media_time">12:23:45</string>
-     
      <string name="instant_upload_on_wifi">Upload pictures via WiFi only</string>
      <string name="instant_video_upload_on_wifi">Upload videos via WiFi only</string>
      <string name="instant_upload_path">/InstantUpload</string>
      
      <string name="preview_image_description">Image preview</string>
      <string name="preview_image_error_unknown_format">This image cannot be shown</string>
-     
      <string name="error__upload__local_file_not_copied">%1$s could not be copied to %2$s local folder</string>
      <string name="prefs_instant_upload_path_title">Upload Path</string>
  
      <string name="share_link_password_title">Enter a password</string>
      <string name="share_link_empty_password">You must enter a password</string>
  
-       <string name="activity_chooser_send_file_title">Send</string>
+     <string name="activity_chooser_send_file_title">Send</string>
+     <string name="copy_link">Copy link</string>
+     <string name="clipboard_text_copied">Copied to clipboard</string>
  
-       <string name="copy_link">Copy link</string>
-       <string name="clipboard_text_copied">Copied to clipboard</string>
+     <string name="error_cant_bind_to_operations_service">Critical error: cannot perform operations</string>
  
-       <string name="error_cant_bind_to_operations_service">Critical error: cannot perform operations</string>
-       
-       <string name="network_error_socket_exception">An error occurred while connecting with the server.</string>
-       <string name="network_error_socket_timeout_exception">An error occurred while waiting for the server, the operation couldn\'t have been done</string>
-       <string name="network_error_connect_timeout_exception">An error occurred while waiting for the server, the operation couldn\'t have been done</string>
-       <string name="network_host_not_available">The operation couldn\'t be completed, server is unavailable</string>
+     <string name="network_error_socket_exception">An error occurred while connecting with the server.</string>
+     <string name="network_error_socket_timeout_exception">An error occurred while waiting for the server, the operation couldn\'t have been done</string>
+     <string name="network_error_connect_timeout_exception">An error occurred while waiting for the server, the operation couldn\'t have been done</string>
+     <string name="network_host_not_available">The operation couldn\'t be completed, server is unavailable</string>
+     <string name="empty" />
  
-       <string name="empty" />
-       
-       <string name="forbidden_permissions">You do not have permission %s</string>
-       <string name="forbidden_permissions_rename">to rename this file</string>
-       <string name="forbidden_permissions_delete">to delete this file</string>
-       <string name="share_link_forbidden_permissions">to share this file</string>
-       <string name="unshare_link_forbidden_permissions">to unshare this file</string>
-       <string name="forbidden_permissions_create">to create the file</string>
-       <string name="uploader_upload_forbidden_permissions">to upload in this folder</string>
-       <string name="downloader_download_file_not_found">The file is no longer available on the server</string>
+     <string name="forbidden_permissions">You do not have permission %s</string>
+     <string name="forbidden_permissions_rename">to rename this file</string>
+     <string name="forbidden_permissions_delete">to delete this file</string>
+     <string name="share_link_forbidden_permissions">to share this file</string>
+     <string name="unshare_link_forbidden_permissions">to unshare this file</string>
+     <string name="forbidden_permissions_create">to create the file</string>
+     <string name="uploader_upload_forbidden_permissions">to upload in this folder</string>
+     <string name="downloader_download_file_not_found">The file is no longer available on the server</string>
  
-       <string name="prefs_category_accounts">Accounts</string>
-       <string name="prefs_add_account">Add account</string>
-       <string name="auth_redirect_non_secure_connection_title">Secure connection is redirected to an unsecured route.</string>
+     <string name="prefs_category_accounts">Accounts</string>
+     <string name="prefs_add_account">Add account</string>
+     <string name="auth_redirect_non_secure_connection_title">Secure connection is redirected through an unsecured route.</string>
  
        <string name="actionbar_logger">Logs</string>
        <string name="log_send_history_button">Send History</string>
        <string name="file_list_empty_moving">Nothing in here. You can add a folder!</string>
        <string name="folder_picker_choose_button_text">Choose</string>
  
-       <string name="move_file_not_found">Unable to move. Please check whether the file exists</string>
-       <string name="move_file_invalid_into_descendent">It is not possible to move a folder into a descendant</string>
-       <string name="move_file_invalid_overwrite">The file exists already in the destination folder</string>
-       <string name="move_file_error">An error occurred while trying to move this file or folder</string>
-       <string name="forbidden_permissions_move">to move this file</string>
+     <string name="move_file_not_found">Unable to move. Please check whether the file exists</string>
+     <string name="move_file_invalid_into_descendent">It is not possible to move a folder into a descendant</string>
+     <string name="move_file_invalid_overwrite">The file exists already in the destination folder</string>
+     <string name="move_file_error">An error occurred while trying to move this file or folder</string>
+     <string name="forbidden_permissions_move">to move this file</string>
+     <string name="copy_file_not_found">Unable to copy. Please check whether the file exists</string>
+     <string name="copy_file_invalid_into_descendent">It is not possible to copy a folder into a descendant</string>
+     <string name="copy_file_invalid_overwrite">The file exists already in the destination folder</string>
+     <string name="copy_file_error">An error occurred while trying to copy this file or folder</string>
+     <string name="forbidden_permissions_copy">to copy this file</string>
  
-       <string name="prefs_category_instant_uploading">Instant Uploads</string>
+     <string name="prefs_category_instant_uploading">Instant Uploads</string>
        <string name="prefs_category_security">Security</string>
  
        <string name="prefs_instant_video_upload_path_title">Upload Video Path</string>
      <string name="file_list__footer__files">%1$d files</string>
      <string name="file_list__footer__files_and_folder">%1$d files, 1 folder</string>
      <string name="file_list__footer__files_and_folders">%1$d files, %2$d folders</string>
 -
 +    <string name="action_switch_grid_view">Switch to grid view</string>
 +    <string name="action_switch_list_view">Switch to list view</string>
  </resources>
@@@ -22,12 -22,11 +22,12 @@@ package com.owncloud.android.datamodel
  
  import android.os.Parcel;
  import android.os.Parcelable;
+ import android.webkit.MimeTypeMap;
  
  import com.owncloud.android.lib.common.utils.Log_OC;
- import com.owncloud.android.utils.FileStorageUtils;
  
  import java.io.File;
 +import java.util.Enumeration;
  
  import third_parties.daveKoeller.AlphanumComparator;
  public class OCFile implements Parcelable, Comparable<OCFile> {
@@@ -75,8 -74,6 +75,8 @@@
  
      private boolean mIsDownloading;
  
 +    private boolean mShowGridView;
 +
  
      /**
       * Create new {@link OCFile} with given path.
      /**
       * Sets the name of the file
       * <p/>
-      * Does nothing if the new name is null, empty or includes "/" ; or if the file is the root directory
+      * 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_OC.d(TAG, "OCFile name changin from " + mRemotePath);
-         if (name != null && name.length() > 0 && !name.contains(PATH_SEPARATOR) && !mRemotePath.equals(ROOT_PATH)) {
+         if (name != null && name.length() > 0 && !name.contains(PATH_SEPARATOR) &&
+                 !mRemotePath.equals(ROOT_PATH)) {
              String parent = (new File(getRemotePath())).getParent();
              parent = (parent.endsWith(PATH_SEPARATOR)) ? parent : parent + PATH_SEPARATOR;
              mRemotePath = parent + name;
  
      @Override
      public int describeContents() {
-         return ((Object) this).hashCode();
+         return super.hashCode();
      }
  
      @Override
  
      @Override
      public String toString() {
-         String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, parentId=%s, favorite=%s etag=%s]";
-         asString = String.format(asString, Long.valueOf(mId), getFileName(), mMimeType, isDown(), mLocalPath, mRemotePath, Long.valueOf(mParentId), Boolean.valueOf(mFavorite), mEtag);
+         String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, " +
+                 "parentId=%s, favorite=%s etag=%s]";
+         asString = String.format(asString, Long.valueOf(mId), getFileName(), mMimeType, isDown(),
+                 mLocalPath, mRemotePath, Long.valueOf(mParentId), Boolean.valueOf(mFavorite),
+                 mEtag);
          return asString;
      }
  
       */
      public boolean isImage() {
          return ((mMimeType != null && mMimeType.startsWith("image/")) ||
-                 FileStorageUtils.getMimeTypeFromName(mRemotePath).startsWith("image/"));
+                 getMimeTypeFromName().startsWith("image/"));
+     }
+     /**
+      * @return 'True' if the file is simple text (e.g. not application-dependent, like .doc or .docx)
+      */
+     public boolean isText() {
+         return ((mMimeType != null && mMimeType.startsWith("text/")) ||
+                 getMimeTypeFromName().startsWith("text/"));
+     }
+     public String getMimeTypeFromName() {
+         String extension = "";
+         int pos = mRemotePath.lastIndexOf('.');
+         if (pos >= 0) {
+             extension = mRemotePath.substring(pos + 1);
+         }
+         String result = MimeTypeMap.getSingleton().
+                 getMimeTypeFromExtension(extension.toLowerCase());
+         return (result != null) ? result : "";
+     }
+     /**
+      * @return 'True' if the file is hidden
+      */
+     public boolean isHidden() {
+         return getFileName().startsWith(".");
      }
  
      public String getPermissions() {
@@@ -39,7 -39,7 +39,7 @@@ import com.owncloud.android.services.Op
  import com.owncloud.android.ui.activity.ComponentsGetter;
  
  /**
-  * Filters out the file actions available in a given {@link Menu} for a given {@link OCFile} 
+  * Filters out the file actions available in a given {@link Menu} for a given {@link OCFile}
   * according to the current state of the latest. 
   */
  public class FileMenuFilter {
      private ComponentsGetter mComponentsGetter;
      private Account mAccount;
      private Context mContext;
-     
      /**
       * Constructor
-      * 
+      *
       * @param targetFile        {@link OCFile} target of the action to filter in the {@link Menu}.
       * @param account           ownCloud {@link Account} holding targetFile.
       * @param cg                Accessor to app components, needed to access the
          mComponentsGetter = cg;
          mContext = context;
      }
-     
-     
      /**
       * Filters out the file actions available in the passed {@link Menu} taken into account
       * the state of the {@link OCFile} held by the filter.
-      *  
+      *
       * @param menu              Options or context menu to filter.
       */
      public void filter(Menu menu) {
-         List<Integer> toShow = new ArrayList<Integer>();  
-         List<Integer> toHide = new ArrayList<Integer>();    
-         
+         List<Integer> toShow = new ArrayList<Integer>();
+         List<Integer> toHide = new ArrayList<Integer>();
          filter(toShow, toHide);
-         
          MenuItem item = null;
          for (int i : toShow) {
              item = menu.findItem(i);
@@@ -86,7 -86,7 +86,7 @@@
                  item.setEnabled(true);
              }
          }
-         
          for (int i : toHide) {
              item = menu.findItem(i);
              if (item != null) {
  
      /**
       * Performs the real filtering, to be applied in the {@link Menu} by the caller methods.
-      * 
+      *
       * Decides what actions must be shown and hidden.
-      *  
-      * @param toShow            List to save the options that must be shown in the menu. 
+      *
+      * @param toShow            List to save the options that must be shown in the menu.
       * @param toHide            List to save the options that must be shown in the menu.
       */
      private void filter(List<Integer> toShow, List <Integer> toHide) {
              FileUploaderBinder uploaderBinder = mComponentsGetter.getFileUploaderBinder();
              uploading = (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile));
          }
-         
          /// decision is taken for each possible action on a file in the menu
-         
          // DOWNLOAD 
          if (mFile == null || mFile.isDown() || downloading || uploading) {
              toHide.add(R.id.action_download_file);
-             
          } else {
              toShow.add(R.id.action_download_file);
          }
-         
          // RENAME
          if (mFile == null || downloading || uploading) {
              toHide.add(R.id.action_rename_file);
-             
          } else {
              toShow.add(R.id.action_rename_file);
          }
  
-         // MOVE
+         // MOVE & COPY
          if (mFile == null || downloading || uploading) {
              toHide.add(R.id.action_move);
+             toHide.add(R.id.action_copy);
          } else {
              toShow.add(R.id.action_move);
+             toShow.add(R.id.action_copy);
          }
-         
          // REMOVE
          if (mFile == null || downloading || uploading) {
              toHide.add(R.id.action_remove_file);
-             
          } else {
              toShow.add(R.id.action_remove_file);
          }
-         
          // OPEN WITH (different to preview!)
          if (mFile == null || mFile.isFolder() || !mFile.isDown() || downloading || uploading) {
              toHide.add(R.id.action_open_file_with);
-             
          } else {
              toShow.add(R.id.action_open_file_with);
          }
-         
-         
          // CANCEL DOWNLOAD
          if (mFile == null || !downloading) {
              toHide.add(R.id.action_cancel_download);
          } else {
              toShow.add(R.id.action_cancel_download);
          }
-         
          // CANCEL UPLOAD
          if (mFile == null || !uploading || mFile.isFolder()) {
              toHide.add(R.id.action_cancel_upload);
          } else {
              toShow.add(R.id.action_cancel_upload);
          }
-         
          // SYNC FILE CONTENTS
          if (mFile == null || mFile.isFolder() || !mFile.isDown() || downloading || uploading) {
              toHide.add(R.id.action_sync_file);
          } else {
              toShow.add(R.id.action_sync_file);
          }
-         
          // SHARE FILE 
          // TODO add check on SHARE available on server side?
          boolean shareAllowed = (mContext != null  &&
          } else {
              toShow.add(R.id.action_share_file);
          }
-         
          // UNSHARE FILE  
          // TODO add check on SHARE available on server side?
          if ( !shareAllowed || (mFile == null || !mFile.isShareByLink())) {
          } else {
              toShow.add(R.id.action_see_details);
          }
-         
          // SEND
          boolean sendAllowed = (mContext != null &&
                  mContext.getString(R.string.send_files_to_other_apps).equalsIgnoreCase("on"));
          } else {
              toShow.add(R.id.action_unfavorite_file);
          }
 -
      }
  
  }
@@@ -77,6 -77,7 +77,7 @@@ import com.owncloud.android.lib.common.
  import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
  import com.owncloud.android.lib.common.utils.Log_OC;
+ import com.owncloud.android.operations.CopyFileOperation;
  import com.owncloud.android.operations.CreateFolderOperation;
  import com.owncloud.android.operations.CreateShareOperation;
  import com.owncloud.android.operations.MoveFileOperation;
@@@ -98,6 -99,7 +99,7 @@@ import com.owncloud.android.ui.fragment
  import com.owncloud.android.ui.preview.PreviewImageActivity;
  import com.owncloud.android.ui.preview.PreviewImageFragment;
  import com.owncloud.android.ui.preview.PreviewMediaFragment;
+ import com.owncloud.android.ui.preview.PreviewTextFragment;
  import com.owncloud.android.ui.preview.PreviewVideoActivity;
  import com.owncloud.android.utils.DisplayUtils;
  import com.owncloud.android.utils.ErrorMessageAdapter;
@@@ -106,7 -108,6 +108,6 @@@ import com.owncloud.android.utils.UriUt
  
  import java.io.File;
  
  /**
   * Displays, what files the user has available in his ownCloud.
   */
@@@ -115,6 -116,8 +116,8 @@@ public class FileDisplayActivity extend
          implements FileFragment.ContainerActivity,
          OnSslUntrustedCertListener, OnEnforceableRefreshListener {
  
      private SyncBroadcastReceiver mSyncBroadcastReceiver;
      private UploadFinishReceiver mUploadFinishReceiver;
      private DownloadFinishReceiver mDownloadFinishReceiver;
      public static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
      public static final int ACTION_SELECT_MULTIPLE_FILES = 2;
      public static final int ACTION_MOVE_FILES = 3;
+     public static final int ACTION_COPY_FILES = 4;
  
      private static final String TAG = FileDisplayActivity.class.getSimpleName();
  
      private static final String TAG_SECOND_FRAGMENT = "SECOND_FRAGMENT";
  
      private OCFile mWaitingToPreview;
-     
      private boolean mSyncInProgress = false;
  
      private static String DIALOG_UNTRUSTED_CERT = "DIALOG_UNTRUSTED_CERT";
      private static String DIALOG_CERT_NOT_SAVED = "DIALOG_CERT_NOT_SAVED";
  
      private OCFile mWaitingToSend;
 +    private Menu mOptionsMenu;
 +
  
 -    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          Log_OC.v(TAG, "onCreate() start");
              Intent initObserversIntent = FileObserverService.makeInitIntent(this);
              startService(initObserversIntent);
          }
-         
          /// Load of saved instance state
          if(savedInstanceState != null) {
              mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(
              mSyncInProgress = savedInstanceState.getBoolean(KEY_SYNC_IN_PROGRESS);
              mWaitingToSend = (OCFile) savedInstanceState.getParcelable(
                      FileDisplayActivity.KEY_WAITING_TO_SEND);
-            
          } else {
              mWaitingToPreview = null;
              mSyncInProgress = false;
              mWaitingToSend = null;
-         }        
+         }
  
          /// USER INTERFACE
  
          // Inflate and set the layout view
          setContentView(R.layout.files);
-         
          // Navigation Drawer
          initDrawer();
  
  
          mProgressBar.setIndeterminate(mSyncInProgress);
          // always AFTER setContentView(...) ; to work around bug in its implementation
-         
          setBackgroundText();
  
          Log_OC.v(TAG, "onCreate() end");
      }
  
      /**
-      *  Called when the ownCloud {@link Account} associated to the Activity was just updated.
-      */ 
+      * Called when the ownCloud {@link Account} associated to the Activity was just updated.
+      */
      @Override
      protected void onAccountSet(boolean stateWasRecovered) {
          super.onAccountSet(stateWasRecovered);
                  if (file.isFolder()) {
                      startSyncFolderOperation(file, false);
                  }
-                 
              } else {
                  updateFragmentsVisibility(!file.isFolder());
                  updateActionBarTitleAndHomeButton(file.isFolder() ? null : file);
          }
      }
  
      private void createMinFragments() {
          OCFileListFragment listOfFiles = new OCFileListFragment();
          FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
          transaction.add(R.id.left_fragment_container, listOfFiles, TAG_LIST_OF_FILES);
          transaction.commit();
      }
-     
      private void initFragmentsWithFile() {
          if (getAccount() != null && getFile() != null) {
              /// First fragment
-             OCFileListFragment listOfFiles = getListOfFilesFragment(); 
+             OCFileListFragment listOfFiles = getListOfFilesFragment();
              if (listOfFiles != null) {
                  listOfFiles.listDirectory(getCurrentDir());
                  // TODO Enable when "On Device" is recovered
                  // listOfFiles.listDirectory(getCurrentDir(), MainApp.getOnlyOnDevice());
              } else {
                  Log_OC.e(TAG, "Still have a chance to lose the initializacion of list fragment >(");
              }
-             
              /// Second fragment
-             OCFile file = getFile(); 
+             OCFile file = getFile();
              Fragment secondFragment = chooseInitialSecondFragment(file);
              if (secondFragment != null) {
                  setSecondFragment(secondFragment);
                  updateFragmentsVisibility(true);
                  updateActionBarTitleAndHomeButton(file);
-                 
              } else {
                  cleanSecondFragment();
+                 if (file.isDown() && PreviewTextFragment.canBePreviewed(file))
+                     startTextPreview(file);
              }
  
 +            if (DisplayUtils.isGridView(getFile(), getStorageManager())){
 +                switchToGridView();
 +            } else {
 +                switchToListView();
 +            }
 +
          } else {
              Log_OC.wtf(TAG, "initFragments() called with invalid NULLs!");
              if (getAccount() == null) {
      private Fragment chooseInitialSecondFragment(OCFile file) {
          Fragment secondFragment = null;
          if (file != null && !file.isFolder()) {
-             if (file.isDown() && PreviewMediaFragment.canBePreviewed(file) 
+             if (file.isDown() && PreviewMediaFragment.canBePreviewed(file)
                      && file.getLastSyncDateForProperties() > 0  // temporal fix
                      ) {
                  int startPlaybackPosition =
                  secondFragment = new PreviewMediaFragment(file, getAccount(),
                          startPlaybackPosition, autoplay);
  
+             } else if (file.isDown() && PreviewTextFragment.canBePreviewed(file)) {
+                 secondFragment = null;
              } else {
-                 secondFragment = FileDetailFragment.newInstance(file, getAccount());
-             }
+             secondFragment = FileDetailFragment.newInstance(file, getAccount());
+         }
          }
          return secondFragment;
      }
      /**
       * Replaces the second fragment managed by the activity with the received as
       * a parameter.
-      * 
-      * Assumes never will be more than two fragments managed at the same time. 
-      * 
-      * @param fragment      New second Fragment to set.
+      * <p/>
+      * Assumes never will be more than two fragments managed at the same time.
+      *
+      * @param fragment New second Fragment to set.
       */
      private void setSecondFragment(Fragment fragment) {
          FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
          Fragment listOfFiles = getSupportFragmentManager().findFragmentByTag(
                  FileDisplayActivity.TAG_LIST_OF_FILES);
          if (listOfFiles != null) {
-             return (OCFileListFragment)listOfFiles;
+             return (OCFileListFragment) listOfFiles;
          }
          Log_OC.wtf(TAG, "Access to unexisting list of files fragment!!");
          return null;
          Fragment second = getSupportFragmentManager().findFragmentByTag(
                  FileDisplayActivity.TAG_SECOND_FRAGMENT);
          if (second != null) {
-             return (FileFragment)second;
+             return (FileFragment) second;
          }
          return null;
      }
                          if (PreviewMediaFragment.canBePreviewed(mWaitingToPreview)) {
                              startMediaPreview(mWaitingToPreview, 0, true);
                              detailsFragmentChanged = true;
+                         } else if (PreviewTextFragment.canBePreviewed(mWaitingToPreview)) {
+                             startTextPreview(mWaitingToPreview);
+                             detailsFragmentChanged = true;
                          } else {
                              getFileOperationsHelper().openFile(mWaitingToPreview);
                          }
          menu.findItem(R.id.action_create_dir).setVisible(!drawerOpen);
          menu.findItem(R.id.action_sort).setVisible(!drawerOpen);
          menu.findItem(R.id.action_sync_account).setVisible(!drawerOpen);
 +        menu.findItem(R.id.action_switch_view).setVisible(!drawerOpen);
          
          return super.onPrepareOptionsMenu(menu);
      }
      public boolean onCreateOptionsMenu(Menu menu) {
          MenuInflater inflater = getMenuInflater();
          inflater.inflate(R.menu.main_menu, menu);
 +        mOptionsMenu = menu;
 +
 +        MenuItem menuItem = mOptionsMenu.findItem(R.id.action_switch_view);
 +
 +        changeGridIcon();
 +
          return true;
      }
      
                  dialog.show(getSupportFragmentManager(), DIALOG_CREATE_FOLDER);
                  break;
              }
              case R.id.action_sync_account: {
                  startSynchronization();
                  break;
                  UploadSourceDialogFragment dialog =
                          UploadSourceDialogFragment.newInstance(getAccount());
                  dialog.show(getSupportFragmentManager(), DIALOG_UPLOAD_SOURCE);
                  break;
              }
              case android.R.id.home: {
                  builder.create().show();
                  break;
              }
 +            case R.id.action_switch_view:{
 +                if (isGridView()){
 +                    item.setTitle(getApplicationContext().getString(R.string.action_switch_grid_view));
 +                    item.setIcon(ContextCompat.getDrawable(getApplicationContext(),
 +                            R.drawable.ic_view_module));
 +                    DisplayUtils.setViewMode(getFile(), false);
 +                    switchToListView();
 +                } else {
 +                    item.setTitle(getApplicationContext().getString(R.string.action_switch_list_view));
 +                    item.setIcon(ContextCompat.getDrawable(getApplicationContext(),
 +                            R.drawable.ic_view_list));
 +                    DisplayUtils.setViewMode(getFile(), true);
 +                    switchToGridView();
 +                }
 +
 +                return true;
 +            }
          default:
              retval = super.onOptionsItemSelected(item);
          }
              requestMultipleUpload(data, resultCode);
  
          } else if (requestCode == ACTION_MOVE_FILES && resultCode == RESULT_OK){
+             final Intent fData = data;
+             final int fResultCode = resultCode;
+             getHandler().postDelayed(
+                     new Runnable() {
+                         @Override
+                         public void run() {
+                             requestMoveOperation(fData, fResultCode);
+                         }
+                     },
+                     DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS
+             );
+         } else if (requestCode == ACTION_COPY_FILES && resultCode == RESULT_OK) {
  
              final Intent fData = data;
-             final int fResultCode = resultCode; 
+             final int fResultCode = resultCode;
              getHandler().postDelayed(
-                 new Runnable() {
-                     @Override
-                     public void run() {
-                         requestMoveOperation(fData, fResultCode);
-                     }
-                 }, 
-                 DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS
+                     new Runnable() {
+                         @Override
+                         public void run() {
+                             requestCopyOperation(fData, fResultCode);
+                         }
+                     },
+                     DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS
              );
  
          } else {
  
      /**
       * Request the operation for moving the file/folder from one path to another
-      * 
-      * @param data              Intent received
-      * @param resultCode        Result code received
+      *
+      * @param data       Intent received
+      * @param resultCode Result code received
       */
      private void requestMoveOperation(Intent data, int resultCode) {
          OCFile folderToMoveAt = (OCFile) data.getParcelableExtra(FolderPickerActivity.EXTRA_FOLDER);
          getFileOperationsHelper().moveFile(folderToMoveAt, targetFile);
      }
  
+     /**
+      * Request the operation for copying the file/folder from one path to another
+      *
+      * @param data       Intent received
+      * @param resultCode Result code received
+      */
+     private void requestCopyOperation(Intent data, int resultCode) {
+         OCFile folderToMoveAt = data.getParcelableExtra(FolderPickerActivity.EXTRA_FOLDER);
+         OCFile targetFile = data.getParcelableExtra(FolderPickerActivity.EXTRA_FILE);
+         getFileOperationsHelper().copyFile(folderToMoveAt, targetFile);
+     }
      @Override
      public void onBackPressed() {
          if (!isDrawerOpen()){
                  setFile(listOfFiles.getCurrentFile());
              }
              cleanSecondFragment();
 +
 +            changeGridIcon();
          } else {
              super.onBackPressed();
          }
      }
  
 +    private void changeGridIcon(){
 +        MenuItem menuItem = mOptionsMenu.findItem(R.id.action_switch_view);
 +        if (DisplayUtils.isGridView(getFile(), getStorageManager())){
 +            menuItem.setTitle(getApplicationContext().getString(R.string.action_switch_list_view));
 +            menuItem.setIcon(ContextCompat.getDrawable(getApplicationContext(),
 +                    R.drawable.ic_view_list));
 +        } else {
 +            menuItem.setTitle(getApplicationContext().getString(R.string.action_switch_grid_view));
 +            menuItem.setIcon(ContextCompat.getDrawable(getApplicationContext(),
 +                    R.drawable.ic_view_module));
 +        }
 +    }
 +
      @Override
      protected void onSaveInstanceState(Bundle outState) {
          // responsibility of restore is preferred in onCreate() before than in
  
          Log_OC.v(TAG, "onSaveInstanceState() end");
      }
-     
  
  
      @Override
      protected void onResume() {
          Log_OC.v(TAG, "onResume() start");
          super.onResume();
          // refresh Navigation Drawer account list
          mNavigationDrawerAdapter.updateAccountList();
  
          // refresh list of files
          refreshListOfFilesFragment();
  
          downloadIntentFilter.addAction(FileDownloader.getDownloadFinishMessage());
          mDownloadFinishReceiver = new DownloadFinishReceiver();
          registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
-         
          Log_OC.v(TAG, "onResume() end");
      }
  
  
              unregisterReceiver(mDownloadFinishReceiver);
              mDownloadFinishReceiver = null;
          }
-         
          super.onPause();
          Log_OC.v(TAG, "onPause() end");
      }
                                  FileSyncAdapter.EXTRA_RESULT);
                  boolean sameAccount = (getAccount() != null &&
                          accountName.equals(getAccount().name) && getStorageManager() != null);
-     
                  if (sameAccount) {
-                     
                      if (FileSyncAdapter.EVENT_FULL_SYNC_START.equals(event)) {
                          mSyncInProgress = true;
-                         
                      } else {
                          OCFile currentFile = (getFile() == null) ? null :
                                  getStorageManager().getFileByPath(getFile().getRemotePath());
                                                     synchFolderRemotePath),
                                              Toast.LENGTH_LONG)
                                  .show();
                              browseToRoot();
-                             
                          } else {
                              if (currentFile == null && !getFile().isFolder()) {
                                  // currently selected file was removed in the server, and now we
                              }
                              setFile(currentFile);
                          }
-                         
                          mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) &&
                                  !RefreshFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED
                                          .equals(event));
                                  
                          if (RefreshFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED.
-                                     equals(event) &&
-                                 /// TODO refactor and make common
-                                 synchResult != null && !synchResult.isSuccess() &&  
-                                 (synchResult.getCode() == ResultCode.UNAUTHORIZED   || 
-                                     synchResult.isIdPRedirection()                  ||
-                                     (synchResult.isException() && synchResult.getException() 
-                                             instanceof AuthenticatorException))) {
+                                     equals(event) &&/// TODO refactor and make common
+                                 synchResult != null && !synchResult.isSuccess() &&
+                                 (synchResult.getCode() == ResultCode.UNAUTHORIZED ||
+                                         synchResult.isIdPRedirection() ||
+                                         (synchResult.isException() && synchResult.getException()
+                                                 instanceof AuthenticatorException))) {
  
  
                              try {
                                          new OwnCloudAccount(getAccount(), context);
                                  client = (OwnCloudClientManagerFactory.getDefaultSingleton().
                                          removeClientFor(ocAccount));
                                  if (client != null) {
                                      OwnCloudCredentials cred = client.getCredentials();
                                      if (cred != null) {
                      /*|| mRefreshSharesInProgress*/ //);
  
                      setBackgroundText();
-                         
                  }
-                 
                  if (synchResult != null) {
                      if (synchResult.getCode().equals(
                              RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) {
              }
          }
      }
-     
      /**
       * Show a text message on screen view for notifying user if content is
       * loading or folder is empty
      private class UploadFinishReceiver extends BroadcastReceiver {
          /**
           * Once the file upload has finished -> update view
-          *  @author David A. Velasco
+          *
+          * @author David A. Velasco
           * {@link BroadcastReceiver} to enable upload feedback in UI
           */
          @Override
                  String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);
                  boolean sameAccount = getAccount() != null && accountName.equals(getAccount().name);
                  OCFile currentDir = getCurrentDir();
-                 boolean isDescendant = (currentDir != null) && (uploadedRemotePath != null) && 
+                 boolean isDescendant = (currentDir != null) && (uploadedRemotePath != null) &&
                          (uploadedRemotePath.startsWith(currentDir.getRemotePath()));
-                 
                  if (sameAccount && isDescendant) {
                      refreshListOfFilesFragment();
                  }
-                 
                  boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT,
                          false);
                  boolean renamedInUpload = getFile().getRemotePath().
                          equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH));
-                 boolean sameFile = getFile().getRemotePath().equals(uploadedRemotePath) || 
+                 boolean sameFile = getFile().getRemotePath().equals(uploadedRemotePath) ||
                          renamedInUpload;
                  FileFragment details = getSecondFragment();
-                 boolean detailFragmentIsShown = (details != null && 
+                 boolean detailFragmentIsShown = (details != null &&
                          details instanceof FileDetailFragment);
-                 
                  if (sameAccount && sameFile && detailFragmentIsShown) {
                      if (uploadWasFine) {
                          setFile(getStorageManager().getFileByPath(uploadedRemotePath));
                      if (renamedInUpload) {
                          String newName = (new File(uploadedRemotePath)).getName();
                          Toast msg = Toast.makeText(
-                                 context, 
+                                 context,
                                  String.format(
-                                         getString(R.string.filedetails_renamed_in_upload_msg), 
-                                         newName), 
+                                         getString(R.string.filedetails_renamed_in_upload_msg),
+                                         newName),
                                  Toast.LENGTH_LONG);
                          msg.show();
                      }
                      if (uploadWasFine || getFile().fileExists()) {
-                         ((FileDetailFragment)details).updateFileDetails(false, true);
+                         ((FileDetailFragment) details).updateFileDetails(false, true);
                      } else {
                          cleanSecondFragment();
                      }
-                     
-                     // Force the preview if the file is an image
-                     if (uploadWasFine && PreviewImageFragment.canBePreviewed(getFile())) {
-                         startImagePreview(getFile());
-                     } // TODO what about other kind of previews?
+                     // Force the preview if the file is an image or text file
+                     if (uploadWasFine) {
+                         OCFile ocFile = getFile();
+                         if (PreviewImageFragment.canBePreviewed(ocFile))
+                             startImagePreview(getFile());
+                         else if (PreviewTextFragment.canBePreviewed(ocFile))
+                             startTextPreview(ocFile);
+                         // TODO what about other kind of previews?
+                     }
                  }
  
                  mProgressBar.setIndeterminate(false);
                      removeStickyBroadcast(intent);
                  }
              }
-             
          }
-         
      }
  
  
      /**
       * Class waiting for broadcast events from the {@link FileDownloader} service.
-      * 
+      *
       * Updates the UI when a download is started or finished, provided that it is relevant for the
       * current folder.
       */
                              intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false)
                      );
                  }
-     
                  if (mWaitingToSend != null) {
                      mWaitingToSend =
                              getStorageManager().getFileByPath(mWaitingToSend.getRemotePath());
-                     if (mWaitingToSend.isDown()) { 
+                     if (mWaitingToSend.isDown()) {
                          sendDownloadedFile();
                      }
                  }
-             
              } finally {
                  if (intent != null) {
                      removeStickyBroadcast(intent);
                      accountName.equals(getAccount().name));
          }
      }
-     
-     
      public void browseToRoot() {
-         OCFileListFragment listOfFiles = getListOfFilesFragment(); 
+         OCFileListFragment listOfFiles = getListOfFilesFragment();
          if (listOfFiles != null) {  // should never be null, indeed
              OCFile root = getStorageManager().getFileByPath(OCFile.ROOT_PATH);
              listOfFiles.listDirectory(root);
              startSyncFolderOperation(root, false);
          }
          cleanSecondFragment();
      }
  
  
      /**
       * {@inheritDoc}
-      * 
+      * <p/>
       * Updates action bar and second fragment, if in dual pane mode.
       */
      @Override
          cleanSecondFragment();
          // Sync Folder
          startSyncFolderOperation(directory, false);
 +
 +        MenuItem menuItem = mOptionsMenu.findItem(R.id.action_switch_view);
 +
 +        changeGridIcon();
 +        if (DisplayUtils.isGridView(directory, getStorageManager())){
 +            switchToGridView();
 +        } else {
 +            switchToListView();
 +        }
      }
  
      /**
-      * Shows the information of the {@link OCFile} received as a 
+      * Shows the information of the {@link OCFile} received as a
       * parameter in the second fragment.
-      * 
-      * @param file          {@link OCFile} whose details will be shown
+      *
+      * @param file {@link OCFile} whose details will be shown
       */
      @Override
      public void showDetails(OCFile file) {
          return new ListServiceConnection();
      }
  
-     /** Defines callbacks for service binding, passed to bindService() */
+     /**
+      * Defines callbacks for service binding, passed to bindService()
+      */
      private class ListServiceConnection implements ServiceConnection {
  
          @Override
                          if (!mWaitingToPreview.isDown()) {
                              requestForDownload();
                          }
-                 }
+                     }
  
              } else if (component.equals(new ComponentName(FileDisplayActivity.this,
                      FileUploader.class))) {
              }
              // a new chance to get the mDownloadBinder through
              // getFileDownloadBinder() - THIS IS A MESS
-             OCFileListFragment listOfFiles = getListOfFilesFragment(); 
+             OCFileListFragment listOfFiles = getListOfFilesFragment();
              if (listOfFiles != null) {
                  listOfFiles.listDirectory();
                  // TODO Enable when "On Device" is recovered ?
              }
              FileFragment secondFragment = getSecondFragment();
              if (secondFragment != null && secondFragment instanceof FileDetailFragment) {
-                 FileDetailFragment detailFragment = (FileDetailFragment)secondFragment;
+                 FileDetailFragment detailFragment = (FileDetailFragment) secondFragment;
                  detailFragment.listenForTransferProgress();
                  detailFragment.updateFileDetails(false, false);
              }
                  mUploaderBinder = null;
              }
          }
-     };    
+     }
  
      @Override
      public void onSavedCertificate() {
      /**
       * Updates the view associated to the activity after the finish of some operation over files
       * in the current account.
-      * 
-      * @param operation     Removal operation performed.
-      * @param result        Result of the removal.
+      *
+      * @param operation Removal operation performed.
+      * @param result    Result of the removal.
       */
      @Override
      public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
          super.onRemoteOperationFinish(operation, result);
-         
          if (operation instanceof RemoveFileOperation) {
              onRemoveFileOperationFinish((RemoveFileOperation) operation, result);
  
          } else if (operation instanceof RenameFileOperation) {
-             onRenameFileOperationFinish((RenameFileOperation)operation, result);
+             onRenameFileOperationFinish((RenameFileOperation) operation, result);
  
          } else if (operation instanceof SynchronizeFileOperation) {
-             onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);
+             onSynchronizeFileOperationFinish((SynchronizeFileOperation) operation, result);
  
          } else if (operation instanceof CreateFolderOperation) {
-             onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
-             
+             onCreateFolderOperationFinish((CreateFolderOperation) operation, result);
          } else if (operation instanceof CreateShareOperation) {
              onCreateShareOperationFinish((CreateShareOperation) operation, result);
-             
          } else if (operation instanceof UnshareLinkOperation) {
-             onUnshareLinkOperationFinish((UnshareLinkOperation)operation, result);
-         
+             onUnshareLinkOperationFinish((UnshareLinkOperation) operation, result);
          } else if (operation instanceof MoveFileOperation) {
-             onMoveFileOperationFinish((MoveFileOperation)operation, result);
+             onMoveFileOperationFinish((MoveFileOperation) operation, result);
+         } else if (operation instanceof CopyFileOperation) {
+             onCopyFileOperationFinish((CopyFileOperation) operation, result);
          }
-         
-     }
  
-     
+     }
      private void onCreateShareOperationFinish(CreateShareOperation operation,
                                                RemoteOperationResult result) {
          if (result.isSuccess()) {
          }
      }
  
-     
      private void onUnshareLinkOperationFinish(UnshareLinkOperation operation,
                                                RemoteOperationResult result) {
          if (result.isSuccess()) {
              refreshShowDetails();
              refreshListOfFilesFragment();
-             
          } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND) {
              cleanSecondFragment();
              refreshListOfFilesFragment();
          }
      }
-     
      private void refreshShowDetails() {
          FileFragment details = getSecondFragment();
          if (details != null) {
              OCFile file = details.getFile();
              if (file != null) {
-                 file = getStorageManager().getFileByPath(file.getRemotePath()); 
+                 file = getStorageManager().getFileByPath(file.getRemotePath());
                  if (details instanceof PreviewMediaFragment) {
                      // Refresh  OCFile of the fragment
                      ((PreviewMediaFragment) details).updateFile(file);
+                 } else if (details instanceof PreviewTextFragment) {
+                     // Refresh  OCFile of the fragment
+                     ((PreviewTextFragment) details).updateFile(file);
                  } else {
                      showDetails(file);
-                 } 
+                 }
              }
              invalidateOptionsMenu();
-         } 
+         }
      }
-     
      /**
       * Updates the view associated to the activity after the finish of an operation trying to
       * remove a file.
      private void onRemoveFileOperationFinish(RemoveFileOperation operation,
                                               RemoteOperationResult result) {
          dismissLoadingDialog();
-         
          Toast msg = Toast.makeText(this,
                  ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
-                 Toast.LENGTH_LONG); 
+                 Toast.LENGTH_LONG);
          msg.show();
-         
          if (result.isSuccess()) {
              OCFile removedFile = operation.getFile();
              FileFragment second = getSecondFragment();
              if (second != null && removedFile.equals(second.getFile())) {
                  if (second instanceof PreviewMediaFragment) {
-                     ((PreviewMediaFragment)second).stopPreview(true);
+                     ((PreviewMediaFragment) second).stopPreview(true);
                  }
                  setFile(getStorageManager().getFileById(removedFile.getParentId()));
                  cleanSecondFragment();
              }
-             if (getStorageManager().getFileById(removedFile.getParentId()).equals(getCurrentDir())) {
+             if (getStorageManager().getFileById(removedFile.getParentId()).equals(getCurrentDir())){
                  refreshListOfFilesFragment();
              }
              invalidateOptionsMenu();
              }
          }
      }
-     
-     
      /**
-      * Updates the view associated to the activity after the finish of an operation trying to move a 
+      * Updates the view associated to the activity after the finish of an operation trying to move a
       * file.
-      * 
-      * @param operation     Move operation performed.
-      * @param result        Result of the move operation.
+      *
+      * @param operation Move operation performed.
+      * @param result    Result of the move operation.
       */
      private void onMoveFileOperationFinish(MoveFileOperation operation,
                                             RemoteOperationResult result) {
          } else {
              dismissLoadingDialog();
              try {
-                 Toast msg = Toast.makeText(FileDisplayActivity.this, 
-                         ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
-                         Toast.LENGTH_LONG); 
+                 Toast msg = Toast.makeText(FileDisplayActivity.this,
+                         ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+                         Toast.LENGTH_LONG);
                  msg.show();
  
              } catch (NotFoundException e) {
-                 Log_OC.e(TAG, "Error while trying to show fail message " , e);
+                 Log_OC.e(TAG, "Error while trying to show fail message ", e);
              }
          }
      }
  
+     /**
+      * Updates the view associated to the activity after the finish of an operation trying to copy a
+      * file.
+      *
+      * @param operation Copy operation performed.
+      * @param result    Result of the copy operation.
+      */
+     private void onCopyFileOperationFinish(CopyFileOperation operation, RemoteOperationResult result) {
+         if (result.isSuccess()) {
+             dismissLoadingDialog();
+             refreshListOfFilesFragment();
+         } else {
+             dismissLoadingDialog();
+             try {
+                 Toast msg = Toast.makeText(FileDisplayActivity.this,
+                         ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+                         Toast.LENGTH_LONG);
+                 msg.show();
+             } catch (NotFoundException e) {
+                 Log_OC.e(TAG, "Error while trying to show fail message ", e);
+             }
+         }
+     }
  
      /**
       * Updates the view associated to the activity after the finish of an operation trying to rename
                          renamedFile.equals(details.getFile())) {
                      ((PreviewMediaFragment) details).updateFile(renamedFile);
                      if (PreviewMediaFragment.canBePreviewed(renamedFile)) {
-                         int position = ((PreviewMediaFragment)details).getPosition();
+                         int position = ((PreviewMediaFragment) details).getPosition();
                          startMediaPreview(renamedFile, position, true);
                      } else {
                          getFileOperationsHelper().openFile(renamedFile);
                      }
+                 } else if (details instanceof PreviewTextFragment &&
+                         renamedFile.equals(details.getFile())) {
+                     ((PreviewTextFragment) details).updateFile(renamedFile);
+                     if (PreviewTextFragment.canBePreviewed(renamedFile)) {
+                         startTextPreview(renamedFile);
+                     } else {
+                         getFileOperationsHelper().openFile(renamedFile);
+                     }
                  }
              }
-             
              if (getStorageManager().getFileById(renamedFile.getParentId()).equals(getCurrentDir())){
                  refreshListOfFilesFragment();
              }
          } else {
              Toast msg = Toast.makeText(this,
                      ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
-                     Toast.LENGTH_LONG); 
+                     Toast.LENGTH_LONG);
              msg.show();
-             
              if (result.isSslRecoverableException()) {
                  mLastSslUntrustedServerResult = result;
                  showUntrustedCertDialog(mLastSslUntrustedServerResult);
                  OCFile syncedFile = operation.getLocalFile();
                  onTransferStateChanged(syncedFile, true, true);
                  invalidateOptionsMenu();
+                 refreshShowDetails();
              }
          }
      }
          } else {
              dismissLoadingDialog();
              try {
-                 Toast msg = Toast.makeText(FileDisplayActivity.this, 
-                         ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
-                         Toast.LENGTH_LONG); 
+                 Toast msg = Toast.makeText(FileDisplayActivity.this,
+                         ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+                         Toast.LENGTH_LONG);
                  msg.show();
  
              } catch (NotFoundException e) {
-                 Log_OC.e(TAG, "Error while trying to show fail message " , e);
+                 Log_OC.e(TAG, "Error while trying to show fail message ", e);
              }
          }
      }
  
-     
      /**
       * {@inheritDoc}
       */
          if (details != null && details instanceof FileDetailFragment &&
                  file.equals(details.getFile()) ) {
              if (downloading || uploading) {
-                 ((FileDetailFragment)details).updateFileDetails(file, getAccount());
+                 ((FileDetailFragment) details).updateFileDetails(file, getAccount());
              } else {
                  if (!file.fileExists()) {
                      cleanSecondFragment();
                  } else {
-                     ((FileDetailFragment)details).updateFileDetails(false, true);
+                     ((FileDetailFragment) details).updateFileDetails(false, true);
                  }
              }
          }
-             
      }
  
  
          }
          return null;
      }
-     
      public void startSyncFolderOperation(OCFile folder, boolean ignoreETag) {
-         long currentSyncTime = System.currentTimeMillis(); 
-         
+         long currentSyncTime = System.currentTimeMillis();
          mSyncInProgress = true;
-                 
          // perform folder synchronization
          RemoteOperation synchFolderOp = new RefreshFolderOperation( folder,
                  currentSyncTime,
                  getApplicationContext()
          );
          synchFolderOp.execute(getAccount(), MainApp.getAppContext(), this, null, null);
          mProgressBar.setIndeterminate(true);
  
          setBackgroundText();
      }
  
      /**
-      * Show untrusted cert dialog 
+      * Show untrusted cert dialog
       */
      public void showUntrustedCertDialog(RemoteOperationResult result) {
          // Show a dialog with the certificate info
          FragmentTransaction ft = fm.beginTransaction();
          dialog.show(ft, DIALOG_UNTRUSTED_CERT);
      }
-     
      private void requestForDownload(OCFile file) {
          Account account = getAccount();
          if (!mDownloaderBinder.isDownloading(account, mWaitingToPreview)) {
              startService(i);
          }
      }
-     
-     private void sendDownloadedFile(){
+     private void sendDownloadedFile() {
          getFileOperationsHelper().sendDownloadedFile(mWaitingToSend);
          mWaitingToSend = null;
      }
  
-     
      /**
       * Requests the download of the received {@link OCFile} , updates the UI
       * to monitor the download progress and prepares the activity to send the file
       * when the download finishes.
-      * 
-      * @param file          {@link OCFile} to download and preview.
+      *
+      * @param file {@link OCFile} to download and preview.
       */
      public void startDownloadForSending(OCFile file) {
          mWaitingToSend = file;
          requestForDownload(mWaitingToSend);
-         boolean hasSecondFragment = (getSecondFragment()!= null);
+         boolean hasSecondFragment = (getSecondFragment() != null);
          updateFragmentsVisibility(hasSecondFragment);
      }
-     
      /**
       * Opens the image gallery showing the image {@link OCFile} received as parameter.
-      * 
-      * @param file                      Image {@link OCFile} to show.
+      *
+      * @param file Image {@link OCFile} to show.
       */
      public void startImagePreview(OCFile file) {
          Intent showDetailsIntent = new Intent(this, PreviewImageActivity.class);
          showDetailsIntent.putExtra(EXTRA_FILE, file);
          showDetailsIntent.putExtra(EXTRA_ACCOUNT, getAccount());
          startActivity(showDetailsIntent);
-         
      }
  
      /**
       * Stars the preview of an already down media {@link OCFile}.
-      * 
+      *
       * @param file                      Media {@link OCFile} to preview.
       * @param startPlaybackPosition     Media position where the playback will be started,
       *                                  in milliseconds.
      }
  
      /**
+      * Stars the preview of a text file {@link OCFile}.
+      *
+      * @param file Text {@link OCFile} to preview.
+      */
+     public void startTextPreview(OCFile file) {
+         Bundle args = new Bundle();
+         args.putParcelable(EXTRA_FILE, file);
+         args.putParcelable(EXTRA_ACCOUNT, getAccount());
+         Fragment textPreviewFragment = Fragment.instantiate(getApplicationContext(),
+                 PreviewTextFragment.class.getName(), args);
+         setSecondFragment(textPreviewFragment);
+         updateFragmentsVisibility(true);
+         //updateNavigationElementsInActionBar(file);
+         setFile(file);
+     }
+     /**
       * Requests the download of the received {@link OCFile} , updates the UI
       * to monitor the download progress and prepares the activity to preview
       * or open the file when the download finishes.
-      * 
-      * @param file          {@link OCFile} to download and preview.
+      *
+      * @param file {@link OCFile} to download and preview.
       */
      public void startDownloadForPreview(OCFile file) {
          Fragment detailFragment = FileDetailFragment.newInstance(file, getAccount());
  
      public void cancelTransference(OCFile file) {
          getFileOperationsHelper().cancelTransference(file);
-         if (mWaitingToPreview != null && 
+         if (mWaitingToPreview != null &&
                  mWaitingToPreview.getRemotePath().equals(file.getRemotePath())) {
              mWaitingToPreview = null;
          }
          }
      }
  
-     private void sortByDate(boolean ascending){
+     private void sortByDate(boolean ascending) {
          getListOfFilesFragment().sortByDate(ascending);
      }
  
-     private void sortBySize(boolean ascending){
+     private void sortBySize(boolean ascending) {
          getListOfFilesFragment().sortBySize(ascending);
      }
  
-     private void sortByName(boolean ascending){
+     private void sortByName(boolean ascending) {
          getListOfFilesFragment().sortByName(ascending);
      }
 +    private boolean isGridView(){ return getListOfFilesFragment().isGridView(); }
 +    private void switchToGridView() {
 +        getListOfFilesFragment().switchToGridView();
 +    }
 +    private void switchToListView() {
 +        getListOfFilesFragment().switchToListView();
 +    }
  
     public void allFilesOption() {
         browseToRoot();
@@@ -4,6 -4,7 +4,7 @@@
   *   @author Bartek Przybylski\r
   *   @author Tobias Kaminsky\r
   *   @author David A. Velasco\r
+  *   @author masensio\r
   *   Copyright (C) 2011  Bartek Przybylski\r
   *   Copyright (C) 2015 ownCloud Inc.\r
   *\r
@@@ -54,6 -55,7 +55,7 @@@ import com.owncloud.android.services.Op
  import com.owncloud.android.ui.activity.ComponentsGetter;\r
  import com.owncloud.android.utils.DisplayUtils;\r
  import com.owncloud.android.utils.FileStorageUtils;\r
+ import com.owncloud.android.utils.MimetypeIconUtil;\r
  \r
  \r
  /**\r
@@@ -320,24 -322,23 +322,23 @@@ public class FileListListAdapter extend
                              task.execute(file);\r
                          }\r
                      }\r
\r
+                     if (file.getMimetype().equalsIgnoreCase("image/png")) {\r
+                         fileIcon.setBackgroundColor(mContext.getResources()\r
+                                 .getColor(R.color.background_color));\r
+                     }\r
\r
\r
                  } else {\r
-                     fileIcon.setImageResource(DisplayUtils.getFileTypeIconId(file.getMimetype(),\r
+                     fileIcon.setImageResource(MimetypeIconUtil.getFileTypeIconId(file.getMimetype(),\r
                              file.getFileName()));\r
                  }\r
  \r
              } else {\r
                  // Folder\r
-                 if (checkIfFileIsSharedWithMe(file)) {\r
-                     fileIcon.setImageResource(R.drawable.shared_with_me_folder);\r
-                 } else if (file.isShareByLink()) {\r
-                     // If folder is sharedByLink, icon folder must be changed to\r
-                     // folder-public one\r
-                     fileIcon.setImageResource(R.drawable.folder_public);\r
-                 } else {\r
-                     fileIcon.setImageResource(\r
-                             DisplayUtils.getFileTypeIconId(file.getMimetype(), file.getFileName())\r
-                     );\r
-                 }\r
+                 fileIcon.setImageResource(\r
+                         MimetypeIconUtil.getFolderTypeIconId(\r
+                                 checkIfFileIsSharedWithMe(file), file.isShareByLink()));\r
              }\r
          }\r
  \r
      public void setGridMode(boolean gridMode) {\r
          mGridMode = gridMode;\r
      }\r
 +\r
 +    public boolean isGridMode() {\r
 +        return mGridMode;\r
 +    }\r
  }\r
@@@ -71,8 -71,8 +71,8 @@@ public class ExtendedListFragment exten
      private ArrayList<Integer> mTops;
      private int mHeightCell = 0;
  
-     private OnEnforceableRefreshListener mOnRefreshListener = null;
-     
+     private SwipeRefreshLayout.OnRefreshListener mOnRefreshListener = null;
      protected AbsListView mCurrentListView;
      private ExtendedListView mListView;
      private View mListFooterView;
@@@ -97,7 -97,7 +97,7 @@@
      }
  
  
 -    protected void switchToGridView() {
 +    public void switchToGridView() {
          if ((mCurrentListView == mListView)) {
  
              mListView.setAdapter(null);
              mCurrentListView = mGridView;
          }
      }
 -    
 -    protected void switchToListView() {
 +
 +    public void switchToListView() {
          if (mCurrentListView == mGridView) {
              mGridView.setAdapter(null);
              mRefreshGridLayout.setVisibility(View.GONE);
              mCurrentListView = mListView;
          }
      }
 +
 +    public boolean isGridView(){
 +        if (mAdapter instanceof FileListListAdapter) {
 +            return ((FileListListAdapter) mAdapter).isGridMode();
 +        }
 +        return false;
 +    }
      
      
      @Override
          mRefreshEmptyLayout.setRefreshing(false);
  
          if (mOnRefreshListener != null) {
-             mOnRefreshListener.onRefresh(ignoreETag);
+             mOnRefreshListener.onRefresh();
          }
      }
  
@@@ -22,8 -22,6 +22,6 @@@
   */
  package com.owncloud.android.ui.fragment;
  
- import java.io.File;
  import android.app.Activity;
  import android.content.Intent;
  import android.os.Bundle;
@@@ -55,12 -53,14 +53,15 @@@ import com.owncloud.android.ui.dialog.R
  import com.owncloud.android.ui.dialog.RenameFileDialogFragment;
  import com.owncloud.android.ui.preview.PreviewImageFragment;
  import com.owncloud.android.ui.preview.PreviewMediaFragment;
 +import com.owncloud.android.utils.DisplayUtils;
  import com.owncloud.android.utils.FileStorageUtils;
+ import com.owncloud.android.ui.preview.PreviewTextFragment;
+ import java.io.File;
  
  /**
   * A Fragment that lists all files and folders in a given path.
-  * 
+  *
   * TODO refactor to get rid of direct dependency on FileDisplayActivity
   */
  public class OCFileListFragment extends ExtendedListFragment implements FileActionsDialogFragment.FileActionsDialogFragmentListener {
  
      private static final String MY_PACKAGE = OCFileListFragment.class.getPackage() != null ?
              OCFileListFragment.class.getPackage().getName() : "com.owncloud.android.ui.fragment";
-             
      public final static String ARG_JUST_FOLDERS = MY_PACKAGE + ".JUST_FOLDERS";
      public final static String ARG_ALLOW_CONTEXTUAL_ACTIONS = MY_PACKAGE + ".ALLOW_CONTEXTUAL";
-             
      private static final String KEY_FILE = MY_PACKAGE + ".extra.FILE";
  
      private FileFragment.ContainerActivity mContainerActivity;
-    
      private OCFile mFile = null;
      private FileListListAdapter mAdapter;
      private boolean mJustFolders;
          Log_OC.e(TAG, "onAttach");
          try {
              mContainerActivity = (FileFragment.ContainerActivity) activity;
-             
          } catch (ClassCastException e) {
-             throw new ClassCastException(activity.toString() + " must implement " + 
+             throw new ClassCastException(activity.toString() + " must implement " +
                      FileFragment.ContainerActivity.class.getSimpleName());
          }
          try {
              setOnRefreshListener((OnEnforceableRefreshListener) activity);
              
          } catch (ClassCastException e) {
-             throw new ClassCastException(activity.toString() + " must implement " + 
+             throw new ClassCastException(activity.toString() + " must implement " +
                      SwipeRefreshLayout.OnRefreshListener.class.getSimpleName());
          }
      }
  
-     
      @Override
      public void onDetach() {
          setOnRefreshListener(null);
                  mJustFolders,
                  getActivity(),
                  mContainerActivity
-                 );
+         );
          setListAdapter(mAdapter);
  
          registerLongClickListener();
                  }
              }
  
-             FileActionsDialogFragment dialog = FileActionsDialogFragment.newInstance(menu, fileIndex);
+             FileActionsDialogFragment dialog = FileActionsDialogFragment.newInstance(menu, fileIndex, targetFile.getFileName());
              dialog.setTargetFragment(this, 0);
              dialog.show(getFragmentManager(), FileActionsDialogFragment.FTAG_FILE_ACTIONS);
          }
       * Saves the current listed folder.
       */
      @Override
-     public void onSaveInstanceState (Bundle outState) {
+     public void onSaveInstanceState(Bundle outState) {
          super.onSaveInstanceState(outState);
          outState.putParcelable(KEY_FILE, mFile);
      }
-     
      /**
       * Call this, when the user presses the up button.
-      * 
+      *
       * Tries to move up the current folder one level. If the parent folder was removed from the
       * database, it continues browsing up until finding an existing folders.
-      * 
+      * <p/>
       * return       Count of folder levels browsed up.
       */
      public int onBrowseUp() {
          OCFile parentDir = null;
          int moveCount = 0;
-         
-         if(mFile != null){
+         if (mFile != null) {
              FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
-             
              String parentPath = null;
              if (mFile.getParentId() != FileDataStorageManager.ROOT_PARENT_ID) {
                  parentPath = new File(mFile.getRemotePath()).getParent();
-                 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : 
-                       parentPath + OCFile.PATH_SEPARATOR;
+                 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath :
+                         parentPath + OCFile.PATH_SEPARATOR;
                  parentDir = storageManager.getFileByPath(parentPath);
                  moveCount++;
              } else {
              }
              while (parentDir == null) {
                  parentPath = new File(parentPath).getParent();
-                 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : 
-                       parentPath + OCFile.PATH_SEPARATOR;
+                 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath :
+                         parentPath + OCFile.PATH_SEPARATOR;
                  parentDir = storageManager.getFileByPath(parentPath);
                  moveCount++;
              }   // exit is granted because storageManager.getFileByPath("/") never returns null
              listDirectory(mFile /*, MainApp.getOnlyOnDevice()*/);
  
              onRefresh(false);
-             
              // restore index and top position
              restoreIndexAndTopPosition();
-             
          }   // else - should never happen now
-    
          return moveCount;
      }
-     
      @Override
      public void onItemClick(AdapterView<?> l, View v, int position, long id) {
          OCFile file = (OCFile) mAdapter.getItem(position);
          if (file != null) {
-             if (file.isFolder()) { 
+             if (file.isFolder()) {
                  // update state and view of this fragment
                  // TODO Enable when "On Device" is recovered ?
                  listDirectory(file/*, MainApp.getOnlyOnDevice()*/);
                  mContainerActivity.onBrowsedDownTo(file);
                  // save index and top position
                  saveIndexAndTopPosition(position);
-                 
              } else { /// Click on a file
                  if (PreviewImageFragment.canBePreviewed(file)) {
                      // preview image - it handles the download, if needed
                      ((FileDisplayActivity)mContainerActivity).startImagePreview(file);
-                     
+                 } else if (PreviewTextFragment.canBePreviewed(file)){
+                     ((FileDisplayActivity)mContainerActivity).startTextPreview(file);
                  } else if (file.isDown()) {
                      if (PreviewMediaFragment.canBePreviewed(file)) {
                          // media preview
-                         ((FileDisplayActivity)mContainerActivity).startMediaPreview(file, 0, true);
+                         ((FileDisplayActivity) mContainerActivity).startMediaPreview(file, 0, true);
                      } else {
                          mContainerActivity.getFileOperationsHelper().openFile(file);
                      }
-                     
                  } else {
                      // automatic download, preview on finish
-                     ((FileDisplayActivity)mContainerActivity).startDownloadForPreview(file);
+                     ((FileDisplayActivity) mContainerActivity).startDownloadForPreview(file);
                  }
-                     
              }
-             
          } else {
              Log_OC.d(TAG, "Null object in ListAdapter!!");
          }
-         
      }
-     
      /**
       * {@inheritDoc}
       */
      @Override
-     public void onCreateContextMenu (
+     public void onCreateContextMenu(
              ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
          Bundle args = getArguments();
-         boolean allowContextualActions = 
-                 (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true); 
+         boolean allowContextualActions =
+                 (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true);
          if (allowContextualActions) {
              MenuInflater inflater = getActivity().getMenuInflater();
              inflater.inflate(R.menu.file_actions_menu, menu);
              AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
              OCFile targetFile = (OCFile) mAdapter.getItem(info.position);
-             
              if (mContainerActivity.getStorageManager() != null) {
                  FileMenuFilter mf = new FileMenuFilter(
                      targetFile,
                      item.setEnabled(false);
                  }
              }
 +
 +//            String.format(mContext.getString(R.string.subject_token),
 +//                    getClient().getCredentials().getUsername(), file.getFileName()));
          }
      }
  
                  mContainerActivity.getFileOperationsHelper().toggleFavorite(mTargetFile, false);
                  return true;
              }
+             case R.id.action_copy:
+                 Intent action = new Intent(getActivity(), FolderPickerActivity.class);
+                 // Pass mTargetFile that contains info of selected file/folder
+                 action.putExtra(FolderPickerActivity.EXTRA_FILE, mTargetFile);
+                 getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_COPY_FILES);
+                 return true;
              default:
                  return false;
          }
      /**
       * Use this to query the {@link OCFile} that is currently
       * being displayed by this fragment
+      *
       * @return The currently viewed OCFile
       */
-     public OCFile getCurrentFile(){
+     public OCFile getCurrentFile() {
          return mFile;
      }
-     
      /**
       * Calls {@link OCFileListFragment#listDirectory(OCFile)} with a null parameter
       */
          // TODO Enable when "On Device" is recovered ?
          listDirectory(getCurrentFile()/*, MainApp.getOnlyOnDevice()*/);
      }
-     
      /**
       * Lists the given directory on the view. When the input parameter is null,
       * it will either refresh the last known directory. list the root
       * if there never was a directory.
-      * 
+      *
       * @param directory File to be listed
       */
      public void listDirectory(OCFile directory/*, boolean onlyOnDevice*/) {
          if (storageManager != null) {
  
              // Check input parameters for null
-             if(directory == null){
-                 if(mFile != null){
+             if (directory == null) {
+                 if (mFile != null) {
                      directory = mFile;
                  } else {
                      directory = storageManager.getFileByPath("/");
                  }
              }
  
-         
              // If that's not a directory -> List its parent
-             if(!directory.isFolder()){
+             if (!directory.isFolder()) {
                  Log_OC.w(TAG, "You see, that is not a directory -> " + directory.toString());
                  directory = storageManager.getFileById(directory.getParentId());
              }
                  if (file.isFolder()) {
                      foldersCount++;
                  } else {
-                     filesCount++;
-                     if (file.isImage()){
-                         imagesCount++;
+                     if (!file.isHidden()) {
+                         filesCount++;
+                         if (file.isImage()) {
+                             imagesCount++;
+                         }
                      }
                  }
              }
              OwnCloudVersion version = AccountUtils.getServerVersion(
                      ((FileActivity)mContainerActivity).getAccount());
              if (version != null && version.supportsRemoteThumbnails() &&
 -                imagesCount > 0 && imagesCount == filesCount) {
 +                    DisplayUtils.isGridView(mFile, mContainerActivity.getStorageManager())) {
                  switchToGridView();
                  registerLongClickListener();
              } else {
  \r
  package com.owncloud.android.utils;\r
  \r
 +import java.io.File;\r
 +import java.net.IDN;\r
 +import java.text.DateFormat;\r
 +import java.util.Arrays;\r
 +import java.util.Calendar;\r
 +import java.util.Date;\r
 +import java.util.HashMap;\r
 +import java.util.HashSet;\r
 +import java.util.Set;\r
 +import java.util.Vector;\r
 +\r
  import android.annotation.TargetApi;\r
  import android.app.Activity;\r
  import android.content.Context;\r
 +import android.content.SharedPreferences;\r
  import android.graphics.Point;\r
  import android.graphics.PorterDuff;\r
  import android.os.Build;\r
  import android.text.format.DateUtils;\r
  import android.view.Display;\r
- import android.webkit.MimeTypeMap;\r
  import android.widget.ProgressBar;\r
  import android.widget.SeekBar;\r
  \r
  import com.owncloud.android.MainApp;\r
  import com.owncloud.android.R;\r
 +import com.owncloud.android.datamodel.FileDataStorageManager;\r
  import com.owncloud.android.datamodel.OCFile;\r
  \r
+ import java.net.IDN;\r
+ import java.text.DateFormat;\r
+ import java.util.Calendar;\r
+ import java.util.Date;\r
+ import java.util.HashMap;\r
+ import java.util.Map;\r
\r
  /**\r
   * A helper class for some string operations.\r
   */\r
  public class DisplayUtils {\r
      \r
      private static final String OWNCLOUD_APP_NAME = "ownCloud";\r
\r
-     //private static String TAG = DisplayUtils.class.getSimpleName(); \r
      \r
      private static final String[] sizeSuffixes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };\r
  \r
-     private static HashMap<String, String> mimeType2HUmanReadable;\r
+     private static Map<String, String> mimeType2HumanReadable;\r
\r
      static {\r
-         mimeType2HUmanReadable = new HashMap<String, String>();\r
+         mimeType2HumanReadable = new HashMap<String, String>();\r
          // images\r
-         mimeType2HUmanReadable.put("image/jpeg", "JPEG image");\r
-         mimeType2HUmanReadable.put("image/jpg", "JPEG image");\r
-         mimeType2HUmanReadable.put("image/png", "PNG image");\r
-         mimeType2HUmanReadable.put("image/bmp", "Bitmap image");\r
-         mimeType2HUmanReadable.put("image/gif", "GIF image");\r
-         mimeType2HUmanReadable.put("image/svg+xml", "JPEG image");\r
-         mimeType2HUmanReadable.put("image/tiff", "TIFF image");\r
+         mimeType2HumanReadable.put("image/jpeg", "JPEG image");\r
+         mimeType2HumanReadable.put("image/jpg", "JPEG image");\r
+         mimeType2HumanReadable.put("image/png", "PNG image");\r
+         mimeType2HumanReadable.put("image/bmp", "Bitmap image");\r
+         mimeType2HumanReadable.put("image/gif", "GIF image");\r
+         mimeType2HumanReadable.put("image/svg+xml", "JPEG image");\r
+         mimeType2HumanReadable.put("image/tiff", "TIFF image");\r
          // music\r
-         mimeType2HUmanReadable.put("audio/mpeg", "MP3 music file");\r
-         mimeType2HUmanReadable.put("application/ogg", "OGG music file");\r
\r
+         mimeType2HumanReadable.put("audio/mpeg", "MP3 music file");\r
+         mimeType2HumanReadable.put("application/ogg", "OGG music file");\r
      }\r
  \r
-     private static final String TYPE_APPLICATION = "application";\r
-     private static final String TYPE_AUDIO = "audio";\r
-     private static final String TYPE_IMAGE = "image";\r
-     private static final String TYPE_TXT = "text";\r
-     private static final String TYPE_VIDEO = "video";\r
-     \r
-     private static final String SUBTYPE_PDF = "pdf";\r
-     private static final String SUBTYPE_XML = "xml";\r
-     private static final String[] SUBTYPES_DOCUMENT = { \r
-         "msword",\r
-         "vnd.openxmlformats-officedocument.wordprocessingml.document",\r
-         "vnd.oasis.opendocument.text",\r
-         "rtf",\r
-         "javascript"\r
-     };\r
-     private static Set<String> SUBTYPES_DOCUMENT_SET = new HashSet<String>(Arrays.asList(SUBTYPES_DOCUMENT));\r
-     private static final String[] SUBTYPES_SPREADSHEET = {\r
-         "msexcel",\r
-         "vnd.ms-excel",\r
-         "vnd.openxmlformats-officedocument.spreadsheetml.sheet",\r
-         "vnd.oasis.opendocument.spreadsheet"\r
-     };\r
-     private static Set<String> SUBTYPES_SPREADSHEET_SET = new HashSet<String>(Arrays.asList(SUBTYPES_SPREADSHEET));\r
-     private static final String[] SUBTYPES_PRESENTATION = { \r
-         "mspowerpoint",\r
-         "vnd.ms-powerpoint",\r
-         "vnd.openxmlformats-officedocument.presentationml.presentation",\r
-         "vnd.oasis.opendocument.presentation"\r
-     };\r
-     private static Set<String> SUBTYPES_PRESENTATION_SET = new HashSet<String>(Arrays.asList(SUBTYPES_PRESENTATION));\r
-     private static final String[] SUBTYPES_COMPRESSED = {"x-tar", "x-gzip", "zip"};\r
-     private static final Set<String> SUBTYPES_COMPRESSED_SET = new HashSet<String>(Arrays.asList(SUBTYPES_COMPRESSED));\r
-     private static final String SUBTYPE_OCTET_STREAM = "octet-stream";\r
-     private static final String EXTENSION_RAR = "rar";\r
-     private static final String EXTENSION_RTF = "rtf";\r
-     private static final String EXTENSION_3GP = "3gp";\r
-     private static final String EXTENSION_PY = "py";\r
-     private static final String EXTENSION_JS = "js";\r
-     \r
      /**\r
       * Converts the file size in bytes to human readable output.\r
       * \r
       * @return A human friendly version of the MIME type\r
       */\r
      public static String convertMIMEtoPrettyPrint(String mimetype) {\r
-         if (mimeType2HUmanReadable.containsKey(mimetype)) {\r
-             return mimeType2HUmanReadable.get(mimetype);\r
+         if (mimeType2HumanReadable.containsKey(mimetype)) {\r
+             return mimeType2HumanReadable.get(mimetype);\r
          }\r
          if (mimetype.split("/").length >= 2)\r
              return mimetype.split("/")[1].toUpperCase() + " file";\r
          return "Unknown type";\r
      }\r
-     \r
-     \r
-     /**\r
-      * Returns the resource identifier of an image to use as icon associated to a known MIME type.\r
-      * \r
-      * @param mimetype      MIME type string; if NULL, the method tries to guess it from the extension in filename\r
-      * @param filename      Name, with extension.\r
-      * @return              Identifier of an image resource.\r
-      */\r
-     public static int getFileTypeIconId(String mimetype, String filename) {\r
  \r
-         if (mimetype == null) {\r
-             String fileExtension = getExtension(filename);\r
-             mimetype = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension);\r
-             if (mimetype == null) {\r
-                 mimetype = TYPE_APPLICATION + "/" + SUBTYPE_OCTET_STREAM;\r
-             }\r
-         } \r
-             \r
-         if ("DIR".equals(mimetype)) {\r
-             return R.drawable.ic_menu_archive;\r
\r
-         } else {\r
-             String [] parts = mimetype.split("/");\r
-             String type = parts[0];\r
-             String subtype = (parts.length > 1) ? parts[1] : "";\r
-             \r
-             if(TYPE_TXT.equals(type)) {\r
-                 return R.drawable.file_doc;\r
-     \r
-             } else if(TYPE_IMAGE.equals(type)) {\r
-                 return R.drawable.file_image;\r
-                 \r
-             } else if(TYPE_VIDEO.equals(type)) {\r
-                 return R.drawable.file_movie;\r
-                 \r
-             } else if(TYPE_AUDIO.equals(type)) {  \r
-                 return R.drawable.file_sound;\r
-                 \r
-             } else if(TYPE_APPLICATION.equals(type)) {\r
-                 \r
-                 if (SUBTYPE_PDF.equals(subtype)) {\r
-                     return R.drawable.file_pdf;\r
-                     \r
-                 } else if (SUBTYPE_XML.equals(subtype)) {\r
-                     return R.drawable.file_doc;\r
\r
-                 } else if (SUBTYPES_DOCUMENT_SET.contains(subtype)) {\r
-                     return R.drawable.file_doc;\r
\r
-                 } else if (SUBTYPES_SPREADSHEET_SET.contains(subtype)) {\r
-                     return R.drawable.file_xls;\r
\r
-                 } else if (SUBTYPES_PRESENTATION_SET.contains(subtype)) {\r
-                     return R.drawable.file_ppt;\r
\r
-                 } else if (SUBTYPES_COMPRESSED_SET.contains(subtype)) {\r
-                     return R.drawable.file_zip;\r
\r
-                 } else if (SUBTYPE_OCTET_STREAM.equals(subtype) ) {\r
-                     if (getExtension(filename).equalsIgnoreCase(EXTENSION_RAR)) {\r
-                         return R.drawable.file_zip;\r
-                         \r
-                     } else if (getExtension(filename).equalsIgnoreCase(EXTENSION_RTF)) {\r
-                         return R.drawable.file_doc;\r
-                         \r
-                     } else if (getExtension(filename).equalsIgnoreCase(EXTENSION_3GP)) {\r
-                         return R.drawable.file_movie;\r
-                      \r
-                     } else if ( getExtension(filename).equalsIgnoreCase(EXTENSION_PY) ||\r
-                                 getExtension(filename).equalsIgnoreCase(EXTENSION_JS)) {\r
-                         return R.drawable.file_doc;\r
-                     } \r
-                 } \r
-             }\r
-         }\r
\r
-         // default icon\r
-         return R.drawable.file;\r
-     }\r
\r
-     \r
-     private static String getExtension(String filename) {\r
-         String extension = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();\r
-         return extension;\r
-     }\r
-     \r
      /**\r
       * Converts Unix time to human readable format\r
       * @param milliseconds that have passed since 01/01/1970\r
          return df.format(date);\r
      }\r
      \r
-     \r
      public static int getSeasonalIconId() {\r
          if (Calendar.getInstance().get(Calendar.DAY_OF_YEAR) >= 354 &&\r
                  MainApp.getAppContext().getString(R.string.app_name).equals(OWNCLOUD_APP_NAME)) {\r
      }\r
  \r
      /**\r
 +     * Determines if user set folder to grid or list view. If folder is not set itself,\r
 +     * it finds a parent that is set (at least root is set).\r
 +     * @param file\r
 +     * @param storageManager\r
 +     * @return\r
 +     */\r
 +    public static boolean isGridView(OCFile file, FileDataStorageManager storageManager){\r
 +        if (file != null) {\r
 +            OCFile fileToTest = file;\r
 +            OCFile parentDir = null;\r
 +            String parentPath = null;\r
 +\r
 +            SharedPreferences setting = MainApp.getAppContext().getSharedPreferences(\r
 +                    "viewMode", Context.MODE_PRIVATE);\r
 +\r
 +            if (setting.contains(fileToTest.getRemoteId())) {\r
 +                return setting.getBoolean(fileToTest.getRemoteId(), false);\r
 +            } else {\r
 +                do {\r
 +                    if (fileToTest.getParentId() != FileDataStorageManager.ROOT_PARENT_ID) {\r
 +                        parentPath = new File(fileToTest.getRemotePath()).getParent();\r
 +                        parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath :\r
 +                                parentPath + OCFile.PATH_SEPARATOR;\r
 +                        parentDir = storageManager.getFileByPath(parentPath);\r
 +                    } else {\r
 +                        parentDir = storageManager.getFileByPath(OCFile.ROOT_PATH);\r
 +                    }\r
 +\r
 +                    while (parentDir == null) {\r
 +                        parentPath = new File(parentPath).getParent();\r
 +                        parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath :\r
 +                                parentPath + OCFile.PATH_SEPARATOR;\r
 +                        parentDir = storageManager.getFileByPath(parentPath);\r
 +                    }\r
 +                    fileToTest = parentDir;\r
 +                } while (endWhile(parentDir, setting));\r
 +                return setting.getBoolean(fileToTest.getRemoteId(), false);\r
 +            }\r
 +        } else {\r
 +            return false;\r
 +        }\r
 +    }\r
 +\r
 +    private static boolean endWhile(OCFile parentDir, SharedPreferences setting) {\r
 +        if (parentDir.getRemotePath().compareToIgnoreCase(OCFile.ROOT_PATH) == 0) {\r
 +            return false;\r
 +        } else {\r
 +            return !setting.contains(parentDir.getRemoteId());\r
 +        }\r
 +    }\r
 +\r
 +    public static void setViewMode(OCFile file, boolean setGrid){\r
 +        SharedPreferences setting = MainApp.getAppContext().getSharedPreferences(\r
 +                "viewMode", Context.MODE_PRIVATE);\r
 +\r
 +        SharedPreferences.Editor editor = setting.edit();\r
 +        editor.putBoolean(file.getRemoteId(), setGrid);\r
 +        editor.commit();\r
 +    }\r
 +\r
 +    /**\r
       * sets the coloring of the given progress bar to color_accent.\r
       *\r
       * @param progressBar the progress bar to be colored\r