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

Unified Diff: chrome/browser/ui/gtk/dialogs_kde.cc

Issue 7885002: Added support for KDE file dialogs. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 9 years, 3 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/ui/gtk/dialogs_common.cc ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/ui/gtk/dialogs_kde.cc
===================================================================
--- chrome/browser/ui/gtk/dialogs_kde.cc (revision 0)
+++ chrome/browser/ui/gtk/dialogs_kde.cc (revision 0)
@@ -0,0 +1,405 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#include <map>
+#include <set>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/mime_util.h"
+#include "base/process_util.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/ui/gtk/dialogs_common.h"
+#include "chrome/browser/ui/shell_dialogs.h"
+#include "content/browser/browser_thread.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+// Implementation of SelectFileDialog that shows a KDE common dialog for
+// choosing a file or folder. This acts as a modal dialog.
+class SelectFileDialogImplKDE : public SelectFileDialogImpl {
+ public:
+ explicit SelectFileDialogImplKDE(Listener* listener);
+ ~SelectFileDialogImplKDE();
+
+ protected:
+ // SelectFileDialog implementation.
+ // |params| is user data we pass back via the Listener interface.
+ virtual void SelectFileImpl(Type type,
+ const string16& title,
+ const FilePath& default_path,
+ const FileTypeInfo* file_types,
+ int file_type_index,
+ const FilePath::StringType& default_extension,
+ gfx::NativeWindow owning_window,
+ void* params);
+
+ private:
+ // Get the filters from |file_types_| and concatenate them into
+ // |filter_string|.
+ std::string GetMimeTypeFilterString();
+
+ // Get KDialog command line representing the Argv array for KDialog.
+ void GetKDialogCommandLine(const std::string& type, const std::string& title,
+ const FilePath& default_path, gfx::NativeWindow parent,
+ bool file_operation, bool multiple_selection, CommandLine* command_line);
+
+ // Call KDialog on the FILE thread and post results back to the UI thread.
+ void CallKDialogOutput(const std::string& type, const std::string& title,
+ const FilePath& default_path, gfx::NativeWindow parent,
+ bool file_operation, bool multiple_selection, void* params,
+ void (SelectFileDialogImplKDE::*callback)(const std::string&,
+ int, void*));
+
+ // Notifies the listener that a single file was chosen.
+ void FileSelected(const FilePath& path, void* params);
+
+ // Notifies the listener that multiple files were chosen.
+ void MultiFilesSelected(const std::vector<FilePath>& files, void* params);
+
+ // Notifies the listener that no file was chosen (the action was canceled).
+ // Dialog is passed so we can find that |params| pointer that was passed to
+ // us when we were told to show the dialog.
+ void FileNotSelected(void *params);
+
+ void CreateSelectFolderDialog(const std::string& title,
+ const FilePath& default_path,
+ gfx::NativeWindow parent, void* params);
+
+ void CreateFileOpenDialog(const std::string& title,
+ const FilePath& default_path,
+ gfx::NativeWindow parent, void* params);
+
+ void CreateMultiFileOpenDialog(const std::string& title,
+ const FilePath& default_path,
+ gfx::NativeWindow parent, void* params);
+
+ void CreateSaveAsDialog(const std::string& title,
+ const FilePath& default_path,
+ gfx::NativeWindow parent, void* params);
+
+ // Common function for OnSelectSingleFileDialogResponse and
+ // OnSelectSingleFolderDialogResponse.
+ void SelectSingleFileHelper(const std::string& output, int exit_code,
+ void* params, bool allow_folder);
+
+ void OnSelectSingleFileDialogResponse(const std::string& output,
+ int exit_code, void* params);
+ void OnSelectMultiFileDialogResponse(const std::string& output,
+ int exit_code, void* params);
+ void OnSelectSingleFolderDialogResponse(const std::string& output,
+ int exit_code, void* params);
+
+ DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImplKDE);
+};
+
+SelectFileDialogImpl* SelectFileDialogImpl::NewSelectFileDialogImplKDE(
+ Listener* listener) {
+ return new SelectFileDialogImplKDE(listener);
+}
+
+SelectFileDialogImplKDE::SelectFileDialogImplKDE(Listener* listener)
+ : SelectFileDialogImpl(listener) {
+}
+
+SelectFileDialogImplKDE::~SelectFileDialogImplKDE() {
+}
+
+// We ignore |default_extension|.
+void SelectFileDialogImplKDE::SelectFileImpl(
+ Type type,
+ const string16& title,
+ const FilePath& default_path,
+ const FileTypeInfo* file_types,
+ int file_type_index,
+ const FilePath::StringType& default_extension,
+ gfx::NativeWindow owning_window,
+ void* params) {
+ type_ = type;
+ // |owning_window| can be null when user right-clicks on a downloadable item
+ // and chooses 'Open Link in New Tab' when 'Ask where to save each file
+ // before downloading.' preference is turned on. (http://crbug.com/29213)
+ if (owning_window)
+ parents_.insert(owning_window);
+
+ std::string title_string = UTF16ToUTF8(title);
+
+ file_type_index_ = file_type_index;
+ if (file_types)
+ file_types_ = *file_types;
+ else
+ file_types_.include_all_files = true;
+
+ switch (type) {
+ case SELECT_FOLDER:
+ CreateSelectFolderDialog(title_string, default_path,
+ owning_window, params);
+ return;
+ case SELECT_OPEN_FILE:
+ CreateFileOpenDialog(title_string, default_path, owning_window,
+ params);
+ return;
+ case SELECT_OPEN_MULTI_FILE:
+ CreateMultiFileOpenDialog(title_string, default_path,
+ owning_window, params);
+ return;
+ case SELECT_SAVEAS_FILE:
+ CreateSaveAsDialog(title_string, default_path, owning_window,
+ params);
+ return;
+ default:
+ NOTREACHED();
+ return;
+ }
+}
+
+std::string SelectFileDialogImplKDE::GetMimeTypeFilterString() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ std::string filter_string;
+ // We need a filter set because the same mime type can appear multiple times.
+ std::set<std::string> filter_set;
+ for (size_t i = 0; i < file_types_.extensions.size(); ++i) {
+ for (size_t j = 0; j < file_types_.extensions[i].size(); ++j) {
+ if (!file_types_.extensions[i][j].empty()) {
+ std::string mime_type = mime_util::GetFileMimeType(
+ FilePath("name").ReplaceExtension(file_types_.extensions[i][j]));
+ filter_set.insert(mime_type);
+ }
+ }
+ }
+ // Add the *.* filter, but only if we have added other filters (otherwise it
+ // is implied).
+ if (file_types_.include_all_files && !file_types_.extensions.empty())
+ filter_set.insert("application/octet-stream");
+ // Create the final output string.
+ filter_string.clear();
+ for (std::set<std::string>::iterator it = filter_set.begin();
+ it != filter_set.end(); ++it) {
+ filter_string.append(*it + " ");
+ }
+ return filter_string;
+}
+
+void SelectFileDialogImplKDE::CallKDialogOutput(
+ const std::string& type, const std::string& title,
+ const FilePath& default_path, gfx::NativeWindow parent,
+ bool file_operation, bool multiple_selection, void* params,
+ void (SelectFileDialogImplKDE::*callback)(const std::string&, int, void*)) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ CommandLine command_line(FilePath("kdialog"));
+ GetKDialogCommandLine(type, title, default_path, parent, file_operation,
+ multiple_selection, &command_line);
+ std::string output;
+ int exit_code;
+ // Get output from KDialog
+ base::GetAppOutputWithExitCode(command_line, &output, &exit_code);
+ if (!output.empty())
+ output.erase(output.size() - 1);
+ // Now the dialog is no longer showing. We can erase its parent from the
+ // parent set.
+ std::set<GtkWindow*>::iterator iter = parents_.find(parent);
+ if (iter != parents_.end())
+ parents_.erase(iter);
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this, callback, output, exit_code, params));
+}
+
+void SelectFileDialogImplKDE::GetKDialogCommandLine(const std::string& type,
+ const std::string& title, const FilePath& path,
+ gfx::NativeWindow parent, bool file_operation, bool multiple_selection,
+ CommandLine* command_line) {
+ if (!command_line) {
+ VLOG(1) << "Command line for KDialog is NULL" << std::endl;
+ return;
+ }
+ // Attach to the current Chrome window.
+ GdkWindow* gdk_window =
+ gtk_widget_get_window(GTK_WIDGET((parent)));
+ int window_id = GDK_DRAWABLE_XID(gdk_window);
+ command_line->AppendSwitchNative("--attach", base::IntToString(window_id));
+ // Set the correct title for the dialog.
+ if (!title.empty()) {
+ command_line->AppendSwitchNative("--title", title);
+ }
+ // Enable multiple file selection if we need to.
+ if (multiple_selection) {
+ command_line->AppendSwitch("--multiple");
+ command_line->AppendSwitch("--separate-output");
+ }
+ command_line->AppendSwitch(type);
+ // The path should never be empty. If it is, set it to PWD.
+ if (path.empty()) {
+ command_line->AppendArgPath(FilePath("."));
+ } else {
+ command_line->AppendArgPath(path);
+ }
+ // Depending on the type of the operation we need, get the path to the
+ // file/folder and set up mime type filters.
+ if (file_operation) {
+ command_line->AppendArg(GetMimeTypeFilterString());
+ }
+ VLOG(1) << "KDialog command line: "
+ << command_line->GetCommandLineString() << std::endl;
+}
+
+void SelectFileDialogImplKDE::FileSelected(const FilePath& path, void* params) {
+ if (type_ == SELECT_SAVEAS_FILE)
+ *last_saved_path_ = path.DirName();
+ else if (type_ == SELECT_OPEN_FILE)
+ *last_opened_path_ = path.DirName();
+ else if (type_ == SELECT_FOLDER)
+ *last_opened_path_ = path;
+ else
+ NOTREACHED();
+ if (listener_) { // What does the filter index actually do?
+ // TODO(dfilimon): Get a reasonable index value from somewhere.
+ listener_->FileSelected(path, 1, params);
+ }
+}
+
+void SelectFileDialogImplKDE::MultiFilesSelected(
+ const std::vector<FilePath>& files, void* params) {
+ *last_opened_path_ = files[0].DirName();
+ if (listener_)
+ listener_->MultiFilesSelected(files, params);
+}
+
+void SelectFileDialogImplKDE::FileNotSelected(void* params) {
+ if (listener_)
+ listener_->FileSelectionCanceled(params);
+}
+
+void SelectFileDialogImplKDE::CreateSelectFolderDialog(
+ const std::string& title, const FilePath& default_path,
+ gfx::NativeWindow parent, void *params) {
+ std::string title_string = !title.empty() ? title :
+ l10n_util::GetStringUTF8(IDS_SELECT_FOLDER_DIALOG_TITLE);
+
+ Task* dialog_task =
+ NewRunnableMethod(
+ this, &SelectFileDialogImplKDE::CallKDialogOutput,
+ std::string("--getexistingdirectory"), title,
+ default_path.empty() ? *last_opened_path_ : default_path,
+ parent, false, false, params,
+ &SelectFileDialogImplKDE::OnSelectSingleFolderDialogResponse);
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, dialog_task);
+}
+
+void SelectFileDialogImplKDE::CreateFileOpenDialog(
+ const std::string& title, const FilePath& default_path,
+ gfx::NativeWindow parent, void* params) {
+ std::string title_string = !title.empty() ? title :
+ l10n_util::GetStringUTF8(IDS_OPEN_FILE_DIALOG_TITLE);
+
+ Task* dialog_task =
+ NewRunnableMethod(
+ this, &SelectFileDialogImplKDE::CallKDialogOutput,
+ std::string("--getopenfilename"), title,
+ default_path.empty() ? *last_opened_path_ : default_path,
+ parent, true, false, params,
+ &SelectFileDialogImplKDE::OnSelectSingleFileDialogResponse);
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, dialog_task);
+}
+
+void SelectFileDialogImplKDE::CreateMultiFileOpenDialog(
+ const std::string& title, const FilePath& default_path,
+ gfx::NativeWindow parent, void* params) {
+ std::string title_string = !title.empty() ? title :
+ l10n_util::GetStringUTF8(IDS_OPEN_FILES_DIALOG_TITLE);
+
+ Task* dialog_task =
+ NewRunnableMethod(
+ this, &SelectFileDialogImplKDE::CallKDialogOutput,
+ std::string("--getopenfilename"), title,
+ default_path.empty() ? *last_opened_path_ : default_path,
+ parent, true, true, params,
+ &SelectFileDialogImplKDE::OnSelectMultiFileDialogResponse);
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, dialog_task);
+}
+
+void SelectFileDialogImplKDE::CreateSaveAsDialog(
+ const std::string& title, const FilePath& default_path,
+ gfx::NativeWindow parent, void* params) {
+ std::string title_string = !title.empty() ? title :
+ l10n_util::GetStringUTF8(IDS_SAVE_AS_DIALOG_TITLE);
+
+ Task* dialog_task =
+ NewRunnableMethod(
+ this, &SelectFileDialogImplKDE::CallKDialogOutput,
+ std::string("--getsavefilename"), title,
+ default_path.empty() ? *last_saved_path_ : default_path,
+ parent, true, false, params,
+ &SelectFileDialogImplKDE::OnSelectSingleFileDialogResponse);
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, dialog_task);
+}
+
+void SelectFileDialogImplKDE::SelectSingleFileHelper(const std::string& output,
+ int exit_code, void* params, bool allow_folder) {
+ VLOG(1) << "[kdialog] SingleFileResponse: " << output << std::endl;
+ if (exit_code != 0 || output.empty()) {
+ FileNotSelected(params);
+ return;
+ }
+
+ FilePath path(output);
+ if (allow_folder) {
+ FileSelected(path, params);
+ return;
+ }
+
+ if (CallDirectoryExistsOnUIThread(path))
+ FileNotSelected(params);
+ else
+ FileSelected(path, params);
+}
+
+void SelectFileDialogImplKDE::OnSelectSingleFileDialogResponse(
+ const std::string& output, int exit_code, void* params) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ SelectSingleFileHelper(output, exit_code, params, false);
+}
+
+void SelectFileDialogImplKDE::OnSelectSingleFolderDialogResponse(
+ const std::string& output, int exit_code, void* params) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ SelectSingleFileHelper(output, exit_code, params, true);
+}
+
+void SelectFileDialogImplKDE::OnSelectMultiFileDialogResponse(
+ const std::string& output, int exit_code, void* params) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ VLOG(1) << "[kdialog] MultiFileResponse: " << output << std::endl;
+
+ if (exit_code != 0 || output.empty()) {
+ FileNotSelected(params);
+ return;
+ }
+
+ std::vector<std::string> filenames;
+ Tokenize(output, "\n", &filenames);
+ std::vector<FilePath> filenames_fp;
+ for (std::vector<std::string>::iterator iter = filenames.begin();
+ iter != filenames.end(); ++iter) {
+ FilePath path(*iter);
+ if (CallDirectoryExistsOnUIThread(path))
+ continue;
+ filenames_fp.push_back(path);
+ }
+
+ if (filenames_fp.empty()) {
+ FileNotSelected(params);
+ return;
+ }
+ MultiFilesSelected(filenames_fp, params);
+}
+
Property changes on: chrome/browser/ui/gtk/dialogs_kde.cc
___________________________________________________________________
Added: svn:eol-style
+ LF
« no previous file with comments | « chrome/browser/ui/gtk/dialogs_common.cc ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698