[gtk+/wip/csoriano/pathbar-prototype: 45/46] work on implementing root



commit e54341e76647ad57e086fbabe118ecd4389d3a24
Author: Carlos Soriano <csoriano gnome org>
Date:   Thu Nov 19 17:24:05 2015 +0100

    work on implementing root

 gtk/gtkpathbar.c    |  296 +++++++++++++++++++++++++++++++++++++++------------
 tests/testpathbar.c |    4 +-
 2 files changed, 231 insertions(+), 69 deletions(-)
---
diff --git a/gtk/gtkpathbar.c b/gtk/gtkpathbar.c
index 813b8fa..0d3ae8f 100644
--- a/gtk/gtkpathbar.c
+++ b/gtk/gtkpathbar.c
@@ -70,6 +70,10 @@ struct _GtkPathBarPrivate
   GtkWidget *overflow_button_2;
   GtkWidget *path_chunk_popover_container;
 
+  GIcon *root_icon;
+  gchar *root_label;
+  gchar *root_path;
+
   gchar *path;
   gchar *selected_path;
   gboolean hide_direction;
@@ -247,7 +251,6 @@ create_path_chunk (GtkPathBar    *self,
   direction = gtk_widget_get_direction (GTK_WIDGET (self));
 
   path_chunk = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-
   button = gtk_toggle_button_new ();
   button_label = gtk_label_new (label);
   gtk_label_set_ellipsize (GTK_LABEL (button_label), PANGO_ELLIPSIZE_MIDDLE);
@@ -257,11 +260,11 @@ create_path_chunk (GtkPathBar    *self,
                              MIN (g_utf8_strlen (label, -1), 10));
   gtk_container_add (GTK_CONTAINER (button), button_label);
 
-  g_signal_connect_swapped (button, "button-release-event",
-                            G_CALLBACK (on_path_chunk_button_release_event), path_chunk);
   style = gtk_widget_get_style_context (button);
   gtk_style_context_add_class (style, "flat");
 
+  g_signal_connect_swapped (button, "button-release-event",
+                            G_CALLBACK (on_path_chunk_button_release_event), path_chunk);
   if (add_separator)
     {
       separator = gtk_label_new ("/");
@@ -292,6 +295,76 @@ create_path_chunk (GtkPathBar    *self,
   return path_chunk;
 }
 
+static GtkWidget*
+create_root_chunk (GtkPathBar *self)
+{
+  GtkPathBarPrivate *priv = gtk_path_bar_get_instance_private (self);
+  GtkWidget *button;
+  GtkWidget *separator;
+  GtkWidget *path_chunk = NULL;
+  GtkWidget *button_label;
+  GtkWidget *image;
+  GtkStyleContext *style;
+  PathChunkData *path_chunk_data;
+  GtkTextDirection direction;
+
+  if (priv->root_label || priv->root_icon)
+    {
+      direction = gtk_widget_get_direction (GTK_WIDGET (self));
+
+      path_chunk = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+      button = gtk_toggle_button_new ();
+      if (priv->root_label)
+        {
+          button_label = gtk_label_new (priv->root_label);
+          gtk_label_set_ellipsize (GTK_LABEL (button_label), PANGO_ELLIPSIZE_MIDDLE);
+          gtk_button_set_label (GTK_BUTTON (path_chunk), priv->root_label);
+          // FIXME: the GtkLabel requests more than the number of chars set here.
+          // For visual testing for now substract 2 chars.
+          gtk_label_set_width_chars (GTK_LABEL (button_label),
+                                     MIN (g_utf8_strlen (priv->root_label, -1), 10));
+          gtk_container_add (GTK_CONTAINER (button), button_label);
+        }
+
+      if (priv->root_icon)
+        {
+          image = gtk_image_new_from_gicon (priv->root_icon, GTK_ICON_SIZE_MENU);
+          gtk_button_set_image (GTK_BUTTON (path_chunk), image);
+        }
+
+      style = gtk_widget_get_style_context (button);
+      gtk_style_context_add_class (style, "flat");
+
+      g_signal_connect_swapped (button, "button-release-event",
+                                G_CALLBACK (on_path_chunk_button_release_event), path_chunk);
+
+      separator = gtk_label_new ("/");
+      gtk_widget_set_sensitive (separator, FALSE);
+      gtk_container_add (GTK_CONTAINER (path_chunk), separator);
+
+      if (direction == GTK_TEXT_DIR_LTR)
+        {
+          gtk_container_add (GTK_CONTAINER (path_chunk), button);
+          gtk_container_add (GTK_CONTAINER (path_chunk), separator);
+        } else {
+          gtk_container_add (GTK_CONTAINER (path_chunk), separator);
+          gtk_container_add (GTK_CONTAINER (path_chunk), button);
+        }
+
+      path_chunk_data = g_slice_new (PathChunkData);
+      path_chunk_data->label = g_strdup (priv->root_label);
+      path_chunk_data->path = g_string_new (priv->root_path);
+      path_chunk_data->path_bar = self;
+      path_chunk_data->button = path_chunk;
+      g_object_set_data_full (G_OBJECT (path_chunk), "data",
+                              path_chunk_data, (GDestroyNotify) free_path_chunk_data);
+
+      gtk_widget_show_all (path_chunk);
+    }
+
+  return path_chunk;
+}
+
 static void
 on_entry_activate (GtkPathBar *self)
 {
@@ -301,9 +374,97 @@ on_entry_activate (GtkPathBar *self)
   gtk_path_bar_set_path (self, gtk_entry_get_text (GTK_ENTRY (priv->edit_entry)));
 }
 
+static gboolean
+check_path_format (const gchar *path)
+{
+  gchar ** splitted_path;
+  gboolean valid = FALSE;
+
+  splitted_path = g_strsplit (path, "/", -1);
+
+  if (g_strv_length (splitted_path) == 0)
+    goto out;
+
+  if (!g_utf8_validate (path, -1, NULL))
+    goto out;
+
+  for (guint i = 0; i < g_strv_length (splitted_path); i++)
+    {
+      /* First and last part of the path is always empty when splitted */
+      if (g_strcmp0 (splitted_path[i], "") == 0 && i != 0)
+        goto out;
+    }
+  /* Path must start with "/" */
+  if (g_strcmp0 (splitted_path[0], "") != 0)
+    goto out;
+
+  valid = TRUE;
+
+out:
+  g_strfreev (splitted_path);
+
+  return valid;
+}
+
 static void
-update_selected_path (GtkPathBar  *self,
-                      const gchar *path)
+update_path_bar (GtkPathBar  *self)
+{
+  GtkPathBarPrivate *priv = gtk_path_bar_get_instance_private (self);
+  gchar ** splitted_path;
+  GString *current_path = NULL;
+  GtkWidget *path_chunk;
+  GtkWidget *path_box;
+  GtkWidget *overflow_button;
+  GtkWidget *path_bar;
+  GtkWidget *root_chunk;
+  gchar *unprefixed_path = NULL;
+
+  get_path_bar_widgets (GTK_PATH_BAR (self), &path_bar, &overflow_button, &path_box, FALSE);
+
+  /* Make sure we dismiss all popovers */
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->overflow_button_1), FALSE);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->overflow_button_2), FALSE);
+
+  gtk_container_foreach (GTK_CONTAINER (path_box), (GtkCallback) gtk_widget_destroy, NULL);
+
+  root_chunk = create_root_chunk (self);
+  if (root_chunk)
+    gtk_container_add (GTK_CONTAINER (path_box), root_chunk);
+
+  /* Remove root path */
+  if (priv->root_path)
+    unprefixed_path = g_utf8_substring (priv->path, strlen (priv->root_path) - 1,
+                                        strlen (priv->path) -1);
+  else
+    unprefixed_path = g_strdup (priv->path);
+
+  splitted_path = g_strsplit (unprefixed_path, "/", -1);
+  current_path = g_string_new ("");
+
+  for (guint i = 0; i < g_strv_length (splitted_path); i++)
+    {
+      if (g_strcmp0 (splitted_path[0], "") == 0 && i == 0)
+        continue;
+
+      g_string_append (current_path, "/");
+      g_string_append (current_path, splitted_path[i]);
+
+      path_chunk = create_path_chunk (self, current_path, splitted_path[i],
+                                      i != g_strv_length (splitted_path) - 1);
+      gtk_container_add (GTK_CONTAINER (path_box), path_chunk);
+    }
+
+  gtk_entry_set_text (GTK_ENTRY (priv->edit_entry), priv->path);
+
+  gtk_stack_set_visible_child (GTK_STACK (priv->path_bar_containers_stack), path_bar);
+
+  g_strfreev (splitted_path);
+  g_free (unprefixed_path);
+  g_string_free (current_path, TRUE);
+}
+
+static void
+update_selected_path (GtkPathBar  *self)
 {
   GtkPathBarPrivate *priv = gtk_path_bar_get_instance_private (self);
   PathChunkData *data;
@@ -326,14 +487,14 @@ update_selected_path (GtkPathBar  *self,
     {
       data = g_object_get_data (G_OBJECT (l->data), "data");
       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (data->button),
-                                    g_strcmp0 (data->path->str, path) == 0);
+                                    g_strcmp0 (data->path->str, priv->selected_path) == 0);
     }
 
   for (l = overflow_children; l != NULL; l = l->next)
     {
       data = g_object_get_data (G_OBJECT (l->data), "data");
       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (data->button),
-                                    g_strcmp0 (data->path->str, path) == 0);
+                                    g_strcmp0 (data->path->str, priv->selected_path) == 0);
     }
 
   g_list_free (children);
@@ -345,7 +506,6 @@ update_selected_path (GtkPathBar  *self,
 static void
 populate_overflow_popover (GtkPathBar *self)
 {
-  GtkPathBarPrivate *priv = gtk_path_bar_get_instance_private (self);
   GList *overflow_children;
   GList *l;
   PathChunkData *data;
@@ -371,7 +531,7 @@ populate_overflow_popover (GtkPathBar *self)
       gtk_container_add (GTK_CONTAINER (overflow_container), path_chunk);
     }
 
-  update_selected_path (self, (const gchar *) priv->selected_path);
+  update_selected_path (self);
 
   g_list_free (overflow_children);
 }
@@ -591,74 +751,22 @@ gtk_path_bar_set_path (GtkPathBar  *self,
                        const gchar *path)
 {
   GtkPathBarPrivate *priv;
-  gchar ** splitted_path;
-  GString *current_path = NULL;
-  GtkWidget *path_chunk;
-  PathChunkData *data;
-  GList *children;
-  GtkWidget *path_box;
-  GtkWidget *overflow_button;
-  GtkWidget *path_bar;
 
   g_return_if_fail (GTK_IS_PATH_BAR (self));
+  g_return_if_fail (check_path_format (path));
 
   priv = gtk_path_bar_get_instance_private (GTK_PATH_BAR (self));
 
   if (g_strcmp0 (priv->path, path) == 0)
     return;
 
-  get_path_bar_widgets (GTK_PATH_BAR (self), &path_bar, &overflow_button, &path_box, FALSE);
-
-  /* Make sure we dismiss all popovers */
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->overflow_button_1), FALSE);
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->overflow_button_2), FALSE);
-
-  gtk_container_foreach (GTK_CONTAINER (path_box), (GtkCallback) gtk_widget_destroy, NULL);
-
   if (priv->path)
-    {
-      g_free (priv->path);
-      priv->path = NULL;
-    }
-
-  if (priv->selected_path)
-    {
-      g_free (priv->selected_path);
-      priv->selected_path = NULL;
-    }
-
-  splitted_path = g_strsplit (path, "/", -1);
-  current_path = g_string_new ("");
-
-  for (guint i = 0; i < g_strv_length (splitted_path); i++)
-    {
-      if (g_strcmp0 (splitted_path[i], "") == 0)
-        continue;
-
-      g_string_append (current_path, "/");
-      g_string_append (current_path, splitted_path[i]);
-      path_chunk = create_path_chunk (self, current_path, splitted_path[i], TRUE);
-      gtk_container_add (GTK_CONTAINER (path_box), path_chunk);
-    }
-
-  children = gtk_container_get_children (GTK_CONTAINER (path_box));
-  if (children != NULL)
-    {
-      path_chunk = GTK_WIDGET (g_list_last (children)->data);
-      data = g_object_get_data (G_OBJECT (path_chunk), "data");
-      priv->path = g_strdup (data->path->str);
-    }
-
-  gtk_entry_set_text (GTK_ENTRY (priv->edit_entry), priv->path);
+    g_free (priv->path);
+  priv->path = g_strdup (path);
 
-  gtk_stack_set_visible_child (GTK_STACK (priv->path_bar_containers_stack), path_bar);
+  update_path_bar (self);
   g_object_notify_by_pspec (G_OBJECT (self), path_bar_properties[PROP_PATH]);
-
   gtk_path_bar_set_selected_path (self, priv->path);
-
-  g_strfreev (splitted_path);
-  g_string_free (current_path, TRUE);
-  g_list_free (children);
 }
 
 /**
@@ -704,7 +812,9 @@ gtk_path_bar_set_selected_path (GtkPathBar  *self,
 
   priv = gtk_path_bar_get_instance_private (GTK_PATH_BAR (self));
 
-  g_return_if_fail (g_str_has_prefix (priv->path, path));
+  g_print ("set selected %s %s\n", priv->path, path);
+  g_return_if_fail (g_str_has_prefix (priv->path, path) ||
+                    g_strcmp0 (priv->path, path) == 0);
 
   if (g_strcmp0 (priv->selected_path, path) != 0)
     {
@@ -712,9 +822,14 @@ gtk_path_bar_set_selected_path (GtkPathBar  *self,
         g_free (priv->selected_path);
 
       priv->selected_path = g_strdup (path);
-      update_selected_path (self, path);
+      update_selected_path (self);
       g_object_notify_by_pspec (G_OBJECT (self), path_bar_properties[PROP_SELECTED_PATH]);
     }
+  else
+    {
+      /* Update the style in any case */
+      update_selected_path (self);
+    }
 }
 
 /**
@@ -818,6 +933,53 @@ gtk_path_bar_set_edit_mode_enabled (GtkPathBar *self,
     }
 }
 
+void
+gtk_path_bar_set_root (GtkPathBar  *self,
+                       GIcon       *icon,
+                       const gchar *label,
+                       const gchar *path)
+{
+  GtkPathBarPrivate *priv ;
+
+  g_return_if_fail (GTK_IS_PATH_BAR (self));
+  priv = gtk_path_bar_get_instance_private (GTK_PATH_BAR (self));
+
+  if (path)
+    {
+      g_return_if_fail (g_str_has_prefix (priv->path, path) ||
+                        g_strcmp0 (priv->path, path) == 0);
+      g_return_if_fail (label || icon);
+
+    }
+
+  if (priv->root_icon)
+    {
+      g_object_unref (priv->root_icon);
+      priv->root_icon = NULL;
+    }
+  if (icon)
+    priv->root_icon = g_object_ref (icon);
+
+  if (priv->root_label)
+    {
+      g_free (priv->root_label);
+      priv->root_label = NULL;
+    }
+  if (label)
+    priv->root_label = g_strdup (label);
+
+  if (priv->root_path)
+    {
+      g_free (priv->root_path);
+      priv->root_path = NULL;
+    }
+  if (path)
+    priv->root_path = g_strdup (path);
+
+  update_path_bar (self);
+  update_selected_path (self);
+}
+
 GtkWidget *
 gtk_path_bar_new (void)
 {
diff --git a/tests/testpathbar.c b/tests/testpathbar.c
index 39a3a3f..0cbaaa7 100644
--- a/tests/testpathbar.c
+++ b/tests/testpathbar.c
@@ -5,8 +5,8 @@
 static GActionGroup *action_group;
 static GList *path_bars = NULL;
 static GList *files_path_bars = NULL;
-static const gchar* original_path = "/test/test 2/test 3/asda lkasdl//pppppppppppppppp/ alskd/";
-static const gchar* file_original_path = "/test/test 2/test 3/asda lkasdl/pppppppppppppppp/alskd/";
+static const gchar* original_path = "/test/test 2/test 3/asda lkasdl/pppppppppppppppp/ alskd";
+static const gchar* file_original_path = "/test/test 2/test 3/asda lkasdl/pppppppppppppppp/alskd";
 
 static void
 action_menu_1 (GSimpleAction *action,


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