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