[gtk+/wip/csoriano/gtkpathbar_rework: 992/993] gtkpathbar: listen to file changes and update pathbar



commit 324e9473a2fe917cca1371cdd30f09b28fd2d39f
Author: Carlos Soriano <csoriano gnome org>
Date:   Wed Mar 4 19:13:57 2015 +0100

    gtkpathbar: listen to file changes and update pathbar
    
    It's something we have more or less for free in Nautilus
    given that we have all the backend in NautilusFile.
    
    Here we have to do it ourselves, but we fix a long old bug,
    and one of the most confusing things of gtkpathbar.

 gtk/gtkpathbar.c |  608 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 gtk/gtkpathbar.h |    5 +-
 2 files changed, 574 insertions(+), 39 deletions(-)
---
diff --git a/gtk/gtkpathbar.c b/gtk/gtkpathbar.c
index 7aa968c..de83dbf 100644
--- a/gtk/gtkpathbar.c
+++ b/gtk/gtkpathbar.c
@@ -41,6 +41,8 @@ struct _GtkPathBarPrivate
 
   GdkWindow *event_window;
 
+  GFile *current_path;
+
   GList *button_list;
   GList *first_scrolled_button;
   GtkWidget *up_slider_button;
@@ -92,6 +94,8 @@ struct _ButtonData
   gboolean is_root;
   char *dir_name;
   GFile *file;
+  GFileMonitor *monitor;
+  guint file_changed_signal_id;
   GtkWidget *image;
   GtkWidget *label;
   GCancellable *cancellable;
@@ -99,7 +103,22 @@ struct _ButtonData
   guint file_is_hidden : 1;
 };
 
-G_DEFINE_TYPE_WITH_PRIVATE (GtkPathBar, gtk_path_bar, GTK_TYPE_CONTAINER)
+typedef struct _SetFileInfo
+{
+  GFile *file;
+  GFile *parent_file;
+  GtkPathBar *path_bar;
+  GList *new_buttons;
+  gboolean first_directory;
+} SetFileInfo;
+
+typedef struct  _CreateButtonsParentsData {
+  GtkPathBar *path_bar;
+  GFile *current_file;
+  ButtonData *first_not_changed_button;
+} CreateButtonsParentsData;
+
+G_DEFINE_TYPE_WITH_PRIVATE (GtkPathBar, gtk_path_bar, GTK_TYPE_BOX)
 
 static void gtk_path_bar_finalize                 (GObject          *object);
 static void gtk_path_bar_dispose                  (GObject          *object);
@@ -144,9 +163,24 @@ static void gtk_path_bar_style_updated            (GtkWidget        *widget);
 static void gtk_path_bar_screen_changed           (GtkWidget        *widget,
                                                   GdkScreen        *previous_screen);
 static void gtk_path_bar_check_icon_theme         (GtkPathBar       *path_bar);
-static void gtk_path_bar_update_button_appearance (GtkPathBar       *path_bar,
-                                                  ButtonData       *button_data,
-                                                  gboolean          current_dir);
+static void gtk_path_bar_update_button_appearance_and_state (ButtonData       *button_data,
+                                                             gboolean          current_dir);
+static void gtk_path_bar_update_button_appearance (ButtonData       *button_data);
+static void gtk_path_bar_on_file_changed (GFileMonitor      *monitor,
+                                          GFile             *file,
+                                          GFile             *new_file,
+                                          GFileMonitorEvent  event_type,
+                                          gpointer          *user_data);
+static ButtonData * make_directory_button (GtkPathBar *path_bar,
+                                           const char *dir_name,
+                                           GFile      *file,
+                                           gboolean    current_dir,
+                                           gboolean    file_is_hidden);
+static void gtk_path_bar_get_info_callback (GObject      *source,
+                                            GAsyncResult *result,
+                                            gpointer      data);
+static void gtk_path_bar_create_buttons_parents_async (CreateButtonsParentsData *user_data);
+static void gtk_path_bar_update_path_async (GTask *task);
 
 static void
 gtk_path_bar_init (GtkPathBar *path_bar)
@@ -1089,7 +1123,7 @@ gtk_path_bar_stop_scrolling (GtkPathBar *path_bar)
 }
 
 static gboolean
-gtk_path_bar_slider_button_press (GtkWidget      *widget, 
+gtk_path_bar_slider_button_press (GtkWidget      *widget,
                                  GdkEventButton *event,
                                  GtkPathBar     *path_bar)
 {
@@ -1124,7 +1158,7 @@ gtk_path_bar_slider_button_press (GtkWidget      *widget,
 }
 
 static gboolean
-gtk_path_bar_slider_button_release (GtkWidget      *widget, 
+gtk_path_bar_slider_button_release (GtkWidget      *widget,
                                    GdkEventButton *event,
                                    GtkPathBar     *path_bar)
 {
@@ -1163,13 +1197,11 @@ reload_icons (GtkPathBar *path_bar)
   for (list = path_bar->priv->button_list; list; list = list->next)
     {
       ButtonData *button_data;
-      gboolean current_dir;
 
       button_data = BUTTON_DATA (list->data);
       if (button_data->type != NORMAL_BUTTON || button_data->is_root)
        {
-         current_dir = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data->button));
-         gtk_path_bar_update_button_appearance (path_bar, button_data, current_dir);
+         gtk_path_bar_update_button_appearance (button_data);
        }
     }
 
@@ -1365,7 +1397,15 @@ static void
 button_data_free (ButtonData *button_data)
 {
   if (button_data->file)
-    g_object_unref (button_data->file);
+    {
+      g_signal_handler_disconnect (button_data->monitor,
+                                   button_data->file_changed_signal_id);
+      button_data->file_changed_signal_id = 0;
+      g_object_unref (button_data->monitor);
+      g_object_unref (button_data->file);
+      button_data->file = NULL;
+      button_data->monitor= NULL;
+    }
   button_data->file = NULL;
 
   g_free (button_data->dir_name);
@@ -1386,9 +1426,7 @@ get_dir_name (ButtonData *button_data)
 }
 
 static void
-gtk_path_bar_update_button_appearance (GtkPathBar *path_bar,
-                                      ButtonData *button_data,
-                                      gboolean    current_dir)
+gtk_path_bar_update_button_appearance (ButtonData *button_data)
 {
   const gchar *dir_name = get_dir_name (button_data);
   GIcon *icon;
@@ -1407,13 +1445,19 @@ gtk_path_bar_update_button_appearance (GtkPathBar *path_bar,
     {
       gtk_widget_hide (GTK_WIDGET (button_data->image));
     }
+}
 
-  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data->button)) != current_dir)
-    {
-      button_data->ignore_changes = TRUE;
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_data->button), current_dir);
-      button_data->ignore_changes = FALSE;
-    }
+static void
+gtk_path_bar_update_button_appearance_and_state (ButtonData *button_data,
+                                                gboolean    current_dir)
+{
+       gtk_path_bar_update_button_appearance (button_data);
+
+        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data->button)) != current_dir) {
+                button_data->ignore_changes = TRUE;
+                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_data->button), current_dir);
+                button_data->ignore_changes = FALSE;
+        }
 }
 
 gboolean
@@ -1516,6 +1560,500 @@ button_drag_data_get_cb (GtkWidget        *widget,
 }
 
 static ButtonData *
+gtk_path_bar_find_button_from_file (GtkPathBar *path_bar,
+                                    GFile      *file)
+{
+  ButtonData *result = NULL;
+  ButtonData *button_data;
+  GList *list;
+
+  g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+  for (list = path_bar->priv->button_list; list; list = list->next)
+    {
+      button_data = list->data;
+      if (g_file_equal (file, button_data->file))
+        {
+          result = list->data;
+          break;
+        }
+    }
+
+  return result;
+}
+
+static ButtonData *
+gtk_path_bar_get_button_child (GtkPathBar *path_bar,
+                               ButtonData *button_data)
+{
+  ButtonData *result = NULL;
+  GList *list;
+
+  g_return_val_if_fail (button_data != NULL, NULL);
+
+  list = g_list_find (path_bar->priv->button_list, button_data);
+  result = list->prev != NULL? list->prev->data : NULL;
+
+  return result;
+}
+
+static void
+gtk_path_bar_button_data_unmonitor_file (ButtonData *button_data)
+{
+  g_return_if_fail (button_data != NULL);
+
+  if (button_data->file)
+    {
+      g_signal_handler_disconnect (button_data->monitor,
+                                   button_data->file_changed_signal_id);
+      button_data->file_changed_signal_id = 0;
+      g_object_unref (button_data->monitor);
+      g_object_unref (button_data->file);
+      button_data->file = NULL;
+      button_data->monitor= NULL;
+    }
+}
+
+static void
+gtk_path_bar_button_data_monitor_file (ButtonData *button_data)
+{
+  g_return_if_fail (button_data != NULL);
+
+  g_print ("monitor file %s\n", g_file_get_uri (button_data->file));
+  button_data->monitor = g_file_monitor (button_data->file, G_FILE_MONITOR_SEND_MOVED, NULL, NULL);
+  button_data->file_changed_signal_id = g_signal_connect (button_data->monitor, "changed",
+                                                                     G_CALLBACK 
(gtk_path_bar_on_file_changed),
+                                                                     button_data);
+}
+
+static void
+create_buttons_parents_data_free (CreateButtonsParentsData *data)
+{
+  /* Doesn't free the button data, since that's managed
+   * by the GtkPathBar */
+  g_object_unref (data->current_file);
+  g_slice_free (CreateButtonsParentsData, data);
+}
+
+static void
+gtk_path_bar_create_buttons_parents_on_get_info (GObject      *object,
+                                                 GAsyncResult *result,
+                                                 gpointer      user_data)
+{
+  const gchar *display_name;
+  ButtonData *button_data;
+  CreateButtonsParentsData *new_user_data;
+  CreateButtonsParentsData *received_user_data;
+  gboolean is_hidden;
+  GTask *task;
+  GtkPathBar *path_bar;
+  GFileInfo *info;
+  GFile *file;
+  GFile *parent_file;
+
+
+  received_user_data = (CreateButtonsParentsData *) user_data;
+  file = received_user_data->current_file;
+  info = g_file_query_info_finish (file, result, NULL);
+  path_bar = GTK_PATH_BAR (g_task_get_source_object (task));
+
+  g_return_if_fail (info != NULL);
+  g_return_if_fail (path_bar != NULL);
+
+  display_name = g_file_info_get_display_name (info);
+  is_hidden = g_file_info_get_is_hidden (info) || g_file_info_get_is_backup (info);
+  button_data =  make_directory_button (path_bar, display_name, file, FALSE, is_hidden);
+  path_bar->priv->button_list = g_list_append (path_bar->priv->button_list, button_data);
+  gtk_box_pack_start (GTK_BOX (path_bar), button_data->button, TRUE, TRUE, 0);
+
+  /* Update recursively if there is parent */
+  parent_file = g_file_get_parent (file);
+  if (parent_file != NULL && !button_data->is_root)
+    {
+      /* Set the children button data for operating on the next button */
+      new_user_data = g_slice_new (CreateButtonsParentsData);
+      new_user_data->current_file = g_object_ref (parent_file);
+      new_user_data->first_not_changed_button = received_user_data->first_not_changed_button;
+
+      gtk_path_bar_create_buttons_parents_async (new_user_data);
+    }
+  else
+    {
+      g_print ("no more buttons ended\n");
+      /* No more button, we finished */
+      g_task_return_pointer (task, NULL, NULL);
+    }
+
+  g_object_unref (info);
+}
+
+static void
+gtk_path_bar_create_buttons_parents_async (CreateButtonsParentsData *user_data)
+{
+  g_file_query_info_async (user_data->current_file,
+                           "standard::display-name,standard::is-hidden,standard::is-backup",
+                           G_FILE_QUERY_INFO_NONE,
+                           G_PRIORITY_DEFAULT,
+                           user_data->path_bar->priv->get_info_cancellable,
+                           gtk_path_bar_create_buttons_parents_on_get_info,
+                           user_data);
+}
+
+static void
+gtk_path_bar_create_buttons_parents (GtkPathBar          *path_bar,
+                                     ButtonData          *first_not_changed_button,
+                                     GFile               *new_file,
+                                     GAsyncReadyCallback  callback)
+{
+  CreateButtonsParentsData *user_data;
+
+  if (path_bar->priv->get_info_cancellable)
+    {
+      g_cancellable_cancel (path_bar->priv->get_info_cancellable);
+      g_object_unref (path_bar->priv->get_info_cancellable);
+    }
+
+  path_bar->priv->get_info_cancellable = g_cancellable_new ();
+
+  user_data = g_slice_new (CreateButtonsParentsData);
+  user_data ->current_file = g_file_get_parent (new_file);
+  user_data->first_not_changed_button = first_not_changed_button;
+
+  gtk_path_bar_create_buttons_parents_async (user_data);
+
+}
+
+static void
+gtk_path_bar_remove_buttons_parents (GtkPathBar *path_bar,
+                                     ButtonData *button_data)
+{
+
+  GList *l;
+  GList *next;
+
+  l = g_list_find (path_bar->priv->button_list, button_data);
+  g_return_if_fail (l != NULL);
+
+  l = l->next;
+  while (l != NULL)
+    {
+      next = l->next;
+      g_print ("remove parents %s\n", g_file_get_uri (BUTTON_DATA (l->data)->file));
+      gtk_widget_destroy (BUTTON_DATA (l->data)->button);
+      path_bar->priv->button_list = g_list_remove (path_bar->priv->button_list, l->data);
+      l = next;
+    }
+
+  child_ordering_changed (path_bar);
+}
+
+static void
+gtk_path_bar_remove_buttons_children (GtkPathBar *path_bar,
+                                      ButtonData *button_data)
+{
+  GList *l;
+  GList *prev;
+
+  l = g_list_find (path_bar->priv->button_list, button_data);
+  g_return_if_fail (l != NULL);
+
+  while (l != NULL)
+    {
+      prev = l->prev;
+      gtk_widget_destroy (BUTTON_DATA (l->data)->button);
+      path_bar->priv->button_list = g_list_remove (path_bar->priv->button_list, l->data);
+      l = prev;
+    }
+
+  child_ordering_changed (path_bar);
+}
+
+typedef struct  _UpdatePathData {
+  GFile *updated_file;
+  ButtonData *button_data;
+} UpdatePathData;
+
+static void
+update_path_data_free (UpdatePathData *update_path_data)
+{
+  /* Doesn't free the button data, since that's managed
+   * by the GtkPathBar */
+  g_object_unref (update_path_data->updated_file);
+  g_slice_free (UpdatePathData, update_path_data);
+}
+
+static void
+gtk_path_bar_update_path_on_get_info (GObject      *object,
+                                      GAsyncResult *result,
+                                      gpointer      user_data)
+{
+  const gchar *display_name;
+  ButtonData *button_data;
+  ButtonData *child_button_data;
+  UpdatePathData *update_path_data;
+  UpdatePathData *new_update_path_data;
+  GTask *task;
+  GtkPathBar *path_bar;
+  GFileInfo *info;
+  GFile *file;
+  gchar *child_basename;
+  GFile *updated_child_file;
+
+
+  task = (GTask*) user_data;
+  update_path_data = (UpdatePathData *) g_task_get_task_data (task);
+  button_data = update_path_data->button_data;
+  file = G_FILE (object);
+  g_print ("before button data %s\n", g_file_get_uri (file));
+  info = g_file_query_info_finish (file, result, NULL);
+  path_bar = GTK_PATH_BAR (g_task_get_source_object (task));
+
+  g_return_if_fail (info != NULL);
+  g_return_if_fail (path_bar != NULL);
+
+  display_name = g_file_info_get_display_name (info);
+
+  if (g_strcmp0 (display_name, button_data->dir_name) != 0)
+    {
+      g_free (button_data->dir_name);
+      button_data->dir_name = g_strdup (display_name);
+    }
+  gtk_path_bar_update_button_appearance (button_data);
+
+  /* Update recursively if there is a child */
+  child_button_data = gtk_path_bar_get_button_child (path_bar, button_data);
+  if (child_button_data != NULL)
+    {
+      /* Set the children button data for operating on the next button */
+      new_update_path_data = g_slice_new (UpdatePathData);
+      child_basename = g_file_get_basename (child_button_data->file);
+      updated_child_file = g_file_get_child (button_data->file, child_basename);
+      new_update_path_data->updated_file = g_object_ref (updated_child_file);
+      new_update_path_data->button_data = child_button_data;
+      g_task_set_task_data (task, new_update_path_data,
+                            (GDestroyNotify) update_path_data_free);
+
+      gtk_path_bar_update_path_async (task);
+    }
+  else
+    {
+      g_print ("null ended\n");
+      /* No more button, we finished */
+      g_task_return_pointer (task, NULL, NULL);
+    }
+
+  g_object_unref (info);
+}
+
+static void
+gtk_path_bar_update_path_async (GTask *task)
+{
+  ButtonData *button_data;
+  UpdatePathData *update_path_data;
+  GtkPathBar *path_bar;
+
+  update_path_data = (UpdatePathData *) g_task_get_task_data (task);
+  path_bar = GTK_PATH_BAR (g_task_get_source_object (task));
+
+  button_data = BUTTON_DATA (update_path_data->button_data);
+
+  /* Replace the old file with the new one */
+  if (g_file_equal (path_bar->priv->current_path, button_data->file))
+    {
+      path_bar->priv->current_path = update_path_data->updated_file;
+    }
+  gtk_path_bar_button_data_unmonitor_file (button_data);
+  button_data->file= g_object_ref (update_path_data->updated_file);
+  gtk_path_bar_button_data_monitor_file (button_data);
+
+  g_print ("asking info for %s\n", g_file_get_uri (button_data->file));
+  /* Ask for the user friendly name (display-name) and update the button label */
+  g_file_query_info_async (button_data->file,
+                           "standard::display-name",
+                           G_FILE_QUERY_INFO_NONE,
+                           G_PRIORITY_DEFAULT,
+                           NULL,
+                           gtk_path_bar_update_path_on_get_info,
+                           task);
+}
+
+static void
+gtk_path_bar_update_path (GtkPathBar          *path_bar,
+                          ButtonData          *button_data,
+                          GFile               *updated_file)
+{
+  GTask *task;
+  UpdatePathData *update_path_data;
+
+  update_path_data = g_slice_new (UpdatePathData);
+  update_path_data->updated_file = g_object_ref (updated_file);
+  update_path_data->button_data = button_data;
+
+  task = g_task_new (path_bar, NULL, callback, update_path_data);
+  g_task_set_task_data (task, update_path_data,
+                        (GDestroyNotify) update_path_data_free);
+
+  gtk_path_bar_update_path_async (task);
+}
+
+/* This will act acordingly to file changes that are monitored by the path bar.
+ * Here we are in a kind of trade-off. Is the path-bar the one that should take
+ * care of file changes and set the new file acordingly or should be the application
+ * the one that should take care of setting the correct file in the path bar?
+ *
+ * We will actually do a mix. For some cases is interesting that the path bar
+ * changes the buttons automatically withouth the need of the application to set
+ * a new path, and for others we can only rely on the application.
+ * Te path bar can't answer to all file changes, since we will need to listen
+ * to all the file system, that withouth the kernel support is barely imposible.
+ * On the other hand, we have to avoid inconsistency between the application and
+ * the path bar. Due to that, we won't change the displayed file, but instead
+ * only change the path bar buttons acordingly, and let the application set files
+ * if needed.
+ *
+ * Specific cases where we change the path bar is when a file is moved inside
+ * the current hierarchy of the path bar. If it is outside, we can't do nothing
+ * since we will need file system monitoring support.
+ *
+ * Specific cases where the path bar won't change at all is when some file
+ * above the current one displayed is deleted. In this case we will wait until
+ * the application make a decision instead of setting a well known file like
+ * the home directory, since that is just a convention and we can cause
+ * inconsistency between the path bar and the application.
+ */
+
+static void
+gtk_path_bar_on_file_changed (GFileMonitor      *monitor,
+                              GFile             *file,
+                              GFile             *new_file,
+                              GFileMonitorEvent  event_type,
+                              gpointer          *user_data)
+{
+  GFile *new_file_parent, *old_file_parent;
+  ButtonData *button_data;
+  ButtonData *innermost_button_data;
+  GFile *innermost_path;
+  GtkPathBar *path_bar;
+  gboolean renamed;
+
+  button_data = BUTTON_DATA (user_data);
+  path_bar = (GtkPathBar*) gtk_widget_get_ancestor (button_data->button,
+                                                    GTK_TYPE_PATH_BAR);
+  g_print ("event type %i\n", event_type);
+  g_print ("gtk_path_bar_on_file_changed %s, %s, %s\n", g_file_get_uri (file), g_file_get_uri 
(button_data->file), g_file_get_uri (path_bar->priv->current_path));
+  if (path_bar == NULL)
+    {
+      return;
+    }
+
+  g_assert (path_bar->priv->current_path!= NULL);
+
+  innermost_button_data = path_bar->priv->button_list->data;
+  innermost_path = innermost_button_data->file;
+
+  /* If the change doesn't affect directly any file in the path bar, don't do anything.
+   * This happens when one of the random children files of one of the folders in
+   * the path bar is modified, but that modified children file is not a children
+   * in the hierarchy of the pathbar. */
+  if (!g_file_has_prefix (innermost_path, file) && !g_file_equal (file, innermost_path))
+    return;
+
+  if (event_type == G_FILE_MONITOR_EVENT_MOVED)
+    {
+      g_print ("new file %s\n", g_file_get_uri (new_file));
+      if (new_file == NULL)
+        {
+          /* We can do nothing here but wait to the application to set a correct
+           * file... to be honest not sure why it happens.
+           * It happens when we move a file to a directory that is not being
+           * monitored; we receive a move event with a NULL new_file. */
+          gtk_path_bar_clear_buttons (path_bar);
+
+          return;
+        }
+
+      old_file_parent = g_file_get_parent (file);
+      new_file_parent = g_file_get_parent (new_file);
+
+      renamed = (old_file_parent != NULL && new_file_parent != NULL) &&
+                 g_file_equal (old_file_parent, new_file_parent);
+
+      g_clear_object (&old_file_parent);
+      g_clear_object (&new_file_parent);
+
+      if (renamed)
+        {
+          g_print ("renamed \n");
+          /* 1- Rename buttons from the modified one to the innermost button */
+          ButtonData *renamed_button_data;
+
+          renamed_button_data = gtk_path_bar_find_button_from_file (path_bar, file);
+          g_return_if_fail (renamed_button_data != NULL);
+          gtk_path_bar_update_path (path_bar, renamed_button_data, new_file);
+        }
+      else
+        {
+          if (g_file_has_prefix (file, path_bar->priv->current_path))
+            {
+              /* Moved file below the current path. We want to just remove the
+               * buttons below the moved file since they are in a diferent
+               * hierarchy now. To do:
+               * 1- Remove the buttons that are below the one that is moved */
+              g_print ("moved inside current path\n");
+              ButtonData *renamed_button_data;
+
+              renamed_button_data = gtk_path_bar_find_button_from_file (path_bar, file);
+              g_assert (renamed_button_data != NULL);
+              gtk_path_bar_remove_buttons_children (path_bar, renamed_button_data);
+            }
+          else
+            {
+              /* Moved file above the current path. To do:
+               * 1- Recreate parents buttons.
+               * 2- Rename buttons from the modified one to the innermost button */
+              ButtonData *renamed_button_data;
+
+              g_print ("moved outside current path\n");
+              renamed_button_data = gtk_path_bar_find_button_from_file (path_bar, file);
+              g_assert (renamed_button_data != NULL);
+              gtk_path_bar_remove_buttons_parents (path_bar, renamed_button_data);
+              gtk_path_bar_create_buttons_parents (path_bar, renamed_button_data, new_file, NULL);
+              gtk_path_bar_update_path (path_bar, renamed_button_data, new_file);
+            }
+
+          return;
+        }
+    }
+  else if (event_type == G_FILE_MONITOR_EVENT_DELETED)
+    {
+      /* if the current or a parent location are gone, clear all the buttons,
+       * and wait until the application sets a correct file...
+       */
+      if (g_file_has_prefix (path_bar->priv->current_path, file) ||
+          g_file_equal (path_bar->priv->current_path, file))
+        {
+          /* Deleted file above current path.
+           * We can do nothing here but wait to the application to set a correct
+           * file... to be honest not sure why it happens. */
+          g_print ("deleted above current\n");
+          gtk_path_bar_clear_buttons (path_bar);
+        }
+      else if (g_file_has_prefix (file, path_bar->priv->current_path))
+        {
+          /* Deleted file below the current path. We want to just remove the
+           * buttons below the deleted file:
+           * 1- Remove the buttons that are below the one that is moved */
+          g_print ("deleted below current\n");
+          ButtonData *renamed_button_data;
+
+          renamed_button_data = gtk_path_bar_find_button_from_file (path_bar, file);
+          g_assert (renamed_button_data != NULL);
+          gtk_path_bar_remove_buttons_children (path_bar, renamed_button_data);
+        }
+    }
+}
+
+static ButtonData *
 make_directory_button (GtkPathBar  *path_bar,
                       const char  *dir_name,
                       GFile       *file,
@@ -1559,11 +2097,12 @@ make_directory_button (GtkPathBar  *path_bar,
   button_data->dir_name = g_strdup (dir_name);
   button_data->file = g_object_ref (file);
   button_data->file_is_hidden = file_is_hidden;
+  gtk_path_bar_button_data_monitor_file (button_data);
 
   gtk_container_add (GTK_CONTAINER (button_data->button), child);
   gtk_widget_show_all (button_data->button);
 
-  gtk_path_bar_update_button_appearance (path_bar, button_data, current_dir);
+  gtk_path_bar_update_button_appearance_and_state (button_data, current_dir);
 
   g_signal_connect (button_data->button, "clicked",
                    G_CALLBACK (button_clicked_cb),
@@ -1605,9 +2144,8 @@ gtk_path_bar_check_parent_path (GtkPathBar         *path_bar,
     {
       for (list = path_bar->priv->button_list; list; list = list->next)
        {
-         gtk_path_bar_update_button_appearance (path_bar,
-                                                BUTTON_DATA (list->data),
-                                                (list == current_path) ? TRUE : FALSE);
+         gtk_path_bar_update_button_appearance_and_state (BUTTON_DATA (list->data),
+                                                           (list == current_path) ? TRUE : FALSE);
        }
 
       if (!gtk_widget_get_child_visible (BUTTON_DATA (current_path->data)->button))
@@ -1621,18 +2159,8 @@ gtk_path_bar_check_parent_path (GtkPathBar         *path_bar,
   return FALSE;
 }
 
-
-struct SetFileInfo
-{
-  GFile *file;
-  GFile *parent_file;
-  GtkPathBar *path_bar;
-  GList *new_buttons;
-  gboolean first_directory;
-};
-
 static void
-gtk_path_bar_set_file_finish (struct SetFileInfo *info,
+gtk_path_bar_set_file_finish (SetFileInfo *info,
                               gboolean            result)
 {
   if (result)
@@ -1681,7 +2209,7 @@ gtk_path_bar_get_info_callback (GObject      *source,
   GFile *file = G_FILE (source);
   GFileInfo *info;
   GError *error;
-  struct SetFileInfo *file_info = data;
+  SetFileInfo *file_info = data;
   ButtonData *button_data;
   const gchar *display_name;
   gboolean is_hidden;
@@ -1739,18 +2267,24 @@ _gtk_path_bar_set_file (GtkPathBar *path_bar,
                         GFile      *file,
                         gboolean    keep_trail)
 {
-  struct SetFileInfo *info;
+  SetFileInfo *info;
 
   g_return_if_fail (GTK_IS_PATH_BAR (path_bar));
   g_return_if_fail (G_IS_FILE (file));
 
+  if (path_bar->priv->current_path != NULL)
+    {
+      g_object_unref (path_bar->priv->current_path);
+    }
+  path_bar->priv->current_path = g_object_ref (file);
+
   /* Check whether the new path is already present in the pathbar as buttons.
    * This could be a parent directory or a previous selected subdirectory.
    */
   if (keep_trail && gtk_path_bar_check_parent_path (path_bar, file))
     return;
 
-  info = g_new0 (struct SetFileInfo, 1);
+  info = g_new0 (SetFileInfo, 1);
   info->file = g_object_ref (file);
   info->path_bar = path_bar;
   info->first_directory = TRUE;
diff --git a/gtk/gtkpathbar.h b/gtk/gtkpathbar.h
index 8b96b70..9b1e45b 100644
--- a/gtk/gtkpathbar.h
+++ b/gtk/gtkpathbar.h
@@ -19,6 +19,7 @@
 #define __GTK_PATH_BAR_H__
 
 #include "gtkcontainer.h"
+#include "gtkbox.h"
 #include "gtkfilesystem.h"
 
 G_BEGIN_DECLS
@@ -37,14 +38,14 @@ typedef struct _GtkPathBarPrivate GtkPathBarPrivate;
 
 struct _GtkPathBar
 {
-  GtkContainer parent;
+  GtkBox parent;
 
   GtkPathBarPrivate *priv;
 };
 
 struct _GtkPathBarClass
 {
-  GtkContainerClass parent_class;
+  GtkBoxClass parent_class;
 
   void (* path_clicked) (GtkPathBar  *path_bar,
                         GFile       *file,



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