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.
5 #include "chrome/browser/chromeos/file_manager/open_util.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 "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"
31 using content::BrowserThread;
32 using fileapi::FileSystemURL;
34 namespace file_manager {
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,
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);
53 // Executes the |task| for the file specified by |url|.
54 void ExecuteFileTaskForUrl(Profile* profile,
55 const file_tasks::TaskDescriptor& task,
57 fileapi::FileSystemContext* file_system_context =
58 GetFileSystemContextForExtensionId(profile, kFileManagerAppId);
60 file_tasks::ExecuteFileTask(
62 GetFileManagerMainPageUrl(), // Executing the task on behalf of Files.app.
64 std::vector<FileSystemURL>(1, file_system_context->CrackURL(url)),
65 file_tasks::FileTaskFinishedCallback());
68 // Opens the file manager for the specified |url|. Used to implement
69 // internal handlers of special action IDs:
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,
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"));
84 file_tasks::TaskDescriptor task(kFileManagerAppId,
85 file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER,
87 ExecuteFileTaskForUrl(profile, task, url);
90 // Opens the file with fetched MIME type and calls the callback.
91 void OpenFileWithMimeType(Profile* profile,
92 const base::FilePath& path,
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));
99 std::vector<GURL> file_urls;
100 file_urls.push_back(url);
102 std::vector<file_tasks::FullTaskDescriptor> tasks;
103 file_tasks::FindAllTypesOfTasks(
105 drive::util::GetDriveAppRegistryByProfile(profile),
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];
123 ExecuteFileTaskForUrl(profile, chosen_task->task_descriptor(), url);
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,
133 const base::Callback<void(bool)>& callback) {
134 extensions::app_file_handler_util::GetMimeTypeForLocalPath(
137 base::Bind(&OpenFileWithMimeType, profile, path, url, callback));
140 // Called when execution of ContinueOpenItem() is completed.
141 void OnContinueOpenItemCompleted(Profile* profile,
142 const base::FilePath& file_path,
145 ShowWarningMessageBox(
146 profile, file_path, IDS_FILE_BROWSER_ERROR_VIEWING_FILE);
150 // Used to implement OpenItem().
151 void ContinueOpenItem(Profile* profile,
152 const base::FilePath& file_path,
154 base::File::Error error) {
155 DCHECK_CURRENTLY_ON(BrowserThread::UI);
157 if (error == base::File::FILE_OK) {
158 // A directory exists at |url|. Open it with the file manager.
159 OpenFileManagerWithInternalActionId(profile, url, "open");
161 // |url| should be a file. Open it.
165 base::Bind(&OnContinueOpenItemCompleted, profile, file_path));
169 // Converts the |given_path| passed from external callers to the form that the
170 // file manager can correctly handle. It first migrates old Drive/Download
171 // folder path to the new formats, and then converts path to filesystem URL.
173 // When conversion fails, it shows a warning dialog UI and returns false.
174 bool ConvertPath(Profile* profile,
175 const base::FilePath& given_path,
176 base::FilePath* path,
178 // The path may have been stored in preferences in old versions.
179 // We need migration here.
180 // TODO(kinaba): crbug.com/313539 remove it in the future.
181 if (!util::MigratePathFromOldFormat(profile, given_path, path))
184 if (!ConvertAbsoluteFilePathToFileSystemUrl(
185 profile, *path, kFileManagerAppId, url)) {
186 ShowWarningMessageBox(profile, *path,
187 IDS_FILE_BROWSER_ERROR_UNRESOLVABLE_FILE);
195 void OpenRemovableDrive(Profile* profile, const base::FilePath& file_path) {
196 DCHECK_CURRENTLY_ON(BrowserThread::UI);
198 base::FilePath converted_path;
200 if (!ConvertPath(profile, file_path, &converted_path, &url))
203 OpenFileManagerWithInternalActionId(profile, url, "auto-open");
206 void OpenItem(Profile* profile, const base::FilePath& file_path) {
207 DCHECK_CURRENTLY_ON(BrowserThread::UI);
209 base::FilePath converted_path;
211 if (!ConvertPath(profile, file_path, &converted_path, &url))
214 CheckIfDirectoryExists(
215 GetFileSystemContextForExtensionId(profile, kFileManagerAppId),
217 base::Bind(&ContinueOpenItem, profile, converted_path, url));
220 void ShowItemInFolder(Profile* profile, const base::FilePath& file_path) {
221 DCHECK_CURRENTLY_ON(BrowserThread::UI);
223 base::FilePath converted_path;
225 if (!ConvertPath(profile, file_path, &converted_path, &url))
228 // This action changes the selection so we do not reuse existing tabs.
229 OpenFileManagerWithInternalActionId(profile, url, "select");
233 } // namespace file_manager