Home | History | Annotate | Download | only in file_manager
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/file_manager/open_util.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/files/file_path.h"
      9 #include "base/logging.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "chrome/browser/chromeos/drive/file_system_util.h"
     12 #include "chrome/browser/chromeos/file_manager/app_id.h"
     13 #include "chrome/browser/chromeos/file_manager/file_tasks.h"
     14 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
     15 #include "chrome/browser/chromeos/file_manager/path_util.h"
     16 #include "chrome/browser/chromeos/file_manager/url_util.h"
     17 #include "chrome/browser/extensions/api/file_handlers/mime_util.h"
     18 #include "chrome/browser/ui/browser.h"
     19 #include "chrome/browser/ui/browser_finder.h"
     20 #include "chrome/browser/ui/browser_window.h"
     21 #include "chrome/browser/ui/simple_message_box.h"
     22 #include "chrome/grit/generated_resources.h"
     23 #include "content/public/browser/browser_thread.h"
     24 #include "content/public/browser/user_metrics.h"
     25 #include "storage/browser/fileapi/file_system_backend.h"
     26 #include "storage/browser/fileapi/file_system_context.h"
     27 #include "storage/browser/fileapi/file_system_operation_runner.h"
     28 #include "storage/browser/fileapi/file_system_url.h"
     29 #include "ui/base/l10n/l10n_util.h"
     30 
     31 using content::BrowserThread;
     32 using storage::FileSystemURL;
     33 
     34 namespace file_manager {
     35 namespace util {
     36 namespace {
     37 
     38 // Shows a warning message box saying that the file could not be opened.
     39 void ShowWarningMessageBox(Profile* profile,
     40                            const base::FilePath& file_path,
     41                            int message_id) {
     42   Browser* browser = chrome::FindTabbedBrowser(
     43       profile, false, chrome::HOST_DESKTOP_TYPE_ASH);
     44   chrome::ShowMessageBox(
     45       browser ? browser->window()->GetNativeWindow() : NULL,
     46       l10n_util::GetStringFUTF16(
     47           IDS_FILE_BROWSER_ERROR_VIEWING_FILE_TITLE,
     48           base::UTF8ToUTF16(file_path.BaseName().AsUTF8Unsafe())),
     49       l10n_util::GetStringUTF16(message_id),
     50       chrome::MESSAGE_BOX_TYPE_WARNING);
     51 }
     52 
     53 // Executes the |task| for the file specified by |url|.
     54 void ExecuteFileTaskForUrl(Profile* profile,
     55                            const file_tasks::TaskDescriptor& task,
     56                            const GURL& url) {
     57   storage::FileSystemContext* file_system_context =
     58       GetFileSystemContextForExtensionId(profile, kFileManagerAppId);
     59 
     60   file_tasks::ExecuteFileTask(
     61       profile,
     62       GetFileManagerMainPageUrl(), // Executing the task on behalf of Files.app.
     63       task,
     64       std::vector<FileSystemURL>(1, file_system_context->CrackURL(url)),
     65       file_tasks::FileTaskFinishedCallback());
     66 }
     67 
     68 // Opens the file manager for the specified |url|. Used to implement
     69 // internal handlers of special action IDs:
     70 //
     71 // "open" - Open the file manager for the given folder.
     72 // "auto-open" - Open the file manager for the given removal drive and close
     73 //               the file manager when the removal drive is unmounted.
     74 // "select" - Open the file manager for the given file. The folder containing
     75 //            the file will be opened with the file selected.
     76 void OpenFileManagerWithInternalActionId(Profile* profile,
     77                                          const GURL& url,
     78                                          const std::string& action_id) {
     79   DCHECK(action_id == "auto-open" ||
     80          action_id == "open" ||
     81          action_id == "select");
     82   content::RecordAction(base::UserMetricsAction("ShowFileBrowserFullTab"));
     83 
     84   file_tasks::TaskDescriptor task(kFileManagerAppId,
     85                                   file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER,
     86                                   action_id);
     87   ExecuteFileTaskForUrl(profile, task, url);
     88 }
     89 
     90 // Opens the file with fetched MIME type and calls the callback.
     91 void OpenFileWithMimeType(Profile* profile,
     92                           const base::FilePath& path,
     93                           const GURL& url,
     94                           const base::Callback<void(bool)>& callback,
     95                           const std::string& mime_type) {
     96   extensions::app_file_handler_util::PathAndMimeTypeSet path_mime_set;
     97   path_mime_set.insert(std::make_pair(path, mime_type));
     98 
     99   std::vector<GURL> file_urls;
    100   file_urls.push_back(url);
    101 
    102   std::vector<file_tasks::FullTaskDescriptor> tasks;
    103   file_tasks::FindAllTypesOfTasks(
    104       profile,
    105       drive::util::GetDriveAppRegistryByProfile(profile),
    106       path_mime_set,
    107       file_urls,
    108       &tasks);
    109 
    110   if (tasks.empty()) {
    111     callback.Run(false);
    112     return;
    113   }
    114 
    115   const file_tasks::FullTaskDescriptor* chosen_task = &tasks[0];
    116   for (size_t i = 0; i < tasks.size(); ++i) {
    117     if (tasks[i].is_default()) {
    118       chosen_task = &tasks[i];
    119       break;
    120     }
    121   }
    122 
    123   ExecuteFileTaskForUrl(profile, chosen_task->task_descriptor(), url);
    124   callback.Run(true);
    125 }
    126 
    127 // Opens the file specified by |url| by finding and executing a file task for
    128 // the file. In case of success, calls |callback| with true. Otherwise the
    129 // returned value is false.
    130 void OpenFile(Profile* profile,
    131               const base::FilePath& path,
    132               const GURL& url,
    133               const base::Callback<void(bool)>& callback) {
    134   extensions::app_file_handler_util::GetMimeTypeForLocalPath(
    135       profile,
    136       path,
    137       base::Bind(&OpenFileWithMimeType, profile, path, url, callback));
    138 }
    139 
    140 // Called when execution of ContinueOpenItem() is completed.
    141 void OnContinueOpenItemCompleted(Profile* profile,
    142                                  const base::FilePath& file_path,
    143                                  bool result) {
    144   if (!result) {
    145     int message;
    146     if (file_path.Extension() == FILE_PATH_LITERAL(".dmg"))
    147       message = IDS_FILE_BROWSER_ERROR_VIEWING_FILE_FOR_DMG;
    148     else if (file_path.Extension() == FILE_PATH_LITERAL(".exe") ||
    149              file_path.Extension() == FILE_PATH_LITERAL(".msi"))
    150       message = IDS_FILE_BROWSER_ERROR_VIEWING_FILE_FOR_EXECUTABLE;
    151     else
    152       message = IDS_FILE_BROWSER_ERROR_VIEWING_FILE;
    153     ShowWarningMessageBox(profile, file_path, message);
    154   }
    155 }
    156 
    157 // Used to implement OpenItem().
    158 void ContinueOpenItem(Profile* profile,
    159                       const base::FilePath& file_path,
    160                       const GURL& url,
    161                       base::File::Error error) {
    162   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    163 
    164   if (error == base::File::FILE_OK) {
    165     // A directory exists at |url|. Open it with the file manager.
    166     OpenFileManagerWithInternalActionId(profile, url, "open");
    167   } else {
    168     // |url| should be a file. Open it.
    169     OpenFile(profile,
    170              file_path,
    171              url,
    172              base::Bind(&OnContinueOpenItemCompleted, profile, file_path));
    173   }
    174 }
    175 
    176 // Converts the |given_path| passed from external callers to the form that the
    177 // file manager can correctly handle. It first migrates old Drive/Download
    178 // folder path to the new formats, and then converts path to filesystem URL.
    179 //
    180 // When conversion fails, it shows a warning dialog UI and returns false.
    181 bool ConvertPath(Profile* profile,
    182                  const base::FilePath& given_path,
    183                  base::FilePath* path,
    184                  GURL* url) {
    185   // The path may have been stored in preferences in old versions.
    186   // We need migration here.
    187   // TODO(kinaba): crbug.com/313539 remove it in the future.
    188   if (!util::MigratePathFromOldFormat(profile, given_path, path))
    189     *path = given_path;
    190 
    191   if (!ConvertAbsoluteFilePathToFileSystemUrl(
    192           profile, *path, kFileManagerAppId, url)) {
    193     ShowWarningMessageBox(profile, *path,
    194                           IDS_FILE_BROWSER_ERROR_UNRESOLVABLE_FILE);
    195     return false;
    196   }
    197   return true;
    198 }
    199 
    200 }  // namespace
    201 
    202 void OpenRemovableDrive(Profile* profile, const base::FilePath& file_path) {
    203   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    204 
    205   base::FilePath converted_path;
    206   GURL url;
    207   if (!ConvertPath(profile, file_path, &converted_path, &url))
    208     return;
    209 
    210   OpenFileManagerWithInternalActionId(profile, url, "auto-open");
    211 }
    212 
    213 void OpenItem(Profile* profile, const base::FilePath& file_path) {
    214   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    215 
    216   base::FilePath converted_path;
    217   GURL url;
    218   if (!ConvertPath(profile, file_path, &converted_path, &url))
    219     return;
    220 
    221   CheckIfDirectoryExists(
    222       GetFileSystemContextForExtensionId(profile, kFileManagerAppId),
    223       url,
    224       base::Bind(&ContinueOpenItem, profile, converted_path, url));
    225 }
    226 
    227 void ShowItemInFolder(Profile* profile, const base::FilePath& file_path) {
    228   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    229 
    230   base::FilePath converted_path;
    231   GURL url;
    232   if (!ConvertPath(profile, file_path, &converted_path, &url))
    233     return;
    234 
    235   // This action changes the selection so we do not reuse existing tabs.
    236   OpenFileManagerWithInternalActionId(profile, url, "select");
    237 }
    238 
    239 }  // namespace util
    240 }  // namespace file_manager
    241