[Xfce4-commits] <thunar-vcs-plugin:master> Show revision graph in log dialog.
Peter de Ridder
noreply at xfce.org
Mon Dec 7 01:00:02 CET 2009
Updating branch refs/heads/master
to cb88c8658fc271103f0cc3db15c834e60f312daa (commit)
from 796cb565a69eb7f417a8ea66d6e12f9861106d5d (commit)
commit cb88c8658fc271103f0cc3db15c834e60f312daa
Author: Peter de Ridder <peter at xfce.org>
Date: Mon Dec 7 00:43:00 2009 +0100
Show revision graph in log dialog.
Graph cell renderer draws a graph of the log revisions based on parent
commits.
The renderer uses the fg style to draw lines and bg style to fill boxes.
tvp-git-helper/Makefile.am | 4 +-
tvp-git-helper/tgh-cell-renderer-graph.c | 404 ++++++++++++++++++++++++++++++
tvp-git-helper/tgh-cell-renderer-graph.h | 53 ++++
tvp-git-helper/tgh-common.c | 33 +++-
tvp-git-helper/tgh-log-dialog.c | 122 +++++++++-
tvp-git-helper/tgh-log-dialog.h | 1 +
tvp-git-helper/tgh-log.c | 8 +-
7 files changed, 617 insertions(+), 8 deletions(-)
diff --git a/tvp-git-helper/Makefile.am b/tvp-git-helper/Makefile.am
index 475f01f..fe616e8 100644
--- a/tvp-git-helper/Makefile.am
+++ b/tvp-git-helper/Makefile.am
@@ -55,7 +55,9 @@ tvp_git_helper_SOURCES = \
tgh-status-dialog.h \
tgh-status-dialog.c \
tgh-transfer-dialog.h \
- tgh-transfer-dialog.c
+ tgh-transfer-dialog.c \
+ tgh-cell-renderer-graph.h \
+ tgh-cell-renderer-graph.c
tvp_git_helper_CPPFLAGS = \
-DG_LOG_DOMAIN=\"tvp-git-helper\" \
diff --git a/tvp-git-helper/tgh-cell-renderer-graph.c b/tvp-git-helper/tgh-cell-renderer-graph.c
new file mode 100644
index 0000000..147da86
--- /dev/null
+++ b/tvp-git-helper/tgh-cell-renderer-graph.c
@@ -0,0 +1,404 @@
+/*-
+ * Copyright (c) 2006 Peter de Ridder <peter at xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <thunar-vfs/thunar-vfs.h>
+#include <gtk/gtk.h>
+
+#include "tgh-common.h"
+#include "tgh-cell-renderer-graph.h"
+
+struct _TghCellRendererGraph
+{
+ GtkCellRenderer cell;
+
+ GList *graph_iter;
+ guint junction_size;
+ guint spacing;
+};
+
+struct _TghCellRendererGraphClass
+{
+ GtkCellRendererClass cell_class;
+};
+
+enum {
+ PROPERTY_GRAPH_ITER = 1
+};
+
+static void tgh_cell_renderer_graph_get_property (GObject*, guint, GValue*, GParamSpec*);
+static void tgh_cell_renderer_graph_set_property (GObject*, guint, const GValue*, GParamSpec*);
+
+static void tgh_cell_renderer_graph_get_size (GtkCellRenderer*, GtkWidget*, GdkRectangle*, gint*, gint*, gint*, gint*);
+static void tgh_cell_renderer_graph_render (GtkCellRenderer*, GdkDrawable*, GtkWidget*, GdkRectangle*, GdkRectangle*, GdkRectangle*, GtkCellRendererState);
+
+G_DEFINE_TYPE (TghCellRendererGraph, tgh_cell_renderer_graph, GTK_TYPE_CELL_RENDERER)
+
+static void
+tgh_cell_renderer_graph_class_init (TghCellRendererGraphClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
+
+ object_class->get_property = tgh_cell_renderer_graph_get_property;
+ object_class->set_property = tgh_cell_renderer_graph_set_property;
+
+ cell_class->get_size = tgh_cell_renderer_graph_get_size;
+ cell_class->render = tgh_cell_renderer_graph_render;
+
+ g_object_class_install_property (object_class, PROPERTY_GRAPH_ITER,
+ g_param_spec_pointer ("graph-iter", "", "", G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class, PROPERTY_GRAPH_ITER,
+ g_param_spec_uint ("junction-size", "", "", 1, G_MAXUINT, 5, G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class, PROPERTY_GRAPH_ITER,
+ g_param_spec_uint ("spacing", "", "", 1, G_MAXUINT, 4, G_PARAM_READWRITE));
+}
+
+static void
+tgh_cell_renderer_graph_init (TghCellRendererGraph *renderer)
+{
+ renderer->junction_size = 5;
+ renderer->spacing = 4;
+}
+
+GtkCellRenderer*
+tgh_cell_renderer_graph_new (void)
+{
+ return g_object_new (TGH_TYPE_CELL_RENDERER_GRAPH, NULL);
+}
+
+static void
+tgh_cell_renderer_graph_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ TghCellRendererGraph *renderer = TGH_CELL_RENDERER_GRAPH (object);
+
+ switch (property_id)
+ {
+ case PROPERTY_GRAPH_ITER:
+ g_value_set_pointer (value, renderer->graph_iter);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+tgh_cell_renderer_graph_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ TghCellRendererGraph *renderer = TGH_CELL_RENDERER_GRAPH (object);
+
+ switch (property_id)
+ {
+ case PROPERTY_GRAPH_ITER:
+ renderer->graph_iter = g_value_get_pointer (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+tgh_cell_renderer_graph_get_size (GtkCellRenderer *cell, GtkWidget *widget, GdkRectangle *cell_area, gint *x_offset, gint *y_offset, gint *width, gint *height)
+{
+ TghCellRendererGraph *renderer = TGH_CELL_RENDERER_GRAPH (cell);
+ gint graph_width = 0;
+ gint graph_height = 0;
+ gint calc_width;
+ gint calc_height;
+
+ if (renderer->graph_iter)
+ {
+ gint count;
+ TghGraphNode *node_iter;
+
+ for (node_iter = renderer->graph_iter->data, count = 0; node_iter; node_iter = node_iter->next, count++)
+ {
+ switch (node_iter->type)
+ {
+ case TGH_GRAPH_LINE:
+ break;
+ case TGH_GRAPH_JUNCTION:
+ graph_height = renderer->junction_size;
+ break;
+ }
+ }
+
+ if (count)
+ {
+ graph_width = renderer->spacing + renderer->spacing * count + count;
+ }
+ }
+
+ calc_width = (gint) cell->xpad * 2 + graph_width;
+ calc_height = (gint) cell->ypad * 2 + graph_height;
+
+ if (cell_area && graph_width > 0 && graph_height > 0)
+ {
+ if (x_offset)
+ {
+ *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
+ (1.0 - cell->xalign) : cell->xalign) * (cell_area->width - calc_width));
+ if (*x_offset < 0)
+ *x_offset = 0;
+ }
+ if (y_offset)
+ {
+ *y_offset = (cell->yalign * (cell_area->height - calc_height));
+ if (*y_offset < 0)
+ *y_offset = 0;
+ }
+ }
+ else
+ {
+ if (x_offset)
+ *x_offset = 0;
+ if (y_offset)
+ *y_offset = 0;
+ }
+
+ if (width)
+ *width = calc_width;
+
+ if (height)
+ *height = calc_height;
+}
+
+static gint
+tgh_graph_node_length (TghGraphNode *list)
+{
+ TghGraphNode *iter;
+ gint count;
+
+ for (iter = list, count = 0; iter; iter = iter->next, count++);
+
+ return count;
+}
+
+static gint
+tgh_graph_node_index_of (TghGraphNode *list, const gchar *name)
+{
+ TghGraphNode *iter;
+ gint index1;
+
+ for (iter = list, index1 = 0; iter; iter = iter->next, index1++)
+ {
+ if (0 == strcmp (name, iter->name))
+ return index1;
+ }
+
+ return -1;
+}
+
+static void
+draw_node (gint index1, TghGraphNode *node_list, const gchar *name, gint x1_offset, gint x2_offset, gint y_offset, gint height, guint spacing, gboolean bottom, gboolean rtl, cairo_t *cr)
+{
+ gint index2;
+
+ index2 = tgh_graph_node_index_of (node_list, name);
+
+ if (index2 >= 0)
+ {
+ double x1, x2;
+ if (rtl)
+ {
+ x1 = x1_offset - (spacing + spacing * index1 + index1) + 0.5;
+ x2 = x2_offset - (spacing + spacing * index2 + index2) + 0.5;
+ }
+ else
+ {
+ x1 = x1_offset + spacing + spacing * index1 + index1 + 0.5;
+ x2 = x2_offset + spacing + spacing * index2 + index2 + 0.5;
+ }
+
+ if (bottom)
+ x2 = (x1+x2)/2;
+ else
+ x1 = (x1+x2)/2;
+
+ cairo_move_to (cr, x1, y_offset);
+ cairo_line_to (cr, x2, y_offset + height);
+ }
+}
+
+static void
+tgh_cell_renderer_graph_render (GtkCellRenderer *cell, GdkDrawable *window, GtkWidget *widget, GdkRectangle *background_area, GdkRectangle *cell_area, GdkRectangle *expose_area, GtkCellRendererState flags)
+{
+ TghCellRendererGraph *renderer = TGH_CELL_RENDERER_GRAPH (cell);
+ gint x_offset;
+ gint width;
+
+ tgh_cell_renderer_graph_get_size (cell, widget, cell_area, &x_offset, NULL, &width, NULL);
+
+ if (renderer->graph_iter)
+ {
+ cairo_t *cr;
+ GdkGC *gc;
+ GList *graph_iter;
+ TghGraphNode *node_iter;
+ TghGraphNode *node_list;
+ gchar **junction_iter;
+ gint index1;
+ gint line_height, line_offset;
+ guint spacing = renderer->spacing;
+ guint junction_size = renderer->junction_size;
+ gint y_offset;
+ gint height;
+ gint x2_offset;
+ gint x;
+ gboolean rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
+ GtkStateType state;
+
+ if (flags & GTK_CELL_RENDERER_INSENSITIVE)
+ state = GTK_STATE_INSENSITIVE;
+ else if (flags & GTK_CELL_RENDERER_SELECTED)
+ state = GTK_STATE_SELECTED;
+ else if (flags & GTK_CELL_RENDERER_PRELIT)
+ state = GTK_STATE_PRELIGHT;
+ else
+ state = GTK_STATE_NORMAL;
+
+ x_offset += cell_area->x + cell->xpad;
+ y_offset = background_area->y;
+ height = background_area->height;
+
+ if (rtl)
+ x_offset += width - cell->xpad * 2;
+
+ cr = gdk_cairo_create (window);
+ cairo_set_line_width (cr, 1);
+ gdk_cairo_set_source_color (cr, &widget->style->fg[state]);
+
+ gc = widget->style->fg_gc[state];
+
+ if (expose_area)
+ gdk_gc_set_clip_rectangle (gc, expose_area);
+
+ node_list = renderer->graph_iter->data;
+ graph_iter = g_list_next (renderer->graph_iter);
+ if (graph_iter)
+ {
+ line_height = (height - junction_size) / 2;
+ line_offset = y_offset;
+
+ x2_offset = tgh_graph_node_length (graph_iter->data);
+ x2_offset = renderer->spacing + renderer->spacing * x2_offset + x2_offset;
+ x2_offset = x2_offset;
+ x2_offset = ((rtl ? (1.0 - cell->xalign) : cell->xalign) * (cell_area->width - x2_offset)) + (rtl ? x2_offset : 0);
+ if (x2_offset < 0)
+ x2_offset = 0;
+ x2_offset += cell_area->x;
+
+ index1 = 0;
+ for (node_iter = graph_iter->data; node_iter; node_iter = node_iter->next)
+ {
+ switch (node_iter->type)
+ {
+ case TGH_GRAPH_LINE:
+ draw_node (index1, node_list, node_iter->name, x2_offset, x_offset, line_offset, line_height, spacing, FALSE, rtl, cr);
+ index1++;
+ break;
+ case TGH_GRAPH_JUNCTION:
+ if (node_iter->junction)
+ {
+ for (junction_iter = node_iter->junction; *junction_iter; junction_iter++)
+ {
+ draw_node (index1, node_list, *junction_iter, x2_offset, x_offset, line_offset, line_height, spacing, FALSE, rtl, cr);
+ }
+ }
+ index1++;
+ break;
+ }
+ }
+ }
+
+ graph_iter = g_list_previous (renderer->graph_iter);
+ if (graph_iter)
+ {
+ node_list = graph_iter->data;
+
+ x2_offset = tgh_graph_node_length (graph_iter->data);
+ x2_offset = renderer->spacing + renderer->spacing * x2_offset + x2_offset;
+ x2_offset = x2_offset;
+ x2_offset = ((rtl ? (1.0 - cell->xalign) : cell->xalign) * (cell_area->width - x2_offset)) + (rtl ? x2_offset : 0);
+ if (x2_offset < 0)
+ x2_offset = 0;
+ x2_offset += cell_area->x;
+ }
+ else
+ node_list = NULL;
+
+ line_height = (height - junction_size) / 2;
+ line_offset = y_offset + height - line_height;
+
+ index1 = 0;
+ for (node_iter = renderer->graph_iter->data; node_iter; node_iter = node_iter->next)
+ {
+ switch (node_iter->type)
+ {
+ case TGH_GRAPH_LINE:
+ if (rtl)
+ x = x_offset - (spacing + spacing * index1 + index1);
+ else
+ x = x_offset + spacing + spacing * index1 + index1;
+ gdk_draw_line (window, gc, x, y_offset + line_height, x, line_offset);
+
+ draw_node (index1, node_list, node_iter->name, x_offset, x2_offset, line_offset, line_height, spacing, TRUE, rtl, cr);
+ index1++;
+ break;
+ case TGH_GRAPH_JUNCTION:
+ if (rtl)
+ x = x_offset - (spacing + spacing * index1 + index1);
+ else
+ x = x_offset + spacing + spacing * index1 + index1;
+ gdk_draw_rectangle (window, widget->style->bg_gc[state], TRUE,
+ x - (junction_size/2),
+ y_offset + line_height,
+ junction_size, junction_size);
+ gdk_draw_rectangle (window, gc, FALSE,
+ x - (junction_size/2),
+ y_offset + line_height,
+ junction_size - 1, junction_size - 1);
+
+ if (node_iter->junction)
+ {
+ for (junction_iter = node_iter->junction; *junction_iter; junction_iter++)
+ {
+ draw_node (index1, node_list, *junction_iter, x_offset, x2_offset, line_offset, line_height, spacing, TRUE, rtl, cr);
+ }
+ }
+ index1++;
+ break;
+ }
+ }
+
+ if (expose_area)
+ gdk_gc_set_clip_rectangle (gc, NULL);
+
+ cairo_stroke (cr);
+ cairo_destroy (cr);
+ }
+}
+
diff --git a/tvp-git-helper/tgh-cell-renderer-graph.h b/tvp-git-helper/tgh-cell-renderer-graph.h
new file mode 100644
index 0000000..567cc21
--- /dev/null
+++ b/tvp-git-helper/tgh-cell-renderer-graph.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2006 Peter de Ridder <peter at xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __TGH_CELL_RENDERER_GRAPH_H__
+#define __TGH_CELL_RENDERER_GRAPH_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS;
+
+typedef struct _TghCellRendererGraphClass TghCellRendererGraphClass;
+typedef struct _TghCellRendererGraph TghCellRendererGraph;
+
+#define TGH_TYPE_CELL_RENDERER_GRAPH (tgh_cell_renderer_graph_get_type ())
+#define TGH_CELL_RENDERER_GRAPH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TGH_TYPE_CELL_RENDERER_GRAPH, TghCellRendererGraph))
+#define TGH_CELL_RENDERER_GRAPH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TGH_TYPE_CELL_RENDERER_GRAPH, TghCellRendererGraphClass))
+#define TGH_IS_CELL_RENDERER_GRAPH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TGH_TYPE_CELL_RENDERER_GRAPH))
+#define TGH_IS_CELL_RENDERER_GRAPH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TGH_TYPE_CELL_RENDERER_GRAPH))
+#define TGH_CELL_RENDERER_GRAPH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TGH_TYPE_CELL_RENDERER_GRAPH, TghCellRendererGraphClass))
+
+typedef struct _TghGraphNode TghGraphNode;
+
+struct _TghGraphNode
+{
+ TghGraphNode *next;
+ enum {TGH_GRAPH_LINE, TGH_GRAPH_JUNCTION} type;
+ gchar *name;
+ gchar **junction;
+};
+
+GType tgh_cell_renderer_graph_get_type (void) G_GNUC_CONST G_GNUC_INTERNAL;
+
+GtkCellRenderer* tgh_cell_renderer_graph_new (void) G_GNUC_MALLOC G_GNUC_INTERNAL;
+
+G_END_DECLS;
+
+#endif /* !__TGH_CELL_RENDERER_GRAPH_H__ */
diff --git a/tvp-git-helper/tgh-common.c b/tvp-git-helper/tgh-common.c
index 62fd1d0..7ae58c9 100644
--- a/tvp-git-helper/tgh-common.c
+++ b/tvp-git-helper/tgh-common.c
@@ -242,6 +242,7 @@ typedef struct {
TghOutputParser parent;
GtkWidget *dialog;
gchar *revision;
+ gchar **parents;
gchar *author;
gchar *author_date;
gchar *commit;
@@ -256,6 +257,7 @@ log_parser_add_entry(TghLogParser *parser, TghLogDialog *dialog)
tgh_log_dialog_add(dialog,
g_slist_reverse(parser->files),
parser->revision,
+ parser->parents,
parser->author,
parser->author_date,
parser->commit,
@@ -265,6 +267,8 @@ log_parser_add_entry(TghLogParser *parser, TghLogDialog *dialog)
parser->files = NULL;
g_free(parser->revision);
parser->revision = NULL;
+ g_strfreev(parser->parents);
+ parser->parents = NULL;
parser->author = NULL;
g_free(parser->author_date);
parser->author_date = NULL;
@@ -284,14 +288,39 @@ log_parser_func(TghLogParser *parser, gchar *line)
{
if(strncmp(line, "commit ", 7) == 0)
{
- gchar *revision;
+ gchar *revision, *parent;
+ GSList *parent_list = NULL;
+ guint parent_count = 0;
if(parser->revision)
log_parser_add_entry(parser, dialog);
+ revision = g_strstrip (line+6);
+ parent = revision;
+
+ while ((parent = strchr (parent, ' ')))
+ {
+ *parent++ = '\0';
+ parent = g_strchug (parent);
+ parent_list = g_slist_prepend (parent_list, parent);
+ parent_count++;
+ }
+
// read first 6 chars of hash?
- revision = g_strstrip(line+6);
parser->revision = g_strndup(revision, revision[0]=='-'?7:6);
+
+ if (parent_count)
+ {
+ gchar **parents = g_new (char*, parent_count+1);
+ parents[parent_count] = NULL;
+ while (parent_list)
+ {
+ // read first 6 chars of hash?
+ parents[--parent_count] = g_strndup (parent_list->data, 6);;
+ parent_list = g_slist_delete_link (parent_list, parent_list);
+ }
+ parser->parents = parents;
+ }
}
else if(strncmp(line, "Author:", 7) == 0)
{
diff --git a/tvp-git-helper/tgh-log-dialog.c b/tvp-git-helper/tgh-log-dialog.c
index f7938c9..f38507b 100644
--- a/tvp-git-helper/tgh-log-dialog.c
+++ b/tvp-git-helper/tgh-log-dialog.c
@@ -25,6 +25,7 @@
#include <gtk/gtk.h>
#include "tgh-common.h"
+#include "tgh-cell-renderer-graph.h"
#include "tgh-log-dialog.h"
static void selection_changed (GtkTreeView*, gpointer);
@@ -35,6 +36,8 @@ struct _TghLogDialog
{
GtkDialog dialog;
+ GList *graph;
+
GtkWidget *tree_view;
GtkWidget *text_view;
GtkWidget *file_view;
@@ -84,6 +87,7 @@ enum {
COLUMN_MESSAGE,
COLUMN_FULL_MESSAGE,
COLUMN_FILE_LIST,
+ COLUMN_GRAPH,
COLUMN_COUNT
};
@@ -114,6 +118,13 @@ tgh_log_dialog_init (TghLogDialog *dialog)
dialog->tree_view = tree_view = gtk_tree_view_new ();
+ renderer = tgh_cell_renderer_graph_new ();
+ g_object_set (G_OBJECT (renderer), "xalign", 0.5f, NULL);
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
+ -1, "", renderer,
+ "graph-iter", COLUMN_GRAPH,
+ NULL);
+
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
-1, _("Revision"),
@@ -132,6 +143,7 @@ tgh_log_dialog_init (TghLogDialog *dialog)
renderer, "text",
COLUMN_AUTHOR_DATE, NULL);
+#if 0
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
-1, _("Commit"),
@@ -143,6 +155,7 @@ tgh_log_dialog_init (TghLogDialog *dialog)
-1, _("CommitDate"),
renderer, "text",
COLUMN_COMMIT_DATE, NULL);
+#endif
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
@@ -150,7 +163,7 @@ tgh_log_dialog_init (TghLogDialog *dialog)
renderer, "text",
COLUMN_MESSAGE, NULL);
- model = GTK_TREE_MODEL (gtk_list_store_new (COLUMN_COUNT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER));
+ model = GTK_TREE_MODEL (gtk_list_store_new (COLUMN_COUNT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER));
gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model);
@@ -255,19 +268,119 @@ tgh_log_dialog_new (const gchar *title, GtkWindow *parent, GtkDialogFlags flags)
return GTK_WIDGET(dialog);
}
+static void
+tgh_graph_node_free (TghGraphNode *node)
+{
+ TghGraphNode *next;
+
+ while (node)
+ {
+ g_free (node->name);
+ g_strfreev (node->junction);
+
+ next = node->next;
+ g_free (node);
+ node = next;
+ }
+}
+
+static TghGraphNode*
+tgh_graph_node_add (TghGraphNode *prev)
+{
+ TghGraphNode *node = g_new0 (TghGraphNode, 1);
+ if (prev)
+ prev->next = node;
+ return node;
+}
+
+static TghGraphNode*
+add_n_check_node (TghGraphNode *node_iter, TghGraphNode **node_list, const gchar *name, const gchar *revision, gchar **parents, gboolean *found)
+{
+ TghGraphNode *iter;
+
+ for (iter = *node_list; iter; iter = iter->next)
+ {
+ if (G_UNLIKELY(0 == strcmp (iter->name, name)))
+ return node_iter;
+ }
+
+ node_iter = tgh_graph_node_add (node_iter);
+
+ if (G_UNLIKELY (!*node_list))
+ *node_list = node_iter;
+
+ node_iter->name = g_strdup (name);
+
+ if (G_UNLIKELY (0 == strcmp (revision, name)))
+ {
+ *found = TRUE;
+ node_iter->type = TGH_GRAPH_JUNCTION;
+ node_iter->junction = g_strdupv (parents);
+ }
+
+ return node_iter;
+}
+
void
-tgh_log_dialog_add (TghLogDialog *dialog, GSList *files, const gchar *revision, const gchar *author, const gchar *author_date, const gchar *commit, const gchar *commit_date, const gchar *message)
+tgh_log_dialog_add (TghLogDialog *dialog, GSList *files, const gchar *revision, gchar **parents, const gchar *author, const gchar *author_date, const gchar *commit, const gchar *commit_date, const gchar *message)
{
GtkTreeModel *model;
GtkTreeIter iter;
gchar **lines = NULL;
gchar **line_iter;
gchar *first_line = NULL;
+ GList *graph;
+ TghGraphNode *next_node_list;
+ TghGraphNode *next_node_iter;
+ TghGraphNode *node_list = NULL;
+ TghGraphNode *node_iter = NULL;
+ gchar **junction_iter;
+ gboolean found = FALSE;
g_return_if_fail (TGH_IS_LOG_DIALOG (dialog));
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->tree_view));
+ graph = dialog->graph;
+
+ if (graph)
+ {
+ next_node_list = graph->data;
+
+ for (next_node_iter = next_node_list; next_node_iter; next_node_iter = next_node_iter->next)
+ {
+ switch (next_node_iter->type)
+ {
+ case TGH_GRAPH_LINE:
+ node_iter = add_n_check_node (node_iter, &node_list, next_node_iter->name, revision, parents, &found);
+ break;
+ case TGH_GRAPH_JUNCTION:
+ if (G_LIKELY (next_node_iter->junction))
+ {
+ for (junction_iter = next_node_iter->junction; *junction_iter; junction_iter++)
+ {
+ node_iter = add_n_check_node (node_iter, &node_list, *junction_iter, revision, parents, &found);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ node_iter = g_new0 (TghGraphNode, 1);
+ node_iter->next = node_list;
+ node_iter->name = g_strdup (revision);
+ node_iter->type = TGH_GRAPH_JUNCTION;
+ node_iter->junction = g_strdupv (parents);
+ node_list = node_iter;
+ }
+
+ graph = g_list_prepend (graph, node_list);
+
+ dialog->graph = graph;
+
if(message)
{
lines = g_strsplit_set (message, "\r\n", -1);
@@ -293,6 +406,7 @@ tgh_log_dialog_add (TghLogDialog *dialog, GSList *files, const gchar *revision,
COLUMN_MESSAGE, first_line,
COLUMN_FULL_MESSAGE, message,
COLUMN_FILE_LIST, files,
+ COLUMN_GRAPH, graph,
-1);
g_strfreev (lines);
@@ -372,6 +486,10 @@ refresh_clicked (GtkButton *button, gpointer user_data)
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->tree_view));
gtk_list_store_clear (GTK_LIST_STORE (model));
+ g_list_foreach(dialog->graph, (GFunc)tgh_graph_node_free, NULL);
+ g_list_free (dialog->graph);
+ dialog->graph = NULL;
+
gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->text_view)), "", -1);
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->file_view));
diff --git a/tvp-git-helper/tgh-log-dialog.h b/tvp-git-helper/tgh-log-dialog.h
index 11e4426..7adf604 100644
--- a/tvp-git-helper/tgh-log-dialog.h
+++ b/tvp-git-helper/tgh-log-dialog.h
@@ -52,6 +52,7 @@ GtkWidget* tgh_log_dialog_new (const gchar *title,
void tgh_log_dialog_add (TghLogDialog *dialog,
GSList *files,
const gchar *revision,
+ gchar ** parents,
const gchar *author,
const gchar *author_date,
const gchar *commit,
diff --git a/tvp-git-helper/tgh-log.c b/tvp-git-helper/tgh-log.c
index 403fe4f..0959030 100644
--- a/tvp-git-helper/tgh-log.c
+++ b/tvp-git-helper/tgh-log.c
@@ -43,7 +43,7 @@ static gboolean log_spawn (TghLogDialog *dialog, gchar **files, GPid *pid)
gint i;
gchar **argv;
- length = 8;
+ length = 10;
if(files)
length += g_strv_length(files);
@@ -55,10 +55,12 @@ static gboolean log_spawn (TghLogDialog *dialog, gchar **files, GPid *pid)
argv[3] = "--numstat";
argv[4] = "--parents";
argv[5] = "--pretty=fuller";
- argv[6] = "--";
+ argv[6] = "--boundary";
+ argv[7] = "--date-order";
+ argv[8] = "--";
argv[length-1] = NULL;
- i = 7;
+ i = 9;
if(files)
while(*files)
argv[i++] = *files++;
More information about the Xfce4-commits
mailing list