• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
ShowWarningMessageBox(Profile * profile,const base::FilePath & file_path,int message_id)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|.
ExecuteFileTaskForUrl(Profile * profile,const file_tasks::TaskDescriptor & task,const GURL & 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.
OpenFileManagerWithInternalActionId(Profile * profile,const GURL & url,const std::string & action_id)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).
OpenFile(Profile * profile,const base::FilePath & path,const GURL & url)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().
ContinueOpenItem(Profile * profile,const base::FilePath & file_path,const GURL & url,base::File::Error error)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.
ConvertPath(Profile * profile,const base::FilePath & given_path,base::FilePath * path,GURL * url)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 
OpenRemovableDrive(Profile * profile,const base::FilePath & file_path)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 
OpenItem(Profile * profile,const base::FilePath & file_path)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 
ShowItemInFolder(Profile * profile,const base::FilePath & file_path)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