[gitg] Use nested branches in combo



commit 75b5b5b90c5c8e5b1afc13be94ebf133ecb646ef
Author: Jesse van den Kieboom <jesse icecrew nl>
Date:   Tue Jun 23 21:47:38 2009 +0200

    Use nested branches in combo
    
    GitgRef is now also a proper GType (Boxed)

 gitg/gitg-commit-view.c    |    3 -
 gitg/gitg-label-renderer.c |    8 ++-
 gitg/gitg-ref.c            |   92 +++++++++++++++++++++++++
 gitg/gitg-ref.h            |   42 +++++++++---
 gitg/gitg-repository.c     |   14 +++-
 gitg/gitg-window.c         |  161 ++++++++++++++++++++++++++++++++++----------
 6 files changed, 264 insertions(+), 56 deletions(-)
---
diff --git a/gitg/gitg-commit-view.c b/gitg/gitg-commit-view.c
index e5fd8de..64fa73d 100644
--- a/gitg/gitg-commit-view.c
+++ b/gitg/gitg-commit-view.c
@@ -777,8 +777,6 @@ on_tree_view_drag_data_get (GtkWidget        *widget,
                             guint             time,
                             GitgCommitView   *view)
 {
-	GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
-	GtkTreeModel *model;
 	GList *selected;
 	GList *item;
 	gchar **uris;
@@ -818,7 +816,6 @@ on_tree_view_staged_drag_data_received(GtkWidget        *widget,
 	/* Stage all the files dropped on this */
 	gchar **uris = gtk_selection_data_get_uris(data);
 	gchar **uri;
-	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
 
 	for (uri = uris; *uri; ++uri)
 	{
diff --git a/gitg/gitg-label-renderer.c b/gitg/gitg-label-renderer.c
index c2fe041..43f5e92 100644
--- a/gitg/gitg-label-renderer.c
+++ b/gitg/gitg-label-renderer.c
@@ -44,7 +44,8 @@ gitg_label_renderer_width(GtkWidget *widget, PangoFontDescription *font, GSList
 	{
 		gint w;
 		GitgRef *ref = (GitgRef *)item->data;
-		gchar *smaller = g_strdup_printf("<span size='smaller'>%s</span>", ref->shortname);
+		gchar *smaller = g_strdup_printf("<span size='smaller'>%s</span>", 
+		                                 gitg_ref_get_shortname(ref));
 		pango_layout_set_markup(layout, smaller, -1);
 		
 		pango_layout_get_pixel_size(layout, &w, NULL);
@@ -114,7 +115,8 @@ gitg_label_renderer_draw(GtkWidget *widget, PangoFontDescription *font, cairo_t
 		GitgRef *ref = (GitgRef *)item->data;
 		gint w;
 		gint h;
-		gchar *smaller = g_strdup_printf("<span size='smaller'>%s</span>", ref->shortname);
+		gchar *smaller = g_strdup_printf("<span size='smaller'>%s</span>", 
+		                                 gitg_ref_get_shortname(ref));
 		
 		pango_layout_set_markup(layout, smaller, -1);
 		pango_layout_get_pixel_size(layout, &w, &h);
@@ -123,7 +125,7 @@ gitg_label_renderer_draw(GtkWidget *widget, PangoFontDescription *font, cairo_t
 		rounded_rectangle(context, pos + 0.5, area->y + MARGIN + 0.5, w + PADDING * 2, area->height - MARGIN * 2, 5);
 		
 		
-		set_source_for_ref_type(context, ref->type);
+		set_source_for_ref_type(context, gitg_ref_get_ref_type(ref));
 		cairo_fill_preserve(context);
 		
 		cairo_set_source_rgb(context, 0, 0, 0);
diff --git a/gitg/gitg-ref.c b/gitg/gitg-ref.c
index f681893..2e5f826 100644
--- a/gitg/gitg-ref.c
+++ b/gitg/gitg-ref.c
@@ -30,6 +30,32 @@ typedef struct
 	GitgRefType type;
 } PrefixTypeMap;
 
+struct _GitgRef
+{
+	Hash hash;
+	GitgRefType type;
+	
+	gchar *name;
+	gchar *shortname;
+	
+	gchar *prefix;
+};
+
+GType 
+gitg_ref_get_type (void)
+{
+	static GType our_type = 0;
+
+	if (!our_type)
+	{
+		our_type = g_boxed_type_register_static("GitGRef",
+		                                        (GBoxedCopyFunc)gitg_ref_copy,
+		                                        (GBoxedFreeFunc)gitg_ref_free);
+	}
+	
+	return our_type;
+} 
+
 GitgRef *
 gitg_ref_new(gchar const *hash, gchar const *name)
 {
@@ -43,16 +69,26 @@ gitg_ref_new(gchar const *hash, gchar const *name)
 		{"refs/remotes/", GITG_REF_TYPE_REMOTE},
 		{"refs/tags/", GITG_REF_TYPE_TAG}
 	};
+
+	inst->prefix = NULL;
 	
 	// set type from name
 	int i;
 	for (i = 0; i < sizeof(map) / sizeof(PrefixTypeMap); ++i)
 	{
+		gchar *pos;
+
 		if (!g_str_has_prefix(name, map[i].prefix))
 			continue;
 		
 		inst->type = map[i].type;
 		inst->shortname = g_strdup(name + strlen(map[i].prefix));
+		
+		if (map[i].type == GITG_REF_TYPE_REMOTE && (pos = strchr(inst->shortname, '/')))
+		{
+			inst->prefix = g_strndup(inst->shortname, pos - inst->shortname);
+		}
+		
 		break;
 	}
 	
@@ -73,6 +109,7 @@ gitg_ref_copy(GitgRef *ref)
 	ret->type = ref->type;
 	ret->name = g_strdup(ref->name);
 	ret->shortname = g_strdup(ref->shortname);
+	ret->prefix = g_strdup(ref->prefix);
 	
 	int i;
 	for (i = 0; i < HASH_BINARY_SIZE; ++i)
@@ -89,6 +126,61 @@ gitg_ref_free(GitgRef *ref)
 
 	g_free(ref->name);
 	g_free(ref->shortname);
+	g_free(ref->prefix);
 
 	g_slice_free(GitgRef, ref);
 }
+
+gboolean 
+gitg_ref_equal(GitgRef *ref, GitgRef *other)
+{
+	if (ref == NULL && other == NULL)
+		return TRUE;
+	
+	if (ref == NULL || other == NULL)
+		return FALSE;
+
+	return strcmp(ref->name, other->name) == 0;
+}
+
+gboolean
+gitg_ref_equal_prefix(GitgRef *ref, GitgRef *other)
+{
+	if (ref == NULL && other == NULL)
+		return TRUE;
+	
+	if (ref == NULL || other == NULL)
+		return FALSE;
+
+	return strcmp(ref->prefix, other->prefix) == 0;
+}
+
+gchar const *
+gitg_ref_get_hash(GitgRef *ref)
+{
+	return ref->hash;
+}
+
+GitgRefType
+gitg_ref_get_ref_type(GitgRef *ref)
+{
+	return ref->type;
+}
+
+gchar const *
+gitg_ref_get_name(GitgRef *ref)
+{
+	return ref->name;
+}
+
+gchar const *
+gitg_ref_get_shortname(GitgRef *ref)
+{
+	return ref->shortname;
+}
+
+gchar const *
+gitg_ref_get_prefix(GitgRef *ref)
+{
+	return ref->prefix;
+}
diff --git a/gitg/gitg-ref.h b/gitg/gitg-ref.h
index 32adae7..0948b64 100644
--- a/gitg/gitg-ref.h
+++ b/gitg/gitg-ref.h
@@ -23,8 +23,15 @@
 #ifndef __GITG_REF_H__
 #define __GITG_REF_H__
 
+#include <glib-object.h>
 #include "gitg-types.h"
 
+G_BEGIN_DECLS
+
+#define GITG_TYPE_REF					(gitg_ref_get_type ())
+#define GITG_REF(obj)					((GitgRef *)obj)
+#define GITG_REF_CONST(obj)				((GitgRef const *)obj)
+
 typedef enum
 {
 	GITG_REF_TYPE_NONE = 0,
@@ -33,17 +40,30 @@ typedef enum
 	GITG_REF_TYPE_TAG
 } GitgRefType;
 
-typedef struct
-{
-	Hash hash;
-	GitgRefType type;
-	gchar *name;
-	gchar *shortname;
-} GitgRef;
-
-GitgRef *gitg_ref_new(gchar const *hash, gchar const *name);
-void gitg_ref_free(GitgRef *ref);
-GitgRef *gitg_ref_copy(GitgRef *ref);
+typedef struct _GitgRef GitgRef;
+
+GType 			 gitg_ref_get_type 				(void) G_GNUC_CONST;
+
+GitgRef 		*gitg_ref_new					(gchar const *hash, 
+                                                 gchar const *name);
+
+gchar const 	*gitg_ref_get_hash				(GitgRef     *ref);
+GitgRefType 	 gitg_ref_get_ref_type			(GitgRef     *ref);
+gchar const 	*gitg_ref_get_name				(GitgRef     *ref);
+
+gchar const 	*gitg_ref_get_shortname			(GitgRef     *ref);
+gchar const 	*gitg_ref_get_prefix			(GitgRef     *ref);
+
+GitgRef			*gitg_ref_copy					(GitgRef     *ref);
+void 			 gitg_ref_free					(GitgRef     *ref);
+
+gboolean 		 gitg_ref_equal					(GitgRef     *ref, 
+                                                 GitgRef     *other);
+
+gboolean		 gitg_ref_equal_prefix			(GitgRef     *ref,
+                                                 GitgRef     *other);
+
+G_END_DECLS
 
 #endif /* __GITG_REF_H__ */
 
diff --git a/gitg/gitg-repository.c b/gitg/gitg-repository.c
index 3a0a860..0ea9d7d 100644
--- a/gitg/gitg-repository.c
+++ b/gitg/gitg-repository.c
@@ -589,10 +589,11 @@ loader_update_commits(GitgRepository *self, gchar **buffer)
 		gint64 timestamp = g_ascii_strtoll(components[4], NULL, 0);
 	
 		GitgRevision *rv = gitg_revision_new(components[0], components[1], components[2], components[3], timestamp);
-		GSList *lanes;
 		
 		if (len > 5 && strlen(components[5]) == 1 && strchr("<>-^", *components[5]) != NULL)
+		{
 			gitg_revision_set_sign(rv, *components[5]);
+		}
 
 		append_revision(self, rv);
 		g_strfreev(components);
@@ -830,12 +831,19 @@ static GitgRef *
 add_ref(GitgRepository *self, gchar const *sha1, gchar const *name)
 {
 	GitgRef *ref = gitg_ref_new(sha1, name);
-	GSList *refs = (GSList *)g_hash_table_lookup(self->priv->refs, ref->hash);
+	GSList *refs = (GSList *)g_hash_table_lookup(self->priv->refs, 
+	                                             gitg_ref_get_hash(ref));
 	
 	if (refs == NULL)
-		g_hash_table_insert(self->priv->refs, ref->hash, g_slist_append(NULL, ref));
+	{
+		g_hash_table_insert(self->priv->refs, 
+		                    (gpointer)gitg_ref_get_hash(ref), 
+		                    g_slist_append(NULL, ref));
+	}
 	else
+	{
 		refs = g_slist_append(refs, ref);
+	}
 	
 	return ref;
 }
diff --git a/gitg/gitg-window.c b/gitg/gitg-window.c
index c439012..83faea0 100644
--- a/gitg/gitg-window.c
+++ b/gitg/gitg-window.c
@@ -42,11 +42,17 @@
 
 #define GITG_WINDOW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_WINDOW, GitgWindowPrivate))
 
+enum
+{
+	COLUMN_BRANCHES_NAME,
+	COLUMN_BRANCHES_REF
+};
+
 struct _GitgWindowPrivate
 {
 	GitgRepository *repository;
 
-	GtkListStore *branches_store;
+	GtkTreeStore *branches_store;
 
 	/* Widget placeholders */
 	GtkNotebook *notebook_main;
@@ -64,7 +70,8 @@ struct _GitgWindowPrivate
 	
 	GtkActionGroup *edit_group;
 	GtkWidget *open_dialog;
-	gchar *current_branch;
+
+	GitgRef *current_branch;
 	GitgCellRendererPath *renderer_path;
 	
 	GTimer *load_timer;
@@ -89,7 +96,8 @@ gitg_window_finalize(GObject *object)
 {
 	GitgWindow *self = GITG_WINDOW(object);
 	
-	g_free(self->priv->current_branch);
+	gitg_ref_free(self->priv->current_branch);
+
 	g_timer_destroy(self->priv->load_timer);
 	gdk_cursor_unref(self->priv->hand);
 	
@@ -304,12 +312,20 @@ on_renderer_path(GtkTreeViewColumn *column, GitgCellRendererPath *renderer, GtkT
 static gboolean
 branches_separator_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
 {
-	gchar *t;
+	gchar *name;
+	GitgRef *ref;
 	
-	gtk_tree_model_get(model, iter, 0, &t, -1);
-	gboolean ret = t == NULL;
+	gtk_tree_model_get(model, 
+	                   iter, 
+	                   COLUMN_BRANCHES_NAME, &name, 
+	                   COLUMN_BRANCHES_REF, &ref,
+	                   -1);
+
+	gboolean ret = (name == NULL && ref == NULL);
 	
-	g_free(t);
+	g_free(name);
+	gitg_ref_free(ref);
+
 	return ret;
 }
 
@@ -327,9 +343,26 @@ on_branches_combo_changed(GtkComboBox *combo, GitgWindow *window)
 	next = iter;
 	
 	if (!gtk_tree_model_iter_next(gtk_combo_box_get_model(combo), &next))
+	{
 		name = g_strdup("--all");
+	}
 	else
-		gtk_tree_model_get(gtk_combo_box_get_model(combo), &iter, 0, &name, -1);
+	{
+		GitgRef *ref;
+		
+		gtk_tree_model_get(gtk_combo_box_get_model(combo), 
+		                   &iter, 
+		                   COLUMN_BRANCHES_REF, &ref, 
+		                   -1);
+		
+		if (ref == NULL)
+		{
+			return;
+		}
+		
+		name = g_strdup(gitg_ref_get_name(ref));
+		gitg_ref_free(ref);
+	}
 
 	gitg_repository_load(window->priv->repository, 1, (gchar const **)&name, NULL);
 	g_free(name);
@@ -339,12 +372,16 @@ static void
 build_branches_combo(GitgWindow *window, GtkBuilder *builder)
 {
 	GtkComboBox *combo = GTK_COMBO_BOX(gtk_builder_get_object(builder, "combo_box_branches"));
-	window->priv->branches_store = gtk_list_store_new(1, G_TYPE_STRING);
+	window->priv->branches_store = gtk_tree_store_new(2, G_TYPE_STRING, GITG_TYPE_REF);
 	window->priv->combo_branches = combo;
 
 	GtkTreeIter iter;
-	gtk_list_store_append(window->priv->branches_store, &iter);
-	gtk_list_store_set(window->priv->branches_store, &iter, 0, _("Select branch"), -1);
+	gtk_tree_store_append(window->priv->branches_store, &iter, NULL);
+	gtk_tree_store_set(window->priv->branches_store, 
+	                   &iter, 
+	                   COLUMN_BRANCHES_NAME, _("Select branch"),
+	                   COLUMN_BRANCHES_REF, NULL, 
+	                   -1);
 	
 	gtk_combo_box_set_model(combo, GTK_TREE_MODEL(window->priv->branches_store));
 	gtk_combo_box_set_active(combo, 0);
@@ -606,20 +643,26 @@ create_repository(GitgWindow *window, gchar const *path, gboolean usewd)
 }
 
 static int
-sort_by_ref_type(GitgRef const *a, GitgRef const *b)
+sort_by_ref_type(GitgRef *a, GitgRef *b)
 {
-	if (a->type == b->type)
+	if (gitg_ref_get_ref_type(a) == gitg_ref_get_ref_type(b))
 	{
-		if (g_ascii_strcasecmp(a->shortname, "master") == 0)
+		if (g_ascii_strcasecmp(gitg_ref_get_shortname(a), "master") == 0)
+		{
 			return -1;
-		else if (g_ascii_strcasecmp(b->shortname, "master") == 0)
+		}
+		else if (g_ascii_strcasecmp(gitg_ref_get_shortname(b), "master") == 0)
+		{
 			return 1;
+		}
 		else
-			return g_ascii_strcasecmp(a->shortname, b->shortname);
+		{
+			return g_ascii_strcasecmp(gitg_ref_get_shortname(a), gitg_ref_get_shortname(b));
+		}
 	}
 	else
 	{
-		return a->type - b->type;
+		return gitg_ref_get_ref_type(a) - gitg_ref_get_ref_type(b);
 	}
 }
 
@@ -631,19 +674,24 @@ clear_branches_combo(GitgWindow *window, gboolean keepselection)
 		GtkTreeIter iter;
 		gtk_combo_box_get_active_iter(GTK_COMBO_BOX(window->priv->combo_branches), &iter);
 		
-		g_free(window->priv->current_branch);
-		gtk_tree_model_get(GTK_TREE_MODEL(window->priv->branches_store), &iter, 0, &window->priv->current_branch, -1);
+		gitg_ref_free(window->priv->current_branch);
+
+		gtk_tree_model_get(GTK_TREE_MODEL(window->priv->branches_store), 
+		                   &iter, 
+		                   COLUMN_BRANCHES_REF, &window->priv->current_branch, 
+		                   -1);
 	}
 	else
 	{
-		g_free(window->priv->current_branch);
+		gitg_ref_free(window->priv->current_branch);
 		window->priv->current_branch = NULL;
 	}
 		
 	GtkTreeIter iter;	
+
 	if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(window->priv->branches_store), &iter, NULL, 1))
 	{
-		while (gtk_list_store_remove(window->priv->branches_store, &iter))
+		while (gtk_tree_store_remove(window->priv->branches_store, &iter))
 		;
 	}
 
@@ -665,37 +713,78 @@ fill_branches_combo(GitgWindow *window)
 	
 	refs = g_slist_sort(refs, (GCompareFunc)sort_by_ref_type);
 	GSList *item;
+	
 	GitgRefType prevtype = GITG_REF_TYPE_NONE;
 	GtkTreeIter iter;
-
+	GtkTreeIter parent;
+	GitgRef *parentref = NULL;
+	GtkTreeStore *store = window->priv->branches_store;
+	
 	for (item = refs; item; item = item->next)
 	{
 		GitgRef *ref = (GitgRef *)item->data;
 		
-		if (!(ref->type == GITG_REF_TYPE_REMOTE || 
-			  ref->type == GITG_REF_TYPE_BRANCH))
+		if (!(gitg_ref_get_ref_type(ref) == GITG_REF_TYPE_REMOTE || 
+			  gitg_ref_get_ref_type(ref) == GITG_REF_TYPE_BRANCH))
 			continue;
 
-		if (ref->type != prevtype)
+		if (gitg_ref_get_ref_type(ref) != prevtype)
+		{
+			gtk_tree_store_append(store, &iter, NULL);
+			gtk_tree_store_set(store, 
+			                   &iter, 
+			                   COLUMN_BRANCHES_NAME, NULL, 
+			                   COLUMN_BRANCHES_REF, NULL,
+			                   -1);
+			
+			prevtype = gitg_ref_get_ref_type(ref);
+		}
+
+		if (gitg_ref_get_prefix(ref))
 		{
-			gtk_list_store_append(window->priv->branches_store, &iter);
-			gtk_list_store_set(window->priv->branches_store, &iter, 0, NULL, -1);
+			if (!parentref || !gitg_ref_equal_prefix(parentref, ref))
+			{
+				parentref = ref;
+
+				gtk_tree_store_append(store, &parent, NULL);
+				gtk_tree_store_set(store,
+				                   &parent,
+				                   COLUMN_BRANCHES_NAME, gitg_ref_get_prefix(ref),
+				                   COLUMN_BRANCHES_REF, NULL,
+				                   -1);
+			}
 			
-			prevtype = ref->type;
+			gtk_tree_store_append(window->priv->branches_store, &iter, &parent);
+		}
+		else
+		{
+			gtk_tree_store_append(window->priv->branches_store, &iter, NULL);
 		}
 
-		gtk_list_store_append(window->priv->branches_store, &iter);
-		gtk_list_store_set(window->priv->branches_store, &iter, 0, ref->shortname, -1);
+		gtk_tree_store_set(window->priv->branches_store, 
+		                   &iter, 
+		                   COLUMN_BRANCHES_NAME, gitg_ref_get_shortname(ref), 
+		                   COLUMN_BRANCHES_REF, ref, 
+		                   -1);
 		
-		if (g_strcmp0(window->priv->current_branch, ref->shortname) == 0)
+		if (window->priv->current_branch && gitg_ref_equal(window->priv->current_branch, ref) == 0)
+		{
 			gtk_combo_box_set_active_iter(window->priv->combo_branches, &iter);
+		}
 	}
 	
-	gtk_list_store_append(window->priv->branches_store, &iter);
-	gtk_list_store_set(window->priv->branches_store, &iter, 0, NULL, -1);
-
-	gtk_list_store_append(window->priv->branches_store, &iter);
-	gtk_list_store_set(window->priv->branches_store, &iter, 0, _("All branches"), -1);
+	gtk_tree_store_append(store, &iter, NULL);
+	gtk_tree_store_set(store, 
+	                   &iter, 
+	                   COLUMN_BRANCHES_NAME, NULL, 
+	                   COLUMN_BRANCHES_REF, NULL, -1);
+
+	gtk_tree_store_append(store, &iter, NULL);
+	gtk_tree_store_set(store, 
+	                   &iter,
+	                   COLUMN_BRANCHES_NAME, _("All branches"),
+	                   COLUMN_BRANCHES_REF, NULL, 
+	                   -1);
 	
 	if (!window->priv->current_branch)
 		gtk_combo_box_set_active(window->priv->combo_branches, 0);



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