[gtk+/wip/gbsneto/other-locations] updates



commit d21b9f8ff0ea7ec916505903f4538e78ff1d5716
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Tue Jul 14 14:35:34 2015 -0300

    updates
    
    Add search, add mnemonics, fix focus chain

 gtk/gtkfilechooserwidget.c |  142 ++++++++++-------
 gtk/gtkplacesview.c        |  277 +++++++++++++++++++++++++--------
 gtk/gtkplacesviewprivate.h |    6 +
 gtk/ui/gtkplacesview.ui    |  378 +++++++++++++++++++++++++++++---------------
 4 files changed, 557 insertions(+), 246 deletions(-)
---
diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c
index d54b2c3..2bc8e56 100644
--- a/gtk/gtkfilechooserwidget.c
+++ b/gtk/gtkfilechooserwidget.c
@@ -211,6 +211,7 @@ struct _GtkFileChooserWidgetPrivate {
   GtkWidget *browse_header_revealer;
   GtkWidget *browse_header_stack;
   GtkWidget *browse_files_stack;
+  GtkWidget *browse_files_swin;
   GtkWidget *browse_files_tree_view;
   GtkWidget *browse_files_popup_menu;
   GtkWidget *add_shortcut_item;
@@ -1371,11 +1372,8 @@ gtk_file_chooser_widget_key_press_event (GtkWidget   *widget,
     }
   else if (gtk_search_entry_handle_event (GTK_SEARCH_ENTRY (priv->search_entry), (GdkEvent *)event))
     {
-      if (priv->operation_mode != OPERATION_MODE_OTHER_LOCATIONS &&
-          priv->operation_mode != OPERATION_MODE_SEARCH)
-        {
-          operation_mode_set (impl, OPERATION_MODE_SEARCH);
-        }
+      if (priv->operation_mode != OPERATION_MODE_SEARCH)
+        operation_mode_set (impl, OPERATION_MODE_SEARCH);
       return TRUE;
     }
 
@@ -2571,6 +2569,8 @@ save_widgets_create (GtkFileChooserWidget *impl)
 
   location_switch_to_path_bar (impl);
 
+  gtk_places_sidebar_set_location (GTK_PLACES_SIDEBAR (priv->places_sidebar), priv->current_folder);
+
   if (priv->external_entry)
     {
       location_entry_disconnect (impl);
@@ -2649,8 +2649,6 @@ location_switch_to_path_bar (GtkFileChooserWidget *impl)
     }
 
   gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_header_stack), "pathbar");
-
-  gtk_places_sidebar_set_location (GTK_PLACES_SIDEBAR (priv->places_sidebar), priv->current_folder);
 }
 
 /* Turns on the location entry.  Can be called even if we are already in that
@@ -3045,6 +3043,7 @@ operation_mode_set_browse (GtkFileChooserWidget *impl)
 {
   GtkFileChooserWidgetPrivate *priv = impl->priv;
 
+  gtk_places_sidebar_set_location (GTK_PLACES_SIDEBAR (priv->places_sidebar), priv->current_folder);
   gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_files_stack), "list");
   location_mode_set (impl, LOCATION_MODE_PATH_BAR);
   gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_header_stack), "pathbar");
@@ -3057,11 +3056,18 @@ static void
 operation_mode_set_search (GtkFileChooserWidget *impl)
 {
   GtkFileChooserWidgetPrivate *priv = impl->priv;
+  GtkWidget *visible_widget;
 
   g_assert (priv->search_model == NULL);
 
-  gtk_places_sidebar_set_location (GTK_PLACES_SIDEBAR (priv->places_sidebar), priv->current_folder);
-  gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_files_stack), "list");
+  visible_widget = gtk_stack_get_visible_child (GTK_STACK (priv->browse_files_stack));
+
+  if (visible_widget != priv->places_view &&
+      visible_widget != priv->browse_files_swin)
+    {
+      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), "search");
   gtk_revealer_set_reveal_child (GTK_REVEALER (priv->browse_header_revealer), TRUE);
   location_bar_update (impl);
@@ -3098,6 +3104,10 @@ operation_mode_set_other_locations (GtkFileChooserWidget *impl)
   gtk_revealer_set_reveal_child (GTK_REVEALER (priv->browse_header_revealer), FALSE);
   location_bar_update (impl);
   stop_loading_and_clear_list_model (impl, TRUE);
+  recent_stop_loading (impl);
+  search_stop_searching (impl, TRUE);
+  recent_clear_model (impl, TRUE);
+  search_clear_model (impl, TRUE);
   gtk_widget_set_sensitive (priv->filter_combo, FALSE);
 }
 
@@ -3239,11 +3249,19 @@ gtk_file_chooser_widget_set_property (GObject      *object,
         operation_mode_set (impl, OPERATION_MODE_SEARCH);
       else
         {
-          operation_mode_set (impl, OPERATION_MODE_BROWSE);
-          if (priv->current_folder)
-            change_folder_and_display_error (impl, priv->current_folder, FALSE);
+          if (gtk_stack_get_visible_child (GTK_STACK (priv->browse_files_stack)) != priv->places_view)
+            {
+              operation_mode_set (impl, OPERATION_MODE_BROWSE);
+
+              if (priv->current_folder)
+                change_folder_and_display_error (impl, priv->current_folder, FALSE);
+               else
+                switch_to_home_dir (impl);
+            }
           else
-            switch_to_home_dir (impl);
+            {
+              operation_mode_set (impl, OPERATION_MODE_OTHER_LOCATIONS);
+            }
         }
       break;
 
@@ -7134,60 +7152,68 @@ search_start_query (GtkFileChooserWidget *impl,
                     const gchar          *query_text)
 {
   GtkFileChooserWidgetPrivate *priv = impl->priv;
-  GFile *file;
 
-  stop_loading_and_clear_list_model (impl, TRUE);
-  recent_stop_loading (impl);
-  recent_clear_model (impl, TRUE);
+  if (gtk_stack_get_visible_child (GTK_STACK (priv->browse_files_stack)) == priv->places_view)
+    {
+      gtk_places_view_set_search_query (GTK_PLACES_VIEW (priv->places_view), query_text);
+    }
+  else if (query_text[0] != '\0')
+    {
+      GFile *file;
 
-  search_stop_searching (impl, FALSE);
-  search_clear_model (impl, TRUE);
-  search_setup_model (impl);
+      stop_loading_and_clear_list_model (impl, TRUE);
+      recent_stop_loading (impl);
+      recent_clear_model (impl, TRUE);
 
-  set_busy_cursor (impl, TRUE);
-  gtk_spinner_start (GTK_SPINNER (priv->search_spinner));
-  priv->show_progress_timeout = g_timeout_add (1000, show_spinner, impl);
+      search_stop_searching (impl, FALSE);
+      search_clear_model (impl, TRUE);
+      search_setup_model (impl);
 
-  gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_files_stack), "list");
+      set_busy_cursor (impl, TRUE);
+      gtk_spinner_start (GTK_SPINNER (priv->search_spinner));
+      priv->show_progress_timeout = g_timeout_add (1000, show_spinner, impl);
 
-  if (priv->search_engine == NULL)
-    priv->search_engine = _gtk_search_engine_new ();
+      gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_files_stack), "list");
 
-  if (!priv->search_engine)
-    {
-      set_busy_cursor (impl, FALSE);
-      gtk_spinner_stop (GTK_SPINNER (priv->search_spinner));
-      search_error_could_not_create_client (impl); /* lame; we don't get an error code or anything */
-      return;
-    }
+      if (priv->search_engine == NULL)
+        priv->search_engine = _gtk_search_engine_new ();
 
-  if (!priv->search_query)
-    {
-      priv->search_query = gtk_query_new ();
-      gtk_query_set_text (priv->search_query, query_text);
-    }
+      if (!priv->search_engine)
+        {
+          set_busy_cursor (impl, FALSE);
+          gtk_spinner_stop (GTK_SPINNER (priv->search_spinner));
+          search_error_could_not_create_client (impl); /* lame; we don't get an error code or anything */
+          return;
+        }
 
-  file = gtk_places_sidebar_get_location (GTK_PLACES_SIDEBAR (priv->places_sidebar));
-  if (file)
-    {
-      gchar *location;
-      location = g_file_get_uri (file);
-      gtk_query_set_location (priv->search_query, location);
-      g_free (location);
-      g_object_unref (file);
-    }
+      if (!priv->search_query)
+        {
+          priv->search_query = gtk_query_new ();
+          gtk_query_set_text (priv->search_query, query_text);
+        }
 
-  _gtk_search_engine_set_model (priv->search_engine, priv->model_for_search);
-  _gtk_search_engine_set_query (priv->search_engine, priv->search_query);
+      file = gtk_places_sidebar_get_location (GTK_PLACES_SIDEBAR (priv->places_sidebar));
+      if (file)
+        {
+          gchar *location;
+          location = g_file_get_uri (file);
+          gtk_query_set_location (priv->search_query, location);
+          g_free (location);
+          g_object_unref (file);
+        }
+
+      _gtk_search_engine_set_model (priv->search_engine, priv->model_for_search);
+      _gtk_search_engine_set_query (priv->search_engine, priv->search_query);
 
-  g_signal_connect (priv->search_engine, "hits-added",
-                    G_CALLBACK (search_engine_hits_added_cb), impl);
-  g_signal_connect (priv->search_engine, "finished",
-                    G_CALLBACK (search_engine_finished_cb), impl);
-  g_signal_connect (priv->search_engine, "error",
-                    G_CALLBACK (search_engine_error_cb), impl);
+      g_signal_connect (priv->search_engine, "hits-added",
+                        G_CALLBACK (search_engine_hits_added_cb), impl);
+      g_signal_connect (priv->search_engine, "finished",
+                        G_CALLBACK (search_engine_finished_cb), impl);
+      g_signal_connect (priv->search_engine, "error",
+                        G_CALLBACK (search_engine_error_cb), impl);
 
-  _gtk_search_engine_start (priv->search_engine);
+      _gtk_search_engine_start (priv->search_engine);
+    }
 }
 
 /* Callback used when the user presses Enter while typing on the search
@@ -7207,8 +7233,7 @@ search_entry_activate_cb (GtkFileChooserWidget *impl)
   /* reset any existing query object */
   g_set_object (&priv->search_query, NULL);
 
-  if (text[0] != '\0')
-    search_start_query (impl, text);
+  search_start_query (impl, text);
 }
 
 static void
@@ -8282,6 +8307,7 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
   gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, places_sidebar);
   gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, places_view);
   gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_files_tree_view);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_files_swin);
   gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_header_revealer);
   gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_header_stack);
   gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, 
browse_new_folder_button);
diff --git a/gtk/gtkplacesview.c b/gtk/gtkplacesview.c
index 4f83ac4..87b59d6 100644
--- a/gtk/gtkplacesview.c
+++ b/gtk/gtkplacesview.c
@@ -58,9 +58,12 @@ struct _GtkPlacesViewPrivate
 
   GCancellable                  *cancellable;
 
+  gchar                         *search_query;
+
   GtkWidget                     *actionbar;
   GtkWidget                     *address_entry;
   GtkWidget                     *connect_button;
+  GtkWidget                     *drives_box;
   GtkWidget                     *drives_listbox;
   GtkWidget                     *network_grid;
   GtkWidget                     *network_listbox;
@@ -68,6 +71,7 @@ struct _GtkPlacesViewPrivate
   GtkWidget                     *recent_servers_listbox;
   GtkWidget                     *recent_servers_popover;
   GtkWidget                     *recent_servers_stack;
+  GtkWidget                     *stack;
 
   GtkEntryCompletion            *address_entry_completion;
   GtkListStore                  *completion_store;
@@ -145,8 +149,6 @@ emit_show_error_message (GtkPlacesView *view,
 static void
 server_file_changed_cb (GtkPlacesView *view)
 {
-  g_message ("file changed!");
-
   populate_servers (view);
 }
 
@@ -179,11 +181,7 @@ server_list_load (GtkPlacesView *view)
       g_clear_error (&error);
     }
 
-  /*
-   * It is interesting for us to monitor the file for external modification,
-   * since other applications can (and probably will) modify this file and
-   * these modifications must reflect in real-time here.
-   */
+  /* Monitor the file in case it's modified outside this code */
   if (!priv->server_list_monitor)
     {
       priv->server_list_file = g_file_new_for_path (filename);
@@ -362,55 +360,6 @@ activate_row (GtkPlacesView      *view,
     }
 }
 
-static gboolean
-on_key_press_event (GtkWidget     *widget,
-                    GdkEventKey   *event,
-                    GtkPlacesView *view)
-{
-  GtkPlacesViewPrivate *priv;
-
-  priv = gtk_places_view_get_instance_private (view);
-
-  if (event)
-    {
-      guint modifiers;
-
-      modifiers = gtk_accelerator_get_default_mod_mask ();
-
-      if (event->keyval == GDK_KEY_Return ||
-          event->keyval == GDK_KEY_KP_Enter ||
-          event->keyval == GDK_KEY_ISO_Enter ||
-          event->keyval == GDK_KEY_space)
-        {
-          GtkWidget *focus_widget;
-          GtkWindow *toplevel;
-
-          priv->current_open_flags = GTK_PLACES_OPEN_NORMAL;
-          toplevel = get_toplevel (GTK_WIDGET (view));
-
-          if (!toplevel)
-            return FALSE;
-
-          focus_widget = gtk_window_get_focus (toplevel);
-
-          if (!focus_widget)
-            return FALSE;
-
-          if ((event->state & modifiers) == GDK_SHIFT_MASK)
-            priv->current_open_flags = GTK_PLACES_OPEN_NEW_TAB;
-          else if ((event->state & modifiers) == GDK_CONTROL_MASK)
-            priv->current_open_flags = GTK_PLACES_OPEN_NEW_WINDOW;
-
-          if (GTK_IS_PLACES_VIEW_ROW (focus_widget))
-            activate_row (view, GTK_PLACES_VIEW_ROW (focus_widget), priv->current_open_flags);
-
-          return TRUE;
-        }
-    }
-
-  return FALSE;
-}
-
 static void
 gtk_places_view_finalize (GObject *object)
 {
@@ -422,6 +371,7 @@ gtk_places_view_finalize (GObject *object)
 
   g_cancellable_cancel (priv->cancellable);
 
+  g_clear_pointer (&priv->search_query, g_free);
   g_clear_object (&priv->server_list_file);
   g_clear_object (&priv->server_list_monitor);
   g_clear_object (&priv->volume_monitor);
@@ -628,15 +578,55 @@ populate_servers (GtkPlacesView *view)
 }
 
 static void
+update_search_widgets (GtkPlacesView *view)
+{
+  GtkPlacesViewPrivate *priv;
+  GList *children;
+  GList *l;
+  gint visible_drives;
+  gint visible_networks;
+
+  priv = gtk_places_view_get_instance_private (view);
+  visible_drives = 0;
+  visible_networks = 0;
+
+  /* drives */
+  children = gtk_container_get_children (GTK_CONTAINER (priv->drives_listbox));
+
+  for (l = children; l; l = l->next)
+    visible_drives += gtk_widget_get_child_visible (l->data);
+
+  g_list_free (children);
+
+  /* networks */
+  children = gtk_container_get_children (GTK_CONTAINER (priv->network_listbox));
+
+  for (l = children; l; l = l->next)
+    visible_networks += gtk_widget_get_child_visible (l->data);
+
+  g_list_free (children);
+
+  gtk_widget_set_visible (priv->drives_box, visible_drives != 0);
+  gtk_widget_set_visible (priv->network_grid, visible_networks != 0);
+
+  if (visible_drives == 0 && visible_networks == 0)
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->stack), "search");
+  else
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->stack), "lists");
+}
+
+static void
 insert_row (GtkPlacesView *view,
             GtkWidget     *row,
             gboolean       is_network)
 {
   GtkPlacesViewPrivate *priv;
+  GtkWidget *container;
   GtkWidget *list;
 
   priv = gtk_places_view_get_instance_private (view);
   list = is_network ? priv->network_listbox : priv->drives_listbox;
+  container = is_network ? priv->network_grid : priv->drives_box;
 
   g_signal_connect_swapped (gtk_places_view_row_get_event_box (GTK_PLACES_VIEW_ROW (row)),
                             "button-press-event",
@@ -654,7 +644,7 @@ insert_row (GtkPlacesView *view,
                     row);
 
   gtk_container_add (GTK_CONTAINER (list), row);
-  gtk_widget_show (list);
+  gtk_widget_show (container);
 }
 
 static void
@@ -805,9 +795,8 @@ update_places (GtkPlacesView *view)
    * Hide both networks and drives lists, and only show them when
    * a row is added.
    */
-  gtk_widget_hide (priv->drives_listbox);
-  gtk_widget_hide (priv->network_listbox);
-
+  gtk_widget_hide (priv->drives_box);
+  gtk_widget_hide (priv->network_grid);
 
   /* Add currently connected drives */
   drives = g_volume_monitor_get_connected_drives (priv->volume_monitor);
@@ -870,6 +859,23 @@ update_places (GtkPlacesView *view)
 
   /* load saved servers */
   populate_servers (view);
+
+  if (!priv->search_query)
+    {
+      if (!gtk_widget_get_visible (priv->drives_box) &&
+          !gtk_widget_get_visible (priv->network_grid))
+        {
+          gtk_stack_set_visible_child_name (GTK_STACK (priv->stack), "empty");
+        }
+      else
+        {
+          gtk_stack_set_visible_child_name (GTK_STACK (priv->stack), "lists");
+        }
+    }
+  else if (priv->search_query)
+    {
+      update_search_widgets (view);
+    }
 }
 
 static void
@@ -1208,7 +1214,8 @@ open_in_new_tab_cb (GtkMenuItem      *item,
 
   get_view_and_file (row, &view, &file);
 
-  emit_open_location (GTK_PLACES_VIEW (view), file, GTK_PLACES_OPEN_NEW_TAB);
+  if (file)
+    emit_open_location (GTK_PLACES_VIEW (view), file, GTK_PLACES_OPEN_NEW_TAB);
 
   g_clear_object (&file);
 }
@@ -1222,7 +1229,8 @@ open_in_new_window_cb (GtkMenuItem      *item,
 
   get_view_and_file (row, &view, &file);
 
-  emit_open_location (GTK_PLACES_VIEW (view), file, GTK_PLACES_OPEN_NEW_WINDOW);
+  if (file)
+    emit_open_location (GTK_PLACES_VIEW (view), file, GTK_PLACES_OPEN_NEW_WINDOW);
 
   g_clear_object (&file);
 }
@@ -1408,6 +1416,54 @@ on_button_press_event (GtkPlacesViewRow *row,
   return FALSE;
 }
 
+static gboolean
+on_key_press_event (GtkWidget     *widget,
+                    GdkEventKey   *event,
+                    GtkPlacesView *view)
+{
+  GtkPlacesViewPrivate *priv;
+
+  priv = gtk_places_view_get_instance_private (view);
+
+  if (event)
+    {
+      guint modifiers;
+
+      modifiers = gtk_accelerator_get_default_mod_mask ();
+
+      if (event->keyval == GDK_KEY_Return ||
+          event->keyval == GDK_KEY_KP_Enter ||
+          event->keyval == GDK_KEY_ISO_Enter ||
+          event->keyval == GDK_KEY_space)
+        {
+          GtkWidget *focus_widget;
+          GtkWindow *toplevel;
+
+          priv->current_open_flags = GTK_PLACES_OPEN_NORMAL;
+          toplevel = get_toplevel (GTK_WIDGET (view));
+
+          if (!toplevel)
+            return FALSE;
+
+          focus_widget = gtk_window_get_focus (toplevel);
+
+          if (!GTK_IS_PLACES_VIEW_ROW (focus_widget))
+            return FALSE;
+
+          if ((event->state & modifiers) == GDK_SHIFT_MASK)
+            priv->current_open_flags = GTK_PLACES_OPEN_NEW_TAB;
+          else if ((event->state & modifiers) == GDK_CONTROL_MASK)
+            priv->current_open_flags = GTK_PLACES_OPEN_NEW_WINDOW;
+
+          activate_row (view, GTK_PLACES_VIEW_ROW (focus_widget), priv->current_open_flags);
+
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
 static void
 on_eject_button_clicked (GtkWidget        *widget,
                          GtkPlacesViewRow *row)
@@ -1417,7 +1473,6 @@ on_eject_button_clicked (GtkWidget        *widget,
       GtkWidget *view = gtk_widget_get_ancestor (GTK_WIDGET (row), GTK_TYPE_PLACES_VIEW);
 
       unmount_mount (GTK_PLACES_VIEW (view), gtk_places_view_row_get_mount (row));
-
     }
 }
 
@@ -1513,6 +1568,38 @@ on_listbox_row_activated (GtkPlacesView    *view,
   activate_row (view, row, priv->current_open_flags);
 }
 
+static gboolean
+listbox_filter_func (GtkListBoxRow *row,
+                     gpointer       user_data)
+{
+  GtkPlacesViewPrivate *priv;
+  gboolean retval;
+  gchar *name;
+  gchar *path;
+
+  priv = gtk_places_view_get_instance_private (GTK_PLACES_VIEW (user_data));
+  retval = FALSE;
+
+  if (!priv->search_query || priv->search_query[0] == '\0')
+    return TRUE;
+
+  g_object_get (row,
+                "name", &name,
+                "path", &path,
+                NULL);
+
+  if (name)
+    retval |= g_strstr_len (name, -1, priv->search_query) != NULL;
+
+  if (path)
+    retval |= g_strstr_len (path, -1, priv->search_query) != NULL;
+
+  g_free (name);
+  g_free (path);
+
+  return retval;
+}
+
 static void
 gtk_places_view_constructed (GObject *object)
 {
@@ -1522,6 +1609,15 @@ gtk_places_view_constructed (GObject *object)
 
   G_OBJECT_CLASS (gtk_places_view_parent_class)->constructed (object);
 
+  gtk_list_box_set_filter_func (GTK_LIST_BOX (priv->drives_listbox),
+                                listbox_filter_func,
+                                object,
+                                NULL);
+  gtk_list_box_set_filter_func (GTK_LIST_BOX (priv->network_listbox),
+                                listbox_filter_func,
+                                object,
+                                NULL);
+
   /* load drives */
   update_places (GTK_PLACES_VIEW (object));
 
@@ -1647,12 +1743,14 @@ gtk_places_view_class_init (GtkPlacesViewClass *klass)
   gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, address_entry_completion);
   gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, completion_store);
   gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, connect_button);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, drives_box);
   gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, drives_listbox);
   gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, network_grid);
   gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, network_listbox);
   gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, recent_servers_listbox);
   gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, recent_servers_popover);
   gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, recent_servers_stack);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, stack);
 
   gtk_widget_class_bind_template_callback (widget_class, on_address_entry_text_changed);
   gtk_widget_class_bind_template_callback (widget_class, on_connect_button_clicked);
@@ -1748,13 +1846,64 @@ gtk_places_view_get_open_flags (GtkPlacesView *view)
 {
   GtkPlacesViewPrivate *priv;
 
-  g_return_val_if_fail (GTK_IS_PLACES_SIDEBAR (view), 0);
+  g_return_val_if_fail (GTK_IS_PLACES_VIEW (view), 0);
 
   priv = gtk_places_view_get_instance_private (view);
 
   return priv->open_flags;
 }
 
+/**
+ * gtk_places_view_get_search_query:
+ * @view: a #GtkPlacesView
+ *
+ * Retrieves the current search query from @view.
+ *
+ * Returns: (transfer none): the current search query.
+ */
+const gchar*
+gtk_places_view_get_search_query (GtkPlacesView *view)
+{
+  GtkPlacesViewPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_PLACES_VIEW (view), NULL);
+
+  priv = gtk_places_view_get_instance_private (view);
+
+  return priv->search_query;
+}
+
+/**
+ * gtk_places_view_get_search_query:
+ * @view: a #GtkPlacesView
+ * @query_text: the query, or NULL.
+ *
+ * Sets the search query of @view. The search is immediately performed
+ * once the query is set.
+ *
+ * Returns:
+ */
+void
+gtk_places_view_set_search_query (GtkPlacesView *view,
+                                  const gchar   *query_text)
+{
+  GtkPlacesViewPrivate *priv;
+
+  g_return_if_fail (GTK_IS_PLACES_VIEW (view));
+
+  priv = gtk_places_view_get_instance_private (view);
+
+  if (g_strcmp0 (priv->search_query, query_text) != 0)
+    {
+      g_clear_pointer (&priv->search_query, g_free);
+      priv->search_query = g_strdup (query_text);
+
+      gtk_list_box_invalidate_filter (GTK_LIST_BOX (priv->drives_listbox));
+      gtk_list_box_invalidate_filter (GTK_LIST_BOX (priv->network_listbox));
+
+      update_search_widgets (view);
+    }
+}
 
 /**
  * gtk_places_view_get_local_only:
diff --git a/gtk/gtkplacesviewprivate.h b/gtk/gtkplacesviewprivate.h
index a063e04..17f55fd 100644
--- a/gtk/gtkplacesviewprivate.h
+++ b/gtk/gtkplacesviewprivate.h
@@ -73,6 +73,12 @@ void               gtk_places_view_set_open_flags                (GtkPlacesView
                                                                   GtkPlacesOpenFlags  flags);
 
 GDK_AVAILABLE_IN_3_18
+const gchar*       gtk_places_view_get_search_query              (GtkPlacesView      *view);
+GDK_AVAILABLE_IN_3_18
+void               gtk_places_view_set_search_query              (GtkPlacesView      *view,
+                                                                  const gchar        *query_text);
+
+GDK_AVAILABLE_IN_3_18
 gboolean           gtk_places_view_get_local_only                (GtkPlacesView         *view);
 
 GDK_AVAILABLE_IN_3_18
diff --git a/gtk/ui/gtkplacesview.ui b/gtk/ui/gtkplacesview.ui
index 2ec3dfc..eb092c6 100644
--- a/gtk/ui/gtkplacesview.ui
+++ b/gtk/ui/gtkplacesview.ui
@@ -129,150 +129,280 @@
     <property name="orientation">vertical</property>
     <signal name="key-press-event" handler="on_key_press_event" object="GtkPlacesView" swapped="no" />
     <child>
-      <object class="GtkScrolledWindow" id="scrolled_window">
+      <object class="GtkStack" id="stack">
         <property name="visible">True</property>
-        <property name="hexpand">True</property>
-        <property name="vexpand">True</property>
+        <property name="can_focus">False</property>
+        <property name="vhomogeneous">False</property>
+        <property name="transition_type">crossfade</property>
         <child>
-          <object class="GtkViewport" id="viewport">
+          <object class="GtkFrame" id="frame">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
+            <property name="label_xalign">0</property>
             <property name="shadow_type">none</property>
             <child>
-              <object class="GtkBox" id="main_box">
+              <object class="GtkScrolledWindow" id="scrolled_window">
                 <property name="visible">True</property>
                 <property name="hexpand">True</property>
-                <property name="can_focus">False</property>
-                <property name="orientation">vertical</property>
-                <child>
-                  <object class="GtkBox" id="drives_box">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="orientation">vertical</property>
-                    <child>
-                      <object class="GtkLabel" id="drives_title_label">
-                        <property name="visible">True</property>
-                        <property name="margin_start">12</property>
-                        <property name="margin_end">12</property>
-                        <property name="margin_top">6</property>
-                        <property name="margin_bottom">6</property>
-                        <property name="label" translatable="yes">This Computer</property>
-                        <property name="xalign">0</property>
-                        <attributes>
-                          <attribute name="weight" value="bold"/>
-                        </attributes>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkSeparator" id="separator1">
-                        <property name="visible">True</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkListBox" id="drives_listbox">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="selection_mode">none</property>
-                        <signal name="row-activated" handler="on_listbox_row_activated" 
object="GtkPlacesView" swapped="yes" />
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">2</property>
-                      </packing>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
+                <property name="vexpand">True</property>
                 <child>
-                  <object class="GtkGrid" id="network_grid">
+                  <object class="GtkViewport" id="viewport">
                     <property name="visible">True</property>
-                    <property name="hexpand">True</property>
                     <property name="can_focus">False</property>
-                    <property name="column_spacing">12</property>
-                    <child>
-                      <object class="GtkLabel" id="network_title_label">
-                        <property name="visible">True</property>
-                        <property name="margin_start">12</property>
-                        <property name="margin_top">6</property>
-                        <property name="margin_bottom">6</property>
-                        <property name="hexpand">False</property>
-                        <property name="label" translatable="yes">Network</property>
-                        <property name="ellipsize">end</property>
-                        <property name="xalign">0</property>
-                        <attributes>
-                          <attribute name="weight" value="bold"/>
-                        </attributes>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkSpinner" id="network_spinner">
-                        <property name="visible">True</property>
-                        <property name="halign">start</property>
-                        <property name="hexpand">True</property>
-                        <property name="can_focus">False</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">0</property>
-                      </packing>
-                    </child>
+                    <property name="shadow_type">none</property>
                     <child>
-                      <object class="GtkSeparator" id="separator2">
+                      <object class="GtkBox" id="main_box">
                         <property name="visible">True</property>
                         <property name="hexpand">True</property>
                         <property name="can_focus">False</property>
+                        <property name="orientation">vertical</property>
+                        <child>
+                          <object class="GtkBox" id="drives_box">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="orientation">vertical</property>
+                            <child>
+                              <object class="GtkLabel" id="drives_title_label">
+                                <property name="visible">True</property>
+                                <property name="margin_start">12</property>
+                                <property name="margin_end">12</property>
+                                <property name="margin_top">6</property>
+                                <property name="margin_bottom">6</property>
+                                <property name="label" translatable="yes">This Computer</property>
+                                <property name="xalign">0</property>
+                                <attributes>
+                                  <attribute name="weight" value="bold"/>
+                                </attributes>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkSeparator" id="separator1">
+                                <property name="visible">True</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkListBox" id="drives_listbox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="selection_mode">none</property>
+                                <signal name="row-activated" handler="on_listbox_row_activated" 
object="GtkPlacesView" swapped="yes" />
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkGrid" id="network_grid">
+                            <property name="visible">True</property>
+                            <property name="hexpand">True</property>
+                            <property name="can_focus">False</property>
+                            <child>
+                              <object class="GtkLabel" id="network_title_label">
+                                <property name="visible">True</property>
+                                <property name="margin_start">12</property>
+                                <property name="margin_end">12</property>
+                                <property name="margin_top">6</property>
+                                <property name="margin_bottom">6</property>
+                                <property name="hexpand">False</property>
+                                <property name="label" translatable="yes">Network</property>
+                                <property name="ellipsize">end</property>
+                                <property name="xalign">0</property>
+                                <attributes>
+                                  <attribute name="weight" value="bold"/>
+                                </attributes>
+                              </object>
+                              <packing>
+                                <property name="left_attach">0</property>
+                                <property name="top_attach">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkSpinner" id="network_spinner">
+                                <property name="visible">True</property>
+                                <property name="halign">start</property>
+                                <property name="hexpand">True</property>
+                                <property name="can_focus">False</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="top_attach">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkSeparator" id="separator2">
+                                <property name="visible">True</property>
+                                <property name="hexpand">True</property>
+                                <property name="can_focus">False</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">0</property>
+                                <property name="top_attach">1</property>
+                                <property name="width">2</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkListBox" id="network_listbox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="selection_mode">none</property>
+                                <signal name="row-activated" handler="on_listbox_row_activated" 
object="GtkPlacesView" swapped="yes" />
+                              </object>
+                              <packing>
+                                <property name="left_attach">0</property>
+                                <property name="top_attach">2</property>
+                                <property name="width">2</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
                       </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">1</property>
-                        <property name="width">2</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkListBox" id="network_listbox">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="selection_mode">none</property>
-                        <signal name="row-activated" handler="on_listbox_row_activated" 
object="GtkPlacesView" swapped="yes" />
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">2</property>
-                        <property name="width">2</property>
-                      </packing>
                     </child>
+                    <style>
+                      <class name="view"/>
+                    </style>
                   </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
                 </child>
               </object>
             </child>
-            <style>
-              <class name="view"/>
-            </style>
           </object>
+          <packing>
+            <property name="name">lists</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="halign">center</property>
+            <property name="valign">center</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">12</property>
+            <child>
+              <object class="GtkImage">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="pixel_size">72</property>
+                <property name="icon_name">drive-harddisk-symbolic</property>
+                <style>
+                  <class name="dim-label"/>
+                </style>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">No drives or networks found</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                  <attribute name="scale" value="1.44"/>
+                </attributes>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="name">empty</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="halign">center</property>
+            <property name="valign">center</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">12</property>
+            <child>
+              <object class="GtkImage">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="pixel_size">72</property>
+                <property name="icon_name">edit-find-symbolic</property>
+                <style>
+                  <class name="dim-label"/>
+                </style>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">No results found</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                  <attribute name="scale" value="1.44"/>
+                </attributes>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Try a different search</property>
+                <style>
+                  <class name="dim-label"/>
+                </style>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="name">search</property>
+            <property name="position">2</property>
+          </packing>
         </child>
       </object>
       <packing>
@@ -292,7 +422,7 @@
             <property name="hexpand">True</property>
             <property name="can_focus">False</property>
             <property name="xalign">0</property>
-            <property name="label" translatable="yes">Connect to Server</property>
+            <property name="label" translatable="yes">Connect to _Server</property>
             <attributes>
               <attribute name="weight" value="bold"/>
             </attributes>
@@ -300,7 +430,7 @@
         </child>
         <child>
           <object class="GtkButton" id="connect_button">
-            <property name="label" translatable="yes">Connect</property>
+            <property name="label" translatable="yes">Con_nect</property>
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="sensitive">False</property>



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