15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gdk/gdk.h> 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gdk/gdkx.h> 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gtk/gtk.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Xlib defines RootWindow 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef RootWindow 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_ptr.h" 179ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h" 20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/libgtk2ui/select_file_dialog_impl.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ui_strings.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/root_window.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window_observer.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/shell_dialogs/select_file_dialog.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kAuraTransientParent[] = "aura-transient-parent"; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Set |dialog| as transient for |parent|, which will keep it on top and center 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// it above |parent|. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetGtkTransientForAura(GtkWidget* dialog, aura::Window* parent) { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_realize(dialog); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkWindow* gdk_window = gtk_widget_get_window(dialog); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(erg): Check to make sure we're using X11 if wayland or some other 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // display server ever happens. Otherwise, this will crash. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) XSetTransientForHint(GDK_WINDOW_XDISPLAY(gdk_window), 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GDK_WINDOW_XID(gdk_window), 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parent->GetRootWindow()->GetAcceleratedWidget()); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We also set the |parent| as a property of |dialog|, so that we can unlink 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the two later. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_object_set_data(G_OBJECT(dialog), kAuraTransientParent, parent); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Makes sure that .jpg also shows .JPG. 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gboolean FileFilterCaseInsensitive(const GtkFileFilterInfo* file_info, 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string* file_extension) { 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return EndsWith(file_info->filename, *file_extension, false); 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Deletes |data| when gtk_file_filter_add_custom() is done with it. 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OnFileFilterDataDestroyed(std::string* file_extension) { 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete file_extension; 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace libgtk2ui { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implementation of SelectFileDialog that shows a Gtk common dialog for 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// choosing a file or folder. This acts as a modal dialog. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SelectFileDialogImplGTK : public SelectFileDialogImpl, 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public aura::WindowObserver { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit SelectFileDialogImplGTK(Listener* listener, 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::SelectFilePolicy* policy); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~SelectFileDialogImplGTK(); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SelectFileDialog implementation. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |params| is user data we pass back via the Listener interface. 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void SelectFileImpl( 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Type type, 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const string16& title, 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& default_path, 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const FileTypeInfo* file_types, 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int file_type_index, 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath::StringType& default_extension, 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::NativeWindow owning_window, 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void* params) OVERRIDE; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual bool HasMultipleFileTypeChoicesImpl() OVERRIDE; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Overridden from aura::WindowObserver: 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnWindowDestroying(aura::Window* window) OVERRIDE; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add the filters from |file_types_| to |chooser|. 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void AddFilters(GtkFileChooser* chooser); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Notifies the listener that a single file was chosen. 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void FileSelected(GtkWidget* dialog, const base::FilePath& path); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Notifies the listener that multiple files were chosen. 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void MultiFilesSelected(GtkWidget* dialog, 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<base::FilePath>& files); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Notifies the listener that no file was chosen (the action was canceled). 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Dialog is passed so we can find that |params| pointer that was passed to 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // us when we were told to show the dialog. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void FileNotSelected(GtkWidget* dialog); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 111a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) GtkWidget* CreateSelectFolderDialog( 112a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) Type type, 113a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const std::string& title, 114a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const base::FilePath& default_path, 115a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) gfx::NativeWindow parent); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* CreateFileOpenDialog(const std::string& title, 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& default_path, gfx::NativeWindow parent); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* CreateMultiFileOpenDialog(const std::string& title, 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& default_path, gfx::NativeWindow parent); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* CreateSaveAsDialog(const std::string& title, 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& default_path, gfx::NativeWindow parent); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Removes and returns the |params| associated with |dialog| from 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |params_map_|. 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* PopParamsForDialog(GtkWidget* dialog); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Take care of internal data structures when a file dialog is destroyed. 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void FileDialogDestroyed(GtkWidget* dialog); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check whether response_id corresponds to the user cancelling/closing the 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // dialog. Used as a helper for the below callbacks. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool IsCancelResponse(gint response_id); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Common function for OnSelectSingleFileDialogResponse and 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // OnSelectSingleFolderDialogResponse. 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SelectSingleFileHelper(GtkWidget* dialog, 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gint response_id, 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool allow_folder); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Common function for CreateFileOpenDialog and CreateMultiFileOpenDialog. 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* CreateFileOpenHelper(const std::string& title, 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& default_path, 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeWindow parent); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Callback for when the user responds to a Save As or Open File dialog. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHROMEGTK_CALLBACK_1(SelectFileDialogImplGTK, void, 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnSelectSingleFileDialogResponse, int); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Callback for when the user responds to a Select Folder dialog. 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHROMEGTK_CALLBACK_1(SelectFileDialogImplGTK, void, 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnSelectSingleFolderDialogResponse, int); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Callback for when the user responds to a Open Multiple Files dialog. 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHROMEGTK_CALLBACK_1(SelectFileDialogImplGTK, void, 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnSelectMultiFileDialogResponse, int); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Callback for when the file chooser gets destroyed. 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHROMEGTK_CALLBACK_0(SelectFileDialogImplGTK, void, OnFileChooserDestroy); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Callback for when we update the preview for the selection. 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHROMEGTK_CALLBACK_0(SelectFileDialogImplGTK, void, OnUpdatePreview); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A map from dialog windows to the |params| user data associated with them. 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::map<GtkWidget*, void*> params_map_; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The GtkImage widget for showing previews of selected images. 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* preview_; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // All our dialogs. 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::set<GtkWidget*> dialogs_; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImplGTK); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The size of the preview we display for selected image files. We set height 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// larger than width because generally there is more free space vertically 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// than horiztonally (setting the preview image will alway expand the width of 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the dialog, but usually not the height). The image's aspect ratio will always 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be preserved. 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kPreviewWidth = 256; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kPreviewHeight = 512; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SelectFileDialogImpl* SelectFileDialogImpl::NewSelectFileDialogImplGTK( 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Listener* listener, ui::SelectFilePolicy* policy) { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new SelectFileDialogImplGTK(listener, policy); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SelectFileDialogImplGTK::SelectFileDialogImplGTK(Listener* listener, 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::SelectFilePolicy* policy) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : SelectFileDialogImpl(listener, policy), 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) preview_(NULL) { 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SelectFileDialogImplGTK::~SelectFileDialogImplGTK() { 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (dialogs_.begin() != dialogs_.end()) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_destroy(*(dialogs_.begin())); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SelectFileDialogImplGTK::HasMultipleFileTypeChoicesImpl() { 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return file_types_.extensions.size() > 1; 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogImplGTK::OnWindowDestroying(aura::Window* window) { 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::set<aura::Window*>::iterator iter = parents_.find(window); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (iter != parents_.end()) { 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*iter)->RemoveObserver(this); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parents_.erase(iter); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We ignore |default_extension|. 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogImplGTK::SelectFileImpl( 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Type type, 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& title, 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& default_path, 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FileTypeInfo* file_types, 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int file_type_index, 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath::StringType& default_extension, 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeWindow owning_window, 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* params) { 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_ = type; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |owning_window| can be null when user right-clicks on a downloadable item 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and chooses 'Open Link in New Tab' when 'Ask where to save each file 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // before downloading.' preference is turned on. (http://crbug.com/29213) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (owning_window) { 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) owning_window->AddObserver(this); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parents_.insert(owning_window); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string title_string = UTF16ToUTF8(title); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_type_index_ = file_type_index; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (file_types) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_types_ = *file_types; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* dialog = NULL; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (type) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SELECT_FOLDER: 243a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case SELECT_UPLOAD_FOLDER: 244a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) dialog = CreateSelectFolderDialog(type, title_string, default_path, 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) owning_window); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SELECT_OPEN_FILE: 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dialog = CreateFileOpenDialog(title_string, default_path, owning_window); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SELECT_OPEN_MULTI_FILE: 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dialog = CreateMultiFileOpenDialog(title_string, default_path, 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) owning_window); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SELECT_SAVEAS_FILE: 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dialog = CreateSaveAsDialog(title_string, default_path, owning_window); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(dialog, "delete-event", 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(gtk_widget_hide_on_delete), NULL); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dialogs_.insert(dialog); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) preview_ = gtk_image_new(); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(dialog, "destroy", 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(OnFileChooserDestroyThunk), this); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(dialog, "update-preview", 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(OnUpdatePreviewThunk), this); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog), preview_); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params_map_[dialog] = params; 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(erg): Figure out how to fake GTK window-to-parent modality without 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // having the parent be a real GtkWindow. 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_show_all(dialog); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogImplGTK::AddFilters(GtkFileChooser* chooser) { 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < file_types_.extensions.size(); ++i) { 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkFileFilter* filter = NULL; 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::set<std::string> fallback_labels; 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t j = 0; j < file_types_.extensions[i].size(); ++j) { 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& current_extension = file_types_.extensions[i][j]; 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!current_extension.empty()) { 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!filter) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filter = gtk_file_filter_new(); 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<std::string> file_extension( 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new std::string("." + current_extension)); 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fallback_labels.insert(std::string("*").append(*file_extension)); 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gtk_file_filter_add_custom( 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) filter, 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GTK_FILE_FILTER_FILENAME, 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) reinterpret_cast<GtkFileFilterFunc>(FileFilterCaseInsensitive), 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_extension.release(), 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) reinterpret_cast<GDestroyNotify>(OnFileFilterDataDestroyed)); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We didn't find any non-empty extensions to filter on. 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!filter) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The description vector may be blank, in which case we are supposed to 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // use some sort of default description based on the filter. 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i < file_types_.extension_description_overrides.size()) { 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_filter_set_name(filter, UTF16ToUTF8( 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_types_.extension_description_overrides[i]).c_str()); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There is no system default filter description so we use 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the extensions themselves if the description is blank. 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> fallback_labels_vector(fallback_labels.begin(), 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fallback_labels.end()); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string fallback_label = JoinString(fallback_labels_vector, ','); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_filter_set_name(filter, fallback_label.c_str()); 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_add_filter(chooser, filter); 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i == file_type_index_ - 1) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_filter(chooser, filter); 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add the *.* filter, but only if we have added other filters (otherwise it 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is implied). 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (file_types_.include_all_files && !file_types_.extensions.empty()) { 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkFileFilter* filter = gtk_file_filter_new(); 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_filter_add_pattern(filter, "*"); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_filter_set_name(filter, 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF8(IDS_SAVEAS_ALL_FILES).c_str()); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_add_filter(chooser, filter); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogImplGTK::FileSelected(GtkWidget* dialog, 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& path) { 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type_ == SELECT_SAVEAS_FILE) 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *last_saved_path_ = path.DirName(); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (type_ == SELECT_OPEN_FILE || type_ == SELECT_FOLDER) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *last_opened_path_ = path.DirName(); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (listener_) { 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkFileFilter* selected_filter = 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog)); 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GSList* filters = gtk_file_chooser_list_filters(GTK_FILE_CHOOSER(dialog)); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int idx = g_slist_index(filters, selected_filter); 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_slist_free(filters); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listener_->FileSelected(path, idx + 1, PopParamsForDialog(dialog)); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_destroy(dialog); 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogImplGTK::MultiFilesSelected(GtkWidget* dialog, 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<base::FilePath>& files) { 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *last_opened_path_ = files[0].DirName(); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (listener_) 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listener_->MultiFilesSelected(files, PopParamsForDialog(dialog)); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_destroy(dialog); 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogImplGTK::FileNotSelected(GtkWidget* dialog) { 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* params = PopParamsForDialog(dialog); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (listener_) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listener_->FileSelectionCanceled(params); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_destroy(dialog); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GtkWidget* SelectFileDialogImplGTK::CreateFileOpenHelper( 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& title, 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& default_path, 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeWindow parent) { 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* dialog = 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_dialog_new(title.c_str(), NULL, 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTK_FILE_CHOOSER_ACTION_OPEN, 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetGtkTransientForAura(dialog, parent); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddFilters(GTK_FILE_CHOOSER(dialog)); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!default_path.empty()) { 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CallDirectoryExistsOnUIThread(default_path)) { 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_path.value().c_str()); 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the file doesn't exist, this will just switch to the correct 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // directory. That's good enough. 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_path.value().c_str()); 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!last_opened_path_->empty()) { 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_opened_path_->value().c_str()); 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return dialog; 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GtkWidget* SelectFileDialogImplGTK::CreateSelectFolderDialog( 403a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) Type type, 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& title, 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& default_path, 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeWindow parent) { 407a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) std::string title_string = title; 408a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (title_string.empty()) { 409a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) title_string = (type == SELECT_UPLOAD_FOLDER) ? 410a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) l10n_util::GetStringUTF8(IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE) : 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF8(IDS_SELECT_FOLDER_DIALOG_TITLE); 412a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 413a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) std::string accept_button_label = (type == SELECT_UPLOAD_FOLDER) ? 414a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) l10n_util::GetStringUTF8(IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON) : 415a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) GTK_STOCK_OPEN; 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* dialog = 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_dialog_new(title_string.c_str(), NULL, 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 421a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) accept_button_label.c_str(), 422a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) GTK_RESPONSE_ACCEPT, 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL); 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetGtkTransientForAura(dialog, parent); 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!default_path.empty()) { 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_path.value().c_str()); 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!last_opened_path_->empty()) { 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_opened_path_->value().c_str()); 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE); 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(dialog, "response", 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(OnSelectSingleFolderDialogResponseThunk), this); 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return dialog; 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GtkWidget* SelectFileDialogImplGTK::CreateFileOpenDialog( 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& title, 4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& default_path, 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeWindow parent) { 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string title_string = !title.empty() ? title : 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF8(IDS_OPEN_FILE_DIALOG_TITLE); 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* dialog = CreateFileOpenHelper(title_string, default_path, parent); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE); 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(dialog, "response", 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(OnSelectSingleFileDialogResponseThunk), this); 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return dialog; 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GtkWidget* SelectFileDialogImplGTK::CreateMultiFileOpenDialog( 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& title, 4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& default_path, 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeWindow parent) { 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string title_string = !title.empty() ? title : 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF8(IDS_OPEN_FILES_DIALOG_TITLE); 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* dialog = CreateFileOpenHelper(title_string, default_path, parent); 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(dialog, "response", 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(OnSelectMultiFileDialogResponseThunk), this); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return dialog; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GtkWidget* SelectFileDialogImplGTK::CreateSaveAsDialog(const std::string& title, 4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& default_path, gfx::NativeWindow parent) { 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string title_string = !title.empty() ? title : 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF8(IDS_SAVE_AS_DIALOG_TITLE); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* dialog = 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_dialog_new(title_string.c_str(), NULL, 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTK_FILE_CHOOSER_ACTION_SAVE, 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL); 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetGtkTransientForAura(dialog, parent); 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddFilters(GTK_FILE_CHOOSER(dialog)); 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!default_path.empty()) { 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since the file may not already exist, we use 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // set_current_folder() followed by set_current_name(), as per the 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // recommendation of the GTK docs. 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_path.DirName().value().c_str()); 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_path.BaseName().value().c_str()); 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!last_saved_path_->empty()) { 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_saved_path_->value().c_str()); 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE); 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TRUE); 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(dialog, "response", 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(OnSelectSingleFileDialogResponseThunk), this); 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return dialog; 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* SelectFileDialogImplGTK::PopParamsForDialog(GtkWidget* dialog) { 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::map<GtkWidget*, void*>::iterator iter = params_map_.find(dialog); 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(iter != params_map_.end()); 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* params = iter->second; 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params_map_.erase(iter); 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return params; 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogImplGTK::FileDialogDestroyed(GtkWidget* dialog) { 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dialogs_.erase(dialog); 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Parent may be NULL in a few cases: 1) on shutdown when 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // AllBrowsersClosed() trigger this handler after all the browser 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // windows got destroyed, or 2) when the parent tab has been opened by 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 'Open Link in New Tab' context menu on a downloadable item and 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the tab has no content (see the comment in SelectFile as well). 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) aura::Window* parent = reinterpret_cast<aura::Window*>( 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_object_get_data(G_OBJECT(dialog), kAuraTransientParent)); 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!parent) 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::set<aura::Window*>::iterator iter = parents_.find(parent); 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (iter != parents_.end()) { 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*iter)->RemoveObserver(this); 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parents_.erase(iter); 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SelectFileDialogImplGTK::IsCancelResponse(gint response_id) { 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_cancel = response_id == GTK_RESPONSE_CANCEL || 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_id == GTK_RESPONSE_DELETE_EVENT; 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_cancel) 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(response_id == GTK_RESPONSE_ACCEPT); 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogImplGTK::SelectSingleFileHelper(GtkWidget* dialog, 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gint response_id, 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool allow_folder) { 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsCancelResponse(response_id)) { 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileNotSelected(dialog); 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gchar* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!filename) { 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileNotSelected(dialog); 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath path(filename); 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_free(filename); 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (allow_folder) { 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileSelected(dialog, path); 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CallDirectoryExistsOnUIThread(path)) 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileNotSelected(dialog); 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileSelected(dialog, path); 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogImplGTK::OnSelectSingleFileDialogResponse( 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* dialog, int response_id) { 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SelectSingleFileHelper(dialog, response_id, false); 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogImplGTK::OnSelectSingleFolderDialogResponse( 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* dialog, int response_id) { 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SelectSingleFileHelper(dialog, response_id, true); 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogImplGTK::OnSelectMultiFileDialogResponse(GtkWidget* dialog, 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int response_id) { 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsCancelResponse(response_id)) { 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileNotSelected(dialog); 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GSList* filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!filenames) { 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileNotSelected(dialog); 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<base::FilePath> filenames_fp; 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (GSList* iter = filenames; iter != NULL; iter = g_slist_next(iter)) { 5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath path(static_cast<char*>(iter->data)); 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_free(iter->data); 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CallDirectoryExistsOnUIThread(path)) 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filenames_fp.push_back(path); 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_slist_free(filenames); 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filenames_fp.empty()) { 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileNotSelected(dialog); 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MultiFilesSelected(dialog, filenames_fp); 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogImplGTK::OnFileChooserDestroy(GtkWidget* dialog) { 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileDialogDestroyed(dialog); 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SelectFileDialogImplGTK::OnUpdatePreview(GtkWidget* chooser) { 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gchar* filename = gtk_file_chooser_get_preview_filename( 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTK_FILE_CHOOSER(chooser)); 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!filename) 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This will preserve the image's aspect ratio. 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_size(filename, kPreviewWidth, 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kPreviewHeight, NULL); 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_free(filename); 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pixbuf) { 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_image_set_from_pixbuf(GTK_IMAGE(preview_), pixbuf); 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_object_unref(pixbuf); 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(chooser), 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pixbuf ? TRUE : FALSE); 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace libgtk2ui 630