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 31using content::BrowserThread; 32using fileapi::FileSystemURL; 33 34namespace file_manager { 35namespace util { 36namespace { 37 38// Shows a warning message box saying that the file could not be opened. 39void 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|. 54void 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. 76void 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). 93bool 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(). 126void 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. 149bool 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 170void 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 181void 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 195void 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