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/mime_util.h"
     16 #include "chrome/browser/chromeos/file_manager/path_util.h"
     17 #include "chrome/browser/chromeos/file_manager/url_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 "content/public/browser/browser_thread.h"
     23 #include "content/public/browser/user_metrics.h"
     24 #include "grit/generated_resources.h"
     25 #include "ui/base/l10n/l10n_util.h"
     26 #include "webkit/browser/fileapi/file_system_backend.h"
     27 #include "webkit/browser/fileapi/file_system_context.h"
     28 #include "webkit/browser/fileapi/file_system_operation_runner.h"
     29 #include "webkit/browser/fileapi/file_system_url.h"
     30 
     31 using content::BrowserThread;
     32 using fileapi::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   fileapi::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 specified by |url| by finding and executing a file
     91 // task for the file. Returns false if failed to open the file (i.e. no file
     92 // task is found).
     93 bool OpenFile(Profile* profile, const base::FilePath& path, const GURL& url) {
     94   // The file is opened per the file extension, hence extension-less files
     95   // cannot be opened properly.
     96   std::string mime_type = GetMimeTypeForPath(path);
     97   extensions::app_file_handler_util::PathAndMimeTypeSet path_mime_set;
     98   path_mime_set.insert(std::make_pair(path, mime_type));
     99 
    100   std::vector<GURL> file_urls;
    101   file_urls.push_back(url);
    102 
    103   std::vector<file_tasks::FullTaskDescriptor> tasks;
    104   file_tasks::FindAllTypesOfTasks(
    105       profile,
    106       drive::util::GetDriveAppRegistryByProfile(profile),
    107       path_mime_set,
    108       file_urls,
    109       &tasks);
    110   if (tasks.empty())
    111     return false;
    112 
    113   const file_tasks::FullTaskDescriptor* chosen_task = &tasks[0];
    114   for (size_t i = 0; i < tasks.size(); ++i) {
    115     if (tasks[i].is_default()) {
    116       chosen_task = &tasks[i];
    117       break;
    118     }
    119   }
    120 
    121   ExecuteFileTaskForUrl(profile, chosen_task->task_descriptor(), url);
    122   return true;
    123 }
    124 
    125 // Used to implement OpenItem().
    126 void ContinueOpenItem(Profile* profile,
    127                       const base::FilePath& file_path,
    128                       const GURL& url,
    129                       base::File::Error error) {
    130   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    131 
    132   if (error == base::File::FILE_OK) {
    133     // A directory exists at |url|. Open it with the file manager.
    134     OpenFileManagerWithInternalActionId(profile, url, "open");
    135   } else {
    136     // |url| should be a file. Open it.
    137     if (!OpenFile(profile, file_path, url)) {
    138       ShowWarningMessageBox(profile, file_path,
    139                             IDS_FILE_BROWSER_ERROR_VIEWING_FILE);
    140     }
    141   }
    142 }
    143 
    144 // Converts the |given_path| passed from external callers to the form that the
    145 // file manager can correctly handle. It first migrates old Drive/Download
    146 // folder path to the new formats, and then converts path to filesystem URL.
    147 //
    148 // When conversion fails, it shows a warning dialog UI and returns false.
    149 bool ConvertPath(Profile* profile,
    150                  const base::FilePath& given_path,
    151                  base::FilePath* path,
    152                  GURL* url) {
    153   // The path may have been stored in preferences in old versions.
    154   // We need migration here.
    155   // TODO(kinaba): crbug.com/313539 remove it in the future.
    156   if (!util::MigratePathFromOldFormat(profile, given_path, path))
    157     *path = given_path;
    158 
    159   if (!ConvertAbsoluteFilePathToFileSystemUrl(
    160           profile, *path, kFileManagerAppId, url)) {
    161     ShowWarningMessageBox(profile, *path,
    162                           IDS_FILE_BROWSER_ERROR_UNRESOLVABLE_FILE);
    163     return false;
    164   }
    165   return true;
    166 }
    167 
    168 }  // namespace
    169 
    170 void OpenRemovableDrive(Profile* profile, const base::FilePath& file_path) {
    171   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    172 
    173   base::FilePath converted_path;
    174   GURL url;
    175   if (!ConvertPath(profile, file_path, &converted_path, &url))
    176     return;
    177 
    178   OpenFileManagerWithInternalActionId(profile, url, "auto-open");
    179 }
    180 
    181 void OpenItem(Profile* profile, const base::FilePath& file_path) {
    182   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    183 
    184   base::FilePath converted_path;
    185   GURL url;
    186   if (!ConvertPath(profile, file_path, &converted_path, &url))
    187     return;
    188 
    189   CheckIfDirectoryExists(
    190       GetFileSystemContextForExtensionId(profile, kFileManagerAppId),
    191       url,
    192       base::Bind(&ContinueOpenItem, profile, converted_path, url));
    193 }
    194 
    195 void ShowItemInFolder(Profile* profile, const base::FilePath& file_path) {
    196   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    197 
    198   base::FilePath converted_path;
    199   GURL url;
    200   if (!ConvertPath(profile, file_path, &converted_path, &url))
    201     return;
    202 
    203   // This action changes the selection so we do not reuse existing tabs.
    204   OpenFileManagerWithInternalActionId(profile, url, "select");
    205 }
    206 
    207 }  // namespace util
    208 }  // namespace file_manager
    209