[gtk+/wip/matthiasc/pathbar-in-header: 3/3] wip: external path bar for file chooser



commit b7513c8b63338a526bf7a0cd269654d7dcafe945
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Jun 17 09:57:20 2015 -0400

    wip: external path bar for file chooser

 gtk/gtkfilechooserdialog.c        |   43 +++++++++
 gtk/gtkfilechooserwidget.c        |  173 +++++++++++++++++++++++++++++--------
 gtk/gtkfilechooserwidgetprivate.h |   36 ++++++++
 3 files changed, 217 insertions(+), 35 deletions(-)
---
diff --git a/gtk/gtkfilechooserdialog.c b/gtk/gtkfilechooserdialog.c
index 29fbb48..d65f6c5 100644
--- a/gtk/gtkfilechooserdialog.c
+++ b/gtk/gtkfilechooserdialog.c
@@ -34,6 +34,10 @@
 #include "gtkstylecontext.h"
 #include "gtkheaderbar.h"
 #include "gtkdialogprivate.h"
+#include "gtkpathbar.h"
+#include "gtkfilechooserentry.h"
+#include "gtkfilechooserwidgetprivate.h"
+#include "gtkstack.h"
 
 #include <stdarg.h>
 
@@ -206,6 +210,8 @@ struct _GtkFileChooserDialogPrivate
   /* for use with GtkFileChooserEmbed */
   gboolean response_requested;
   gboolean search_setup;
+
+  gboolean path_bar_setup;
 };
 
 static void     gtk_file_chooser_dialog_set_property (GObject               *object,
@@ -523,6 +529,42 @@ setup_search (GtkFileChooserDialog *dialog)
 }
 
 static void
+setup_path_bar (GtkFileChooserDialog *dialog)
+{
+  gboolean use_header;
+
+  if (dialog->priv->path_bar_setup)
+    return;
+
+  dialog->priv->path_bar_setup = TRUE;
+
+  g_object_get (dialog, "use-header-bar", &use_header, NULL);
+  if (use_header)
+    {
+      GtkWidget *stack;
+      GtkWidget *path_bar;
+      GtkWidget *entry;
+      GtkWidget *header;
+
+      stack = gtk_stack_new ();
+      path_bar = (GtkWidget *) g_object_new (GTK_TYPE_PATH_BAR, NULL);
+      entry = _gtk_file_chooser_entry_new (TRUE);
+
+      gtk_stack_add_named (GTK_STACK (stack), path_bar, "pathbar");
+      gtk_stack_add_named (GTK_STACK (stack), entry, "location");
+
+      gtk_widget_show_all (stack);
+
+      header = gtk_dialog_get_header_bar (GTK_DIALOG (dialog));
+      gtk_header_bar_pack_start (GTK_HEADER_BAR (header), stack);
+
+      gtk_file_chooser_widget_set_external_controls (GTK_FILE_CHOOSER_WIDGET (dialog->priv->widget),
+                                                     path_bar,
+                                                     entry);
+    }
+}
+
+static void
 ensure_default_response (GtkFileChooserDialog *dialog)
 {
   GtkWidget *widget;
@@ -540,6 +582,7 @@ gtk_file_chooser_dialog_map (GtkWidget *widget)
   GtkFileChooserDialogPrivate *priv = dialog->priv;
 
   setup_search (dialog);
+  setup_path_bar (dialog);
   ensure_default_response (dialog);
 
   _gtk_file_chooser_embed_initial_focus (GTK_FILE_CHOOSER_EMBED (priv->widget));
diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c
index 259b6f5..1fa73dc 100644
--- a/gtk/gtkfilechooserwidget.c
+++ b/gtk/gtkfilechooserwidget.c
@@ -25,6 +25,7 @@
 #include "config.h"
 
 #include "gtkfilechooserwidget.h"
+#include "gtkfilechooserwidgetprivate.h"
 
 #include "gtkbindings.h"
 #include "gtkbutton.h"
@@ -266,6 +267,10 @@ struct _GtkFileChooserWidgetPrivate {
   GtkWidget *location_entry;
   LocationMode location_mode;
 
+  GtkWidget *external_path_bar;
+  GtkWidget *external_location_entry;
+  GtkWidget *external_path_bar_stack;
+
   /* Handles */
   GCancellable *file_list_drag_data_received_cancellable;
   GCancellable *update_current_folder_cancellable;
@@ -2034,6 +2039,22 @@ location_entry_changed_cb (GtkEditable          *editable,
 }
 
 static void
+setup_location_entry (GtkFileChooserWidget *impl,
+                      GtkWidget            *entry)
+{
+  GtkFileChooserWidgetPrivate *priv = impl->priv;
+
+  if (priv->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+      priv->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+    gtk_entry_set_placeholder_text (GTK_ENTRY (entry), _("Location"));
+
+  _gtk_file_chooser_entry_set_local_only (GTK_FILE_CHOOSER_ENTRY (entry), priv->local_only);
+  _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (entry), priv->action);
+  gtk_entry_set_width_chars (GTK_ENTRY (entry), 45);
+  gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
+}
+
+static void
 location_entry_create (GtkFileChooserWidget *impl)
 {
   GtkFileChooserWidgetPrivate *priv = impl->priv;
@@ -2041,18 +2062,11 @@ location_entry_create (GtkFileChooserWidget *impl)
   if (!priv->location_entry)
     {
       priv->location_entry = _gtk_file_chooser_entry_new (TRUE);
-      if (priv->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
-          priv->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
-        gtk_entry_set_placeholder_text (GTK_ENTRY (priv->location_entry), _("Location"));
-
       g_signal_connect (priv->location_entry, "changed",
                         G_CALLBACK (location_entry_changed_cb), impl);
     }
 
-  _gtk_file_chooser_entry_set_local_only (GTK_FILE_CHOOSER_ENTRY (priv->location_entry), priv->local_only);
-  _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (priv->location_entry), priv->action);
-  gtk_entry_set_width_chars (GTK_ENTRY (priv->location_entry), 45);
-  gtk_entry_set_activates_default (GTK_ENTRY (priv->location_entry), TRUE);
+  setup_location_entry (impl, priv->location_entry);
 }
 
 /* Creates the widgets specific to Save mode */
@@ -2125,6 +2139,12 @@ location_switch_to_path_bar (GtkFileChooserWidget *impl)
 {
   GtkFileChooserWidgetPrivate *priv = impl->priv;
 
+  if (priv->external_path_bar)
+    {
+      gtk_stack_set_visible_child_name (GTK_STACK (priv->external_path_bar_stack), "pathbar");
+      return;
+    }
+
   if (priv->location_entry)
     {
       gtk_widget_destroy (priv->location_entry);
@@ -2150,6 +2170,14 @@ location_switch_to_filename_entry (GtkFileChooserWidget *impl)
       priv->operation_mode == OPERATION_MODE_RECENT)
     return;
 
+  if (priv->external_path_bar)
+    {
+      _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (priv->external_location_entry), 
priv->current_folder);
+      gtk_stack_set_visible_child_name (GTK_STACK (priv->external_path_bar_stack), "location");
+      gtk_widget_grab_focus (priv->external_location_entry);
+      return;
+    }
+
   gtk_revealer_set_reveal_child (GTK_REVEALER (priv->browse_header_revealer), TRUE);
 
   if (!priv->location_entry)
@@ -2419,6 +2447,9 @@ put_recent_folder_in_pathbar (GtkFileChooserWidget *impl, GtkTreeIter *iter)
   gtk_tree_model_get (GTK_TREE_MODEL (priv->recent_model), iter,
                      MODEL_COL_FILE, &file,
                      -1);
+  if (priv->external_path_bar)
+    _gtk_path_bar_set_file (GTK_PATH_BAR (priv->external_path_bar), file, FALSE);
+
   _gtk_path_bar_set_file (GTK_PATH_BAR (priv->browse_path_bar), file, FALSE);
   g_object_unref (file);
 }
@@ -2518,8 +2549,16 @@ operation_mode_set_enter_location (GtkFileChooserWidget *impl)
   GtkFileChooserWidgetPrivate *priv = impl->priv;
 
   gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_files_stack), "list");
-  gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_header_stack), "location");
-  gtk_revealer_set_reveal_child (GTK_REVEALER (priv->browse_header_revealer), TRUE);
+  if (priv->external_path_bar)
+    {
+      gtk_stack_set_visible_child_name (GTK_STACK (priv->external_path_bar_stack), "location");
+      gtk_revealer_set_reveal_child (GTK_REVEALER (priv->browse_header_revealer), FALSE);
+    }
+  else
+    {
+      gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_header_stack), "location");
+      gtk_revealer_set_reveal_child (GTK_REVEALER (priv->browse_header_revealer), TRUE);
+    }
   location_bar_update (impl);
   gtk_widget_set_sensitive (priv->filter_combo, TRUE);
   location_mode_set (impl, LOCATION_MODE_FILENAME_ENTRY);
@@ -2532,8 +2571,16 @@ operation_mode_set_browse (GtkFileChooserWidget *impl)
   GtkFileChooserWidgetPrivate *priv = impl->priv;
 
   gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_files_stack), "list");
-  gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_header_stack), "pathbar");
-  gtk_revealer_set_reveal_child (GTK_REVEALER (priv->browse_header_revealer), TRUE);
+  if (priv->external_path_bar)
+    {
+      gtk_stack_set_visible_child_name (GTK_STACK (priv->external_path_bar_stack), "pathbar");
+      gtk_revealer_set_reveal_child (GTK_REVEALER (priv->browse_header_revealer), FALSE);
+    }
+  else
+    {
+      gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_header_stack), "pathbar");
+      gtk_revealer_set_reveal_child (GTK_REVEALER (priv->browse_header_revealer), TRUE);
+    }
   location_bar_update (impl);
   gtk_widget_set_sensitive (priv->filter_combo, TRUE);
   gtk_tree_view_column_set_visible (priv->list_location_column, FALSE);
@@ -2548,6 +2595,8 @@ operation_mode_set_search (GtkFileChooserWidget *impl)
   g_assert (priv->search_model == NULL);
 
   gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_files_stack), "list");
+  if (priv->external_path_bar)
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->external_path_bar_stack), "pathbar");
   gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_header_stack), "search");
   gtk_revealer_set_reveal_child (GTK_REVEALER (priv->browse_header_revealer), TRUE);
   location_bar_update (impl);
@@ -2572,7 +2621,10 @@ operation_mode_set_recent (GtkFileChooserWidget *impl)
   GFile *file;
 
   gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_files_stack), "list");
-  gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_header_stack), "pathbar");
+  if (priv->external_path_bar)
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->external_path_bar_stack), "pathbar");
+  else
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_header_stack), "pathbar");
   gtk_revealer_set_reveal_child (GTK_REVEALER (priv->browse_header_revealer), FALSE);
   location_bar_update (impl);
   recent_start_loading (impl);
@@ -4536,6 +4588,9 @@ update_current_folder_get_info_cb (GCancellable *cancellable,
   if (! _gtk_file_info_consider_as_directory (info))
     goto out;
 
+  if (priv->external_path_bar)
+    _gtk_path_bar_set_file (GTK_PATH_BAR (priv->external_path_bar), data->file, data->keep_trail);
+
   _gtk_path_bar_set_file (GTK_PATH_BAR (priv->browse_path_bar), data->file, data->keep_trail);
 
   if (priv->current_folder != data->file)
@@ -4828,7 +4883,8 @@ gtk_file_chooser_widget_unselect_all (GtkFileChooser *chooser)
  *                          the path will be “$cwd/foobar”)
  */
 static void
-check_save_entry (GtkFileChooserWidget *impl,
+check_save_entry (GtkFileChooserWidget  *impl,
+                  GtkWidget             *entry,
                  GFile                **file_ret,
                  gboolean              *is_well_formed_ret,
                  gboolean              *is_empty_ret,
@@ -4836,7 +4892,7 @@ check_save_entry (GtkFileChooserWidget *impl,
                  gboolean              *is_folder)
 {
   GtkFileChooserWidgetPrivate *priv = impl->priv;
-  GtkFileChooserEntry *chooser_entry;
+  GtkFileChooserEntry *chooser_entry = GTK_FILE_CHOOSER_ENTRY (entry);
   GFile *current_folder;
   const char *file_part;
   GFile *file;
@@ -4848,9 +4904,7 @@ check_save_entry (GtkFileChooserWidget *impl,
                 || priv->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
                && priv->location_mode == LOCATION_MODE_FILENAME_ENTRY));
 
-  chooser_entry = GTK_FILE_CHOOSER_ENTRY (priv->location_entry);
-
-  if (strlen (gtk_entry_get_text (GTK_ENTRY (chooser_entry))) == 0)
+  if (strlen (gtk_entry_get_text (GTK_ENTRY (entry))) == 0)
     {
       *file_ret = NULL;
       *is_well_formed_ret = TRUE;
@@ -4990,13 +5044,20 @@ gtk_file_chooser_widget_get_files (GtkFileChooser *chooser)
       if (info.result == NULL && priv->location_entry)
        goto file_entry;
     }
-  else if (priv->location_entry && current_focus == priv->location_entry)
+  else if ((priv->location_entry && current_focus == priv->location_entry) ||
+           (priv->external_location_entry && current_focus == priv->external_location_entry))
     {
       gboolean is_well_formed, is_empty, is_file_part_empty, is_folder;
+      GtkWidget *entry;
 
     file_entry:
 
-      check_save_entry (impl, &info.file_from_entry, &is_well_formed, &is_empty, &is_file_part_empty, 
&is_folder);
+      if (priv->external_location_entry)
+        entry = priv->external_location_entry;
+      else
+        entry = priv->location_entry;
+
+      check_save_entry (impl, entry, &info.file_from_entry, &is_well_formed, &is_empty, &is_file_part_empty, 
&is_folder);
 
       if (is_empty)
        goto out;
@@ -5012,14 +5073,15 @@ gtk_file_chooser_widget_get_files (GtkFileChooser *chooser)
 
       if (info.file_from_entry)
         info.result = g_slist_prepend (info.result, info.file_from_entry);
-      else if (!file_list_seen) 
+      else if (!file_list_seen)
         goto file_list;
       else
         return NULL;
     }
   else if (priv->toplevel_last_focus_widget == priv->browse_files_tree_view)
     goto file_list;
-  else if (priv->location_entry && priv->toplevel_last_focus_widget == priv->location_entry)
+  else if ((priv->location_entry && priv->toplevel_last_focus_widget == priv->location_entry) ||
+           (priv->external_location_entry && priv->toplevel_last_focus_widget == 
priv->external_location_entry))
     goto file_entry;
   else
     {
@@ -5028,7 +5090,7 @@ gtk_file_chooser_widget_get_files (GtkFileChooser *chooser)
           priv->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
        goto file_entry;
       else
-       goto file_list; 
+       goto file_list;
     }
 
  out:
@@ -5913,12 +5975,13 @@ gtk_file_chooser_widget_should_respond (GtkFileChooserEmbed *chooser_embed)
          g_assert_not_reached ();
        }
     }
-  else if ((priv->location_entry != NULL) && (current_focus == priv->location_entry))
+  else if (((priv->location_entry != NULL) && (current_focus == priv->location_entry)) ||
+           ((priv->external_location_entry != NULL) && (current_focus == priv->external_location_entry)))
     {
       GFile *file;
       gboolean is_well_formed, is_empty, is_file_part_empty;
       gboolean is_folder;
-      GtkFileChooserEntry *entry;
+      GtkWidget *entry;
       GError *error;
 
     save_entry:
@@ -5929,8 +5992,12 @@ gtk_file_chooser_widget_should_respond (GtkFileChooserEmbed *chooser_embed)
                     || priv->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
                    && priv->location_mode == LOCATION_MODE_FILENAME_ENTRY));
 
-      entry = GTK_FILE_CHOOSER_ENTRY (priv->location_entry);
-      check_save_entry (impl, &file, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder);
+      if (priv->external_location_entry)
+        entry = priv->external_location_entry;
+      else
+        entry = priv->location_entry;
+
+      check_save_entry (impl, entry, &file, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder);
 
       if (!is_well_formed)
        {
@@ -5959,7 +6026,7 @@ gtk_file_chooser_widget_should_respond (GtkFileChooserEmbed *chooser_embed)
              || priv->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
            {
              /* FIXME: ERROR_NO_FILENAME */
-             gtk_widget_grab_focus (priv->location_entry);
+             gtk_widget_grab_focus (entry);
              return FALSE;
            }
 
@@ -6002,7 +6069,7 @@ gtk_file_chooser_widget_should_respond (GtkFileChooserEmbed *chooser_embed)
          data = g_new0 (struct FileExistsData, 1);
          data->impl = g_object_ref (impl);
          data->file = g_object_ref (file);
-         data->parent_file = _gtk_file_chooser_entry_get_current_folder (entry);
+         data->parent_file = _gtk_file_chooser_entry_get_current_folder (GTK_FILE_CHOOSER_ENTRY (entry));
 
          if (priv->file_exists_get_info_cancellable)
            g_cancellable_cancel (priv->file_exists_get_info_cancellable);
@@ -7023,6 +7090,9 @@ up_folder_handler (GtkFileChooserWidget *impl)
 {
   GtkFileChooserWidgetPrivate *priv = impl->priv;
 
+  if (priv->external_path_bar)
+    _gtk_path_bar_up (GTK_PATH_BAR (priv->external_path_bar));
+
   _gtk_path_bar_up (GTK_PATH_BAR (priv->browse_path_bar));
 }
 
@@ -7032,6 +7102,9 @@ down_folder_handler (GtkFileChooserWidget *impl)
 {
   GtkFileChooserWidgetPrivate *priv = impl->priv;
 
+  if (priv->external_path_bar)
+    _gtk_path_bar_down (GTK_PATH_BAR (priv->external_path_bar));
+
   _gtk_path_bar_down (GTK_PATH_BAR (priv->browse_path_bar));
 }
 
@@ -7547,12 +7620,24 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
 }
 
 static void
+setup_path_bar (GtkFileChooserWidget *impl,
+                GtkWidget            *path_bar)
+{
+  GFile *file;
+
+  _gtk_path_bar_set_file_system (GTK_PATH_BAR (path_bar), impl->priv->file_system);
+  file = g_file_new_for_path ("/");
+  _gtk_path_bar_set_file (GTK_PATH_BAR (path_bar), file, FALSE);
+  g_object_unref (file);
+}
+
+
+static void
 post_process_ui (GtkFileChooserWidget *impl)
 {
   GtkTreeSelection *selection;
   GtkCellRenderer  *cell;
   GList            *cells;
-  GFile            *file;
 
   /* Some qdata, qdata can't be set with GtkBuilder */
   g_object_set_data (G_OBJECT (impl->priv->browse_files_tree_view), "fmq-name", "file_list");
@@ -7596,11 +7681,7 @@ post_process_ui (GtkFileChooserWidget *impl)
 
   g_list_free (cells);
 
-  /* Set the GtkPathBar file system backend */
-  _gtk_path_bar_set_file_system (GTK_PATH_BAR (impl->priv->browse_path_bar), impl->priv->file_system);
-  file = g_file_new_for_path ("/");
-  _gtk_path_bar_set_file (GTK_PATH_BAR (impl->priv->browse_path_bar), file, FALSE);
-  g_object_unref (file);
+  setup_path_bar (impl, impl->priv->browse_path_bar);
 
   /* Set the fixed size icon renderer, this requires
    * that priv->icon_size be already setup.
@@ -7610,6 +7691,28 @@ post_process_ui (GtkFileChooserWidget *impl)
   gtk_popover_set_default_widget (GTK_POPOVER (impl->priv->new_folder_popover), 
impl->priv->new_folder_create_button);
 }
 
+void
+gtk_file_chooser_widget_set_external_controls (GtkFileChooserWidget *impl,
+                                               GtkWidget            *path_bar,
+                                               GtkWidget            *entry)
+{
+  GtkFileChooserWidgetPrivate *priv = impl->priv;
+
+  g_return_if_fail (GTK_IS_FILE_CHOOSER_WIDGET (impl));
+  g_return_if_fail (GTK_IS_PATH_BAR (path_bar));
+  g_return_if_fail (GTK_IS_FILE_CHOOSER_ENTRY (entry));
+
+  priv->external_path_bar = path_bar;
+  priv->external_location_entry = entry;
+  priv->external_path_bar_stack = gtk_widget_get_ancestor (path_bar, GTK_TYPE_STACK);
+
+  setup_location_entry (impl, entry);
+  setup_path_bar (impl, path_bar);
+
+  g_signal_connect (path_bar, "path-clicked", G_CALLBACK (path_bar_clicked), impl);
+  g_signal_connect (entry, "changed", G_CALLBACK (location_entry_changed_cb), impl);
+}
+
 static void
 gtk_file_chooser_widget_init (GtkFileChooserWidget *impl)
 {
diff --git a/gtk/gtkfilechooserwidgetprivate.h b/gtk/gtkfilechooserwidgetprivate.h
new file mode 100644
index 0000000..d722ca6
--- /dev/null
+++ b/gtk/gtkfilechooserwidgetprivate.h
@@ -0,0 +1,36 @@
+/* gtkfilechooserwidgetprivate.h
+ *
+ * Copyright (C) 2015 Red Hat
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen
+ */
+
+#ifndef __GTK_FILE_CHOOSER_WIDGET_PRIVATE_H__
+#define __GTK_FILE_CHOOSER_WIDGET_PRIVATE_H__
+
+#include <glib.h>
+#include "gtkfilechooserwidget.h"
+
+G_BEGIN_DECLS
+
+void
+gtk_file_chooser_widget_set_external_controls (GtkFileChooserWidget *chooser,
+                                               GtkWidget            *path_bar,
+                                               GtkWidget            *entry);
+
+G_END_DECLS
+
+#endif /* __GTK_FILE_CHOOSER_WIDGET_PRIVATE_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]