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



commit b3b7f233696b719519d4b923b8d3a92830fd338d
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 |  775 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 gtk/gtkpathbar.h |    5 +-
 2 files changed, 744 insertions(+), 36 deletions(-)
---
diff --git a/gtk/gtkpathbar.c b/gtk/gtkpathbar.c
index 2eddd1b..6f092d5 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;
@@ -91,6 +93,8 @@ struct _ButtonData
   gboolean is_root;
   char *dir_name;
   GFile *file;
+  GFileMonitor *monitor;
+  guint file_changed_signal_id;
   GtkWidget *image;
   GtkWidget *label;
   GCancellable *cancellable;
@@ -98,7 +102,7 @@ struct _ButtonData
   guint file_is_hidden : 1;
 };
 
-G_DEFINE_TYPE_WITH_PRIVATE (GtkPathBar, gtk_path_bar, GTK_TYPE_CONTAINER)
+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);
@@ -143,9 +147,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 (GTask *task);
+static void gtk_path_bar_update_path_async (GTask *task);
 
 static void
 gtk_path_bar_init (GtkPathBar *path_bar)
@@ -1160,13 +1179,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);
        }
     }
   
@@ -1264,6 +1281,8 @@ button_clicked_cb (GtkWidget *button,
       child_is_hidden = FALSE;
     }
 
+  g_print ("button clicked %s\n", g_file_get_uri (button_data->file));
+
   g_signal_emit (path_bar, path_bar_signals [PATH_CLICKED], 0,
                 button_data->file, child_file, child_is_hidden);
 }
@@ -1362,12 +1381,21 @@ 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);
   button_data->dir_name = NULL;
 
+  g_print ("freeing button\n");
   button_data->button = NULL;
 
   if (button_data->cancellable)
@@ -1383,9 +1411,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;
@@ -1404,13 +1430,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
@@ -1513,6 +1545,603 @@ 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);
+
+  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);
+}
+
+#if 0
+static void
+gtk_path_bar_add_required_buttons (GtkPathBar *path_bar,
+                                   ButtonData *button_data,
+                                   GFile      *new_file)
+{
+  GList *l;
+  GList *prev;
+  GFile *old_file;
+  GFile *old_parent;
+  GFile *current_evaluated_file;
+
+  l = g_list_find (path_bar->priv->button_list, button_data);
+  g_return_if_fail (l != NULL);
+  old_file = button_data->file;
+  old_parent = g_file_get_parent (old_file);
+  /* Start from the direct parent */
+  current_evaluated_file = g_file_get_parent (new_file);
+
+  while (current_evaluated_file != NULL &&
+         g_file_has_prefix (current_evaluated_file, old_parent))
+    {
+      g_print ("while add required %s, %s\n", g_file_get_uri (BUTTON_DATA (l->data)->file), g_file_get_uri 
(new_parent));
+      next = l->next;
+      g_print ("inside\n");
+      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_dangling_buttons_above (GtkPathBar *path_bar,
+                                            ButtonData *button_data,
+                                            GFile      *new_file)
+{
+  GList *l;
+  GList *next;
+  GFile *new_parent;
+
+  l = g_list_find (path_bar->priv->button_list, button_data);
+  g_return_if_fail (l != NULL);
+  new_parent = g_file_get_parent (new_file);
+
+  /* Start in the next outermost button after the one that actually changed */
+  l = l->next;
+  while (l != NULL)
+    {
+      g_print ("while %s, %s\n", g_file_get_uri (BUTTON_DATA (l->data)->file), g_file_get_uri (new_parent));
+      if (g_file_has_prefix (BUTTON_DATA (l->data)->file, new_parent))
+        {
+          next = l->next;
+          g_print ("inside\n");
+          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;
+        }
+      else
+        {
+          break;
+        }
+    }
+
+  child_ordering_changed (path_bar);
+  g_object_unref (new_parent);
+}
+
+#endif
+
+typedef struct _SetFileInfo
+{
+  GFile *file;
+  GFile *parent_file;
+  GtkPathBar *path_bar;
+  GList *new_buttons;
+  gboolean first_directory;
+} SetFileInfo;
+
+typedef struct  _CreateButtonsParentsData {
+  GFile *current_file;
+  ButtonData *first_not_changed_button;
+} CreateButtonsParentsData;
+
+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 *task_data;
+  CreateButtonsParentsData *new_task_data;
+  gboolean is_hidden;
+  GTask *task;
+  GtkPathBar *path_bar;
+  GFileInfo *info;
+  GFile *file;
+  GFile *parent_file;
+
+
+  task = (GTask*) user_data;
+  task_data = (CreateButtonsParentsData *) g_task_get_task_data (task);
+  file = task_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);
+  g_print ("child data ok\n");
+  if (parent_file != NULL && !button_data->is_root)
+    {
+      /* Set the children button data for operating on the next button */
+      new_task_data = g_slice_new (CreateButtonsParentsData);
+      new_task_data->current_file = g_object_ref (parent_file);
+      new_task_data->first_not_changed_button = task_data->first_not_changed_button;
+      g_task_set_task_data (task, new_task_data,
+                            (GDestroyNotify) create_buttons_parents_data_free);
+
+      gtk_path_bar_create_buttons_parents_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_create_buttons_parents_async (GTask *task)
+{
+  GtkPathBar *path_bar;
+  CreateButtonsParentsData *task_data;
+
+  path_bar = GTK_PATH_BAR (g_task_get_source_object (task));
+  task_data = (CreateButtonsParentsData *) g_task_get_task_data (task);
+
+  g_print ("creating parents info for %s\n", g_file_get_uri (task_data->current_file));
+
+  g_file_query_info_async (task_data->current_file,
+                           "standard::display-name,standard::is-hidden,standard::is-backup",
+                           G_FILE_QUERY_INFO_NONE,
+                           G_PRIORITY_DEFAULT,
+                           path_bar->priv->get_info_cancellable,
+                           gtk_path_bar_create_buttons_parents_on_get_info,
+                           task);
+}
+
+static void
+gtk_path_bar_create_buttons_parents (GtkPathBar          *path_bar,
+                                     ButtonData          *first_not_changed_button,
+                                     GFile               *new_file,
+                                     GAsyncReadyCallback  callback)
+{
+  SetFileInfo *info;
+  CreateButtonsParentsData *task_data;
+
+  info = g_new0 (SetFileInfo, 1);
+  info->file = g_object_ref (new_file);
+  info->path_bar = path_bar;
+  info->first_directory = FALSE;
+  info->parent_file = g_file_get_parent (info->file);
+
+  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 ();
+
+
+  GTask *task;
+
+  task = g_task_new (path_bar, NULL, callback, new_file);
+  task_data = g_slice_new (CreateButtonsParentsData);
+  task_data ->current_file = g_file_get_parent (new_file);
+  task_data->first_not_changed_button = first_not_changed_button;
+  g_task_set_task_data (task, task_data, (GDestroyNotify) create_buttons_parents_data_free);
+
+  gtk_path_bar_create_buttons_parents_async (task);
+
+}
+
+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;
+      g_print ("inside %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 = 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_on_update_path_finished (GObject      *object,
+                                      GAsyncResult *result,
+                                      gpointer      user_data)
+{
+  g_print ("callback called!\n");
+  GtkPathBar *path_bar;
+
+  path_bar = GTK_PATH_BAR (object);
+}
+
+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);
+    }
+  g_print ("in get info\n");
+  gtk_path_bar_update_button_appearance (button_data);
+  g_print ("updated appearance\n");
+
+  /* Update recursively if there is a child */
+  child_button_data = gtk_path_bar_get_button_child (path_bar, button_data);
+  g_print ("child data ok\n");
+  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,
+                          GAsyncReadyCallback  callback)
+{
+  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);
+}
+
+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)
+    {
+
+      old_file_parent = g_file_get_parent (file);
+      new_file_parent = g_file_get_parent (new_file);
+      g_print ("new file %s\n", g_file_get_uri (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,
+                                   (GAsyncReadyCallback) gtk_path_bar_on_update_path_finished);
+        }
+      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 dangling buttons, those are 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);
+              gtk_path_bar_remove_buttons_children (path_bar, renamed_button_data);
+            }
+          else
+            {
+              /* Moved file above the current path. To do:
+               * 1- Remove the dangling buttons, those are the buttons that are
+               * parents of the old file and are no longer children of the old file
+               * parent.
+               * 2- Create necesary buttons if we moved to a longer path.
+               * 3- 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,
+                                        (GAsyncReadyCallback) gtk_path_bar_on_update_path_finished);
+            }
+
+          return;
+        }
+    }
+#if 0
+  else if (event_type == G_FILE_MONITOR_EVENT_DELETED)
+    {
+      gint idx, position;
+      /* if the current or a parent location are gone, clear all the buttons,
+       * the view will set the new path.
+       */
+      if (g_file_has_prefix (path_bar->priv->current_path, file) ||
+          g_file_equal (path_bar->priv->current_path, file))
+        {
+          g_print ("deleted below current\n");
+          gtk_path_bar_clear_buttons (path_bar);
+        }
+      else if (g_file_has_prefix (file, path_bar->priv->current_path))
+        {
+          g_print ("deleted below current\n");
+          /* remove this and the following buttons */
+          position = g_list_position (path_bar->priv->button_list,
+                     g_list_find (path_bar->priv->button_list, button_data));
+
+          if (position != -1)
+            {
+              for (idx = 0; idx <= position; idx++)
+                {
+                  gtk_container_remove (GTK_CONTAINER (path_bar),
+                                        BUTTON_DATA (path_bar->priv->button_list->data)->button);
+                }
+            }
+        }
+
+
+      return;
+    }
+
+#endif
+
+  /* MOUNTs use the GMount as the name, so don't update for those */
+}
+
+static ButtonData *
 make_directory_button (GtkPathBar  *path_bar,
                       const char  *dir_name,
                       GFile       *file,
@@ -1557,10 +2186,15 @@ make_directory_button (GtkPathBar  *path_bar,
   button_data->file = g_object_ref (file);
   button_data->file_is_hidden = file_is_hidden;
 
+  button_data->monitor = g_file_monitor (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);
+
   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),
@@ -1602,9 +2236,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))
@@ -1619,17 +2252,8 @@ gtk_path_bar_check_parent_path (GtkPathBar         *path_bar,
 }
 
 
-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)
@@ -1656,6 +2280,7 @@ gtk_path_bar_set_file_finish (struct SetFileInfo *info,
          ButtonData *button_data;
 
          button_data = BUTTON_DATA (l->data);
+         g_print ("freeing button\n");
          gtk_widget_destroy (button_data->button);
        }
 
@@ -1670,6 +2295,80 @@ gtk_path_bar_set_file_finish (struct SetFileInfo *info,
   g_free (info);
 }
 
+#if 0
+static void
+gtk_path_bar_update_path (GtkPathBar *path_bar,
+                          GFile      *file)
+{
+  gboolean first_directory;
+  GList *new_buttons, *l;
+  ButtonData *button_data;
+
+  g_return_if_fail (NAUTILUS_IS_PATH_BAR (path_bar));
+  g_return_if_fail (file_path != NULL);
+
+  selected_directory = TRUE;
+  new_buttons = NULL;
+
+  while (file != NULL)
+    {
+      GFile *parent_file;
+
+      parent_file = g_file_get_parent (file);
+      button_data = make_button_data (path_bar, file, first_directory);
+      g_object_unref (file);
+
+      if (selected_directory)
+        {
+          selected_directory = FALSE;
+        }
+
+      new_buttons = g_list_prepend (new_buttons, button_data);
+
+      if (parent_file != NULL && button_data->is_root)
+        {
+          nautilus_file_unref (parent_file);
+          break;
+                   }
+
+      file = parent_file;
+     }
+
+  gtk_path_bar_clear_buttons (path_bar);
+  path_bar->priv->button_list = g_list_reverse (new_buttons);
+
+  for (l = path_bar->priv->button_list; l; l = l->next)
+    {
+      GtkWidget *button;
+      button = BUTTON_DATA (l->data)->button;
+      gtk_container_add (GTK_CONTAINER (path_bar), button);
+    }
+
+       child_ordering_changed (path_bar);
+}
+
+static void
+gtk_path_bar_fetch_info (GtkPathBar *path_bar,
+                         GFile      *file)
+{
+  struct SetFileInfo *info;
+
+  info = g_new0 (struct SetFileInfo, 1);
+  info->file = g_object_ref (file);
+  info->path_bar = path_bar;
+  info->first_directory = TRUE;
+  info->parent_file = g_file_get_parent (info->file);
+
+  g_file_query_info_async (file,
+                           "standard::display-name,standard::is-hidden,standard::is-backup",
+                           G_FILE_QUERY_INFO_NONE,
+                           G_PRIORITY_DEFAULT,
+                           path_bar->priv->get_info_cancellable,
+                           gtk_path_bar_get_info_callback,
+                           info);
+}
+#endif
+
 static void
 gtk_path_bar_get_info_callback (GObject      *source,
                                 GAsyncResult *result,
@@ -1678,12 +2377,13 @@ 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;
 
   info = g_file_query_info_finish (file, result, &error);
+  g_print ("get info callback %s\n", g_file_get_uri (file));
 
   if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) || !info)
     {
@@ -1736,18 +2436,25 @@ _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);
+
+  g_print ("set file %s\n", g_file_get_uri (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]