[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