Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(336)

Side by Side Diff: chrome/browser/ui/gtk/select_file_dialog_impl_kde.cc

Issue 10790083: shell dialogs: Move the linux implementations. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase to tot Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/ui/gtk/select_file_dialog_impl_gtk.cc ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 <set>
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/logging.h"
11 #include "base/nix/mime_util_xdg.h"
12 #include "base/nix/xdg_util.h"
13 #include "base/process_util.h"
14 #include "base/string_number_conversions.h"
15 #include "base/string_util.h"
16 #include "base/threading/thread_restrictions.h"
17 #include "base/utf_string_conversions.h"
18 #include "chrome/browser/ui/gtk/select_file_dialog_impl.h"
19
20 // TODO(erg): Move all of this into WorkerPool.
21 #include "content/public/browser/browser_thread.h"
22 #include "grit/generated_resources.h"
23 #include "ui/base/l10n/l10n_util.h"
24
25 // These conflict with base/tracked_objects.h, so need to come last.
26 #include <gdk/gdkx.h>
27 #include <gtk/gtk.h>
28
29 using content::BrowserThread;
30
31 namespace {
32
33 std::string GetTitle(const std::string& title, int message_id) {
34 return title.empty() ? l10n_util::GetStringUTF8(message_id) : title;
35 }
36
37 const char kKdialogBinary[] = "kdialog";
38
39 } // namespace
40
41 // Implementation of SelectFileDialog that shows a KDE common dialog for
42 // choosing a file or folder. This acts as a modal dialog.
43 class SelectFileDialogImplKDE : public SelectFileDialogImpl {
44 public:
45 SelectFileDialogImplKDE(Listener* listener,
46 ui::SelectFilePolicy* policy,
47 base::nix::DesktopEnvironment desktop);
48
49 protected:
50 virtual ~SelectFileDialogImplKDE();
51
52 // SelectFileDialog implementation.
53 // |params| is user data we pass back via the Listener interface.
54 virtual void SelectFileImpl(Type type,
55 const string16& title,
56 const FilePath& default_path,
57 const FileTypeInfo* file_types,
58 int file_type_index,
59 const FilePath::StringType& default_extension,
60 gfx::NativeWindow owning_window,
61 void* params) OVERRIDE;
62
63 private:
64 virtual bool HasMultipleFileTypeChoicesImpl() OVERRIDE;
65
66 struct KDialogParams {
67 KDialogParams(const std::string& type, const std::string& title,
68 const FilePath& default_path, gfx::NativeWindow parent,
69 bool file_operation, bool multiple_selection,
70 void* kdialog_params,
71 void (SelectFileDialogImplKDE::*callback)(const std::string&,
72 int, void*))
73 : type(type), title(title), default_path(default_path), parent(parent),
74 file_operation(file_operation),
75 multiple_selection(multiple_selection),
76 kdialog_params(kdialog_params), callback(callback) {
77 }
78
79 std::string type;
80 std::string title;
81 FilePath default_path;
82 gfx::NativeWindow parent;
83 bool file_operation;
84 bool multiple_selection;
85 void* kdialog_params;
86 void (SelectFileDialogImplKDE::*callback)(const std::string&, int, void*);
87 };
88
89 // Get the filters from |file_types_| and concatenate them into
90 // |filter_string|.
91 std::string GetMimeTypeFilterString();
92
93 // Get KDialog command line representing the Argv array for KDialog.
94 void GetKDialogCommandLine(const std::string& type, const std::string& title,
95 const FilePath& default_path, gfx::NativeWindow parent,
96 bool file_operation, bool multiple_selection, CommandLine* command_line);
97
98 // Call KDialog on the FILE thread and post results back to the UI thread.
99 void CallKDialogOutput(const KDialogParams& params);
100
101 // Notifies the listener that a single file was chosen.
102 void FileSelected(const FilePath& path, void* params);
103
104 // Notifies the listener that multiple files were chosen.
105 void MultiFilesSelected(const std::vector<FilePath>& files, void* params);
106
107 // Notifies the listener that no file was chosen (the action was canceled).
108 // Dialog is passed so we can find that |params| pointer that was passed to
109 // us when we were told to show the dialog.
110 void FileNotSelected(void *params);
111
112 void CreateSelectFolderDialog(const std::string& title,
113 const FilePath& default_path,
114 gfx::NativeWindow parent, void* params);
115
116 void CreateFileOpenDialog(const std::string& title,
117 const FilePath& default_path,
118 gfx::NativeWindow parent, void* params);
119
120 void CreateMultiFileOpenDialog(const std::string& title,
121 const FilePath& default_path,
122 gfx::NativeWindow parent, void* params);
123
124 void CreateSaveAsDialog(const std::string& title,
125 const FilePath& default_path,
126 gfx::NativeWindow parent, void* params);
127
128 // Common function for OnSelectSingleFileDialogResponse and
129 // OnSelectSingleFolderDialogResponse.
130 void SelectSingleFileHelper(const std::string& output, int exit_code,
131 void* params, bool allow_folder);
132
133 void OnSelectSingleFileDialogResponse(const std::string& output,
134 int exit_code, void* params);
135 void OnSelectMultiFileDialogResponse(const std::string& output,
136 int exit_code, void* params);
137 void OnSelectSingleFolderDialogResponse(const std::string& output,
138 int exit_code, void* params);
139
140 // Should be either DESKTOP_ENVIRONMENT_KDE3 or DESKTOP_ENVIRONMENT_KDE4.
141 base::nix::DesktopEnvironment desktop_;
142
143 DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImplKDE);
144 };
145
146 // static
147 bool SelectFileDialogImpl::CheckKDEDialogWorksOnUIThread() {
148 // No choice. UI thread can't continue without an answer here. Fortunately we
149 // only do this once, the first time a file dialog is displayed.
150 base::ThreadRestrictions::ScopedAllowIO allow_io;
151
152 CommandLine::StringVector cmd_vector;
153 cmd_vector.push_back(kKdialogBinary);
154 cmd_vector.push_back("--version");
155 CommandLine command_line(cmd_vector);
156 std::string dummy;
157 return base::GetAppOutput(command_line, &dummy);
158 }
159
160 // static
161 SelectFileDialogImpl* SelectFileDialogImpl::NewSelectFileDialogImplKDE(
162 Listener* listener,
163 ui::SelectFilePolicy* policy,
164 base::nix::DesktopEnvironment desktop) {
165 return new SelectFileDialogImplKDE(listener, policy, desktop);
166 }
167
168 SelectFileDialogImplKDE::SelectFileDialogImplKDE(
169 Listener* listener,
170 ui::SelectFilePolicy* policy,
171 base::nix::DesktopEnvironment desktop)
172 : SelectFileDialogImpl(listener, policy),
173 desktop_(desktop) {
174 DCHECK(desktop_ == base::nix::DESKTOP_ENVIRONMENT_KDE3 ||
175 desktop_ == base::nix::DESKTOP_ENVIRONMENT_KDE4);
176 }
177
178 SelectFileDialogImplKDE::~SelectFileDialogImplKDE() {
179 }
180
181 // We ignore |default_extension|.
182 void SelectFileDialogImplKDE::SelectFileImpl(
183 Type type,
184 const string16& title,
185 const FilePath& default_path,
186 const FileTypeInfo* file_types,
187 int file_type_index,
188 const FilePath::StringType& default_extension,
189 gfx::NativeWindow owning_window,
190 void* params) {
191 type_ = type;
192 // |owning_window| can be null when user right-clicks on a downloadable item
193 // and chooses 'Open Link in New Tab' when 'Ask where to save each file
194 // before downloading.' preference is turned on. (http://crbug.com/29213)
195 if (owning_window)
196 parents_.insert(owning_window);
197
198 std::string title_string = UTF16ToUTF8(title);
199
200 file_type_index_ = file_type_index;
201 if (file_types)
202 file_types_ = *file_types;
203 else
204 file_types_.include_all_files = true;
205
206 switch (type) {
207 case SELECT_FOLDER:
208 CreateSelectFolderDialog(title_string, default_path,
209 owning_window, params);
210 return;
211 case SELECT_OPEN_FILE:
212 CreateFileOpenDialog(title_string, default_path, owning_window,
213 params);
214 return;
215 case SELECT_OPEN_MULTI_FILE:
216 CreateMultiFileOpenDialog(title_string, default_path,
217 owning_window, params);
218 return;
219 case SELECT_SAVEAS_FILE:
220 CreateSaveAsDialog(title_string, default_path, owning_window,
221 params);
222 return;
223 default:
224 NOTREACHED();
225 return;
226 }
227 }
228
229 bool SelectFileDialogImplKDE::HasMultipleFileTypeChoicesImpl() {
230 return file_types_.extensions.size() > 1;
231 }
232
233 std::string SelectFileDialogImplKDE::GetMimeTypeFilterString() {
234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
235 std::string filter_string;
236 // We need a filter set because the same mime type can appear multiple times.
237 std::set<std::string> filter_set;
238 for (size_t i = 0; i < file_types_.extensions.size(); ++i) {
239 for (size_t j = 0; j < file_types_.extensions[i].size(); ++j) {
240 if (!file_types_.extensions[i][j].empty()) {
241 std::string mime_type = base::nix::GetFileMimeType(
242 FilePath("name").ReplaceExtension(file_types_.extensions[i][j]));
243 filter_set.insert(mime_type);
244 }
245 }
246 }
247 // Add the *.* filter, but only if we have added other filters (otherwise it
248 // is implied).
249 if (file_types_.include_all_files && !file_types_.extensions.empty())
250 filter_set.insert("application/octet-stream");
251 // Create the final output string.
252 filter_string.clear();
253 for (std::set<std::string>::iterator it = filter_set.begin();
254 it != filter_set.end(); ++it) {
255 filter_string.append(*it + " ");
256 }
257 return filter_string;
258 }
259
260 void SelectFileDialogImplKDE::CallKDialogOutput(const KDialogParams& params) {
261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
262 CommandLine::StringVector cmd_vector;
263 cmd_vector.push_back(kKdialogBinary);
264 CommandLine command_line(cmd_vector);
265 GetKDialogCommandLine(params.type, params.title, params.default_path,
266 params.parent, params.file_operation,
267 params.multiple_selection, &command_line);
268 std::string output;
269 int exit_code;
270 // Get output from KDialog
271 base::GetAppOutputWithExitCode(command_line, &output, &exit_code);
272 if (!output.empty())
273 output.erase(output.size() - 1);
274 // Now the dialog is no longer showing. We can erase its parent from the
275 // parent set.
276 std::set<GtkWindow*>::iterator iter = parents_.find(params.parent);
277 if (iter != parents_.end())
278 parents_.erase(iter);
279 BrowserThread::PostTask(
280 BrowserThread::UI, FROM_HERE,
281 base::Bind(params.callback, this, output, exit_code,
282 params.kdialog_params));
283 }
284
285 void SelectFileDialogImplKDE::GetKDialogCommandLine(const std::string& type,
286 const std::string& title, const FilePath& path,
287 gfx::NativeWindow parent, bool file_operation, bool multiple_selection,
288 CommandLine* command_line) {
289 CHECK(command_line);
290
291 // Attach to the current Chrome window.
292 GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET((parent)));
293 int window_id = GDK_DRAWABLE_XID(gdk_window);
294 command_line->AppendSwitchNative(
295 desktop_ == base::nix::DESKTOP_ENVIRONMENT_KDE3 ? "--embed" : "--attach",
296 base::IntToString(window_id));
297 // Set the correct title for the dialog.
298 if (!title.empty())
299 command_line->AppendSwitchNative("--title", title);
300 // Enable multiple file selection if we need to.
301 if (multiple_selection) {
302 command_line->AppendSwitch("--multiple");
303 command_line->AppendSwitch("--separate-output");
304 }
305 command_line->AppendSwitch(type);
306 // The path should never be empty. If it is, set it to PWD.
307 if (path.empty())
308 command_line->AppendArgPath(FilePath("."));
309 else
310 command_line->AppendArgPath(path);
311 // Depending on the type of the operation we need, get the path to the
312 // file/folder and set up mime type filters.
313 if (file_operation)
314 command_line->AppendArg(GetMimeTypeFilterString());
315 VLOG(1) << "KDialog command line: " << command_line->GetCommandLineString();
316 }
317
318 void SelectFileDialogImplKDE::FileSelected(const FilePath& path, void* params) {
319 if (type_ == SELECT_SAVEAS_FILE)
320 *last_saved_path_ = path.DirName();
321 else if (type_ == SELECT_OPEN_FILE)
322 *last_opened_path_ = path.DirName();
323 else if (type_ == SELECT_FOLDER)
324 *last_opened_path_ = path;
325 else
326 NOTREACHED();
327 if (listener_) { // What does the filter index actually do?
328 // TODO(dfilimon): Get a reasonable index value from somewhere.
329 listener_->FileSelected(path, 1, params);
330 }
331 }
332
333 void SelectFileDialogImplKDE::MultiFilesSelected(
334 const std::vector<FilePath>& files, void* params) {
335 *last_opened_path_ = files[0].DirName();
336 if (listener_)
337 listener_->MultiFilesSelected(files, params);
338 }
339
340 void SelectFileDialogImplKDE::FileNotSelected(void* params) {
341 if (listener_)
342 listener_->FileSelectionCanceled(params);
343 }
344
345 void SelectFileDialogImplKDE::CreateSelectFolderDialog(
346 const std::string& title, const FilePath& default_path,
347 gfx::NativeWindow parent, void *params) {
348 BrowserThread::PostTask(
349 BrowserThread::FILE, FROM_HERE,
350 base::Bind(
351 &SelectFileDialogImplKDE::CallKDialogOutput,
352 this,
353 KDialogParams(
354 "--getexistingdirectory",
355 GetTitle(title, IDS_SELECT_FOLDER_DIALOG_TITLE),
356 default_path.empty() ? *last_opened_path_ : default_path,
357 parent, false, false, params,
358 &SelectFileDialogImplKDE::OnSelectSingleFolderDialogResponse)));
359 }
360
361 void SelectFileDialogImplKDE::CreateFileOpenDialog(
362 const std::string& title, const FilePath& default_path,
363 gfx::NativeWindow parent, void* params) {
364 BrowserThread::PostTask(
365 BrowserThread::FILE, FROM_HERE,
366 base::Bind(
367 &SelectFileDialogImplKDE::CallKDialogOutput,
368 this,
369 KDialogParams(
370 "--getopenfilename",
371 GetTitle(title, IDS_OPEN_FILE_DIALOG_TITLE),
372 default_path.empty() ? *last_opened_path_ : default_path,
373 parent, true, false, params,
374 &SelectFileDialogImplKDE::OnSelectSingleFileDialogResponse)));
375 }
376
377 void SelectFileDialogImplKDE::CreateMultiFileOpenDialog(
378 const std::string& title, const FilePath& default_path,
379 gfx::NativeWindow parent, void* params) {
380 BrowserThread::PostTask(
381 BrowserThread::FILE, FROM_HERE,
382 base::Bind(
383 &SelectFileDialogImplKDE::CallKDialogOutput,
384 this,
385 KDialogParams(
386 "--getopenfilename",
387 GetTitle(title, IDS_OPEN_FILES_DIALOG_TITLE),
388 default_path.empty() ? *last_opened_path_ : default_path,
389 parent, true, true, params,
390 &SelectFileDialogImplKDE::OnSelectMultiFileDialogResponse)));
391 }
392
393 void SelectFileDialogImplKDE::CreateSaveAsDialog(
394 const std::string& title, const FilePath& default_path,
395 gfx::NativeWindow parent, void* params) {
396 BrowserThread::PostTask(
397 BrowserThread::FILE, FROM_HERE,
398 base::Bind(
399 &SelectFileDialogImplKDE::CallKDialogOutput,
400 this,
401 KDialogParams(
402 "--getsavefilename",
403 GetTitle(title, IDS_SAVE_AS_DIALOG_TITLE),
404 default_path.empty() ? *last_saved_path_ : default_path,
405 parent, true, false, params,
406 &SelectFileDialogImplKDE::OnSelectSingleFileDialogResponse)));
407 }
408
409 void SelectFileDialogImplKDE::SelectSingleFileHelper(const std::string& output,
410 int exit_code, void* params, bool allow_folder) {
411 VLOG(1) << "[kdialog] SingleFileResponse: " << output;
412 if (exit_code != 0 || output.empty()) {
413 FileNotSelected(params);
414 return;
415 }
416
417 FilePath path(output);
418 if (allow_folder) {
419 FileSelected(path, params);
420 return;
421 }
422
423 if (CallDirectoryExistsOnUIThread(path))
424 FileNotSelected(params);
425 else
426 FileSelected(path, params);
427 }
428
429 void SelectFileDialogImplKDE::OnSelectSingleFileDialogResponse(
430 const std::string& output, int exit_code, void* params) {
431 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
432 SelectSingleFileHelper(output, exit_code, params, false);
433 }
434
435 void SelectFileDialogImplKDE::OnSelectSingleFolderDialogResponse(
436 const std::string& output, int exit_code, void* params) {
437 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
438 SelectSingleFileHelper(output, exit_code, params, true);
439 }
440
441 void SelectFileDialogImplKDE::OnSelectMultiFileDialogResponse(
442 const std::string& output, int exit_code, void* params) {
443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
444 VLOG(1) << "[kdialog] MultiFileResponse: " << output;
445
446 if (exit_code != 0 || output.empty()) {
447 FileNotSelected(params);
448 return;
449 }
450
451 std::vector<std::string> filenames;
452 Tokenize(output, "\n", &filenames);
453 std::vector<FilePath> filenames_fp;
454 for (std::vector<std::string>::iterator iter = filenames.begin();
455 iter != filenames.end(); ++iter) {
456 FilePath path(*iter);
457 if (CallDirectoryExistsOnUIThread(path))
458 continue;
459 filenames_fp.push_back(path);
460 }
461
462 if (filenames_fp.empty()) {
463 FileNotSelected(params);
464 return;
465 }
466 MultiFilesSelected(filenames_fp, params);
467 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/gtk/select_file_dialog_impl_gtk.cc ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698