| 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
|
|
|
|
|