[anjuta/git-shell] git: Implement basic log viewer functions
- From: James Liggett <jrliggett src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [anjuta/git-shell] git: Implement basic log viewer functions
- Date: Sun, 26 Sep 2010 07:58:18 +0000 (UTC)
commit cbdb0ba47e41e13ce2389c834003a30775ddace3
Author: James Liggett <jrliggett cox net>
Date: Sun Sep 26 00:57:23 2010 -0700
git: Implement basic log viewer functions
It can show the logs of different branches. We don't have filtering or file
logs yet.
plugins/git/anjuta-git.ui | 10 +-
plugins/git/git-log-pane.c | 454 +++++++++++++++++++++++++++++++++++++++++---
plugins/git/git-log-pane.h | 2 +
3 files changed, 437 insertions(+), 29 deletions(-)
---
diff --git a/plugins/git/anjuta-git.ui b/plugins/git/anjuta-git.ui
index 94d20bd..af01624 100644
--- a/plugins/git/anjuta-git.ui
+++ b/plugins/git/anjuta-git.ui
@@ -1177,11 +1177,12 @@
<object class="GtkTreeView" id="log_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
+ <property name="has_tooltip">True</property>
<child>
- <object class="GtkTreeViewColumn" id="icon_column">
+ <object class="GtkTreeViewColumn" id="ref_icon_column">
<property name="resizable">True</property>
<child>
- <object class="GtkCellRendererPixbuf" id="icon_renderer"/>
+ <object class="GtkCellRendererPixbuf" id="ref_icon_renderer"/>
</child>
</object>
</child>
@@ -1192,13 +1193,10 @@
</object>
</child>
<child>
- <object class="GtkTreeViewColumn" id="shortlog_column">
+ <object class="GtkTreeViewColumn" id="short_log_column">
<property name="resizable">True</property>
<property name="title">Short Log</property>
<property name="expand">True</property>
- <child>
- <object class="GtkCellRendererText" id="shortlog_renderer"/>
- </child>
</object>
</child>
<child>
diff --git a/plugins/git/git-log-pane.c b/plugins/git/git-log-pane.c
index d28b01a..70e8655 100644
--- a/plugins/git/git-log-pane.c
+++ b/plugins/git/git-log-pane.c
@@ -21,6 +21,11 @@
enum
{
+ LOG_COL_REVISION
+};
+
+enum
+{
BRANCH_COL_ACTIVE,
BRANCH_COL_ACTIVE_ICON,
BRANCH_COL_NAME
@@ -30,6 +35,8 @@ struct _GitLogPanePriv
{
GtkBuilder *builder;
GtkListStore *log_model;
+ GtkCellRenderer *graph_renderer;
+ GHashTable *refs;
/* This table maps branch names and iters in the branch combo model. When
* branches get refreshed, use this to make sure that the same branch the
@@ -44,8 +51,8 @@ struct _GitLogPanePriv
G_DEFINE_TYPE (GitLogPane, git_log_pane, GIT_TYPE_PANE);
static void
-on_local_branch_list_command_started (AnjutaCommand *command,
- GitLogPane *self)
+on_branch_list_command_started (AnjutaCommand *command,
+ GitLogPane *self)
{
GtkComboBox *branch_combo;
GtkListStore *log_branch_combo_model;
@@ -62,9 +69,9 @@ on_local_branch_list_command_started (AnjutaCommand *command,
}
static void
-on_remote_branch_list_command_finished (AnjutaCommand *command,
- guint return_code,
- GitLogPane *self)
+on_branch_list_command_finished (AnjutaCommand *command,
+ guint return_code,
+ GitLogPane *self)
{
GtkComboBox *branch_combo;
GtkTreeModel *log_branch_combo_model;
@@ -150,6 +157,118 @@ on_branch_list_command_data_arrived (AnjutaCommand *command,
}
static void
+on_log_command_finished (AnjutaCommand *command, guint return_code,
+ GitLogPane *self)
+{
+ GtkTreeView *log_view;
+ GQueue *queue;
+ GtkTreeIter iter;
+ GitRevision *revision;
+
+ if (return_code != 0)
+ {
+ git_pane_report_errors (command, return_code,
+ ANJUTA_PLUGIN_GIT (anjuta_dock_pane_get_plugin (ANJUTA_DOCK_PANE (self))));
+ g_object_unref (command);
+
+ return;
+ }
+
+ log_view = GTK_TREE_VIEW (gtk_builder_get_object (self->priv->builder,
+ "log_view"));
+
+ g_object_ref (self->priv->log_model);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (log_view), NULL);
+
+ queue = git_log_command_get_output_queue (GIT_LOG_COMMAND (command));
+
+ while (g_queue_peek_head (queue))
+ {
+ revision = g_queue_pop_head (queue);
+
+ gtk_list_store_append (self->priv->log_model, &iter);
+ gtk_list_store_set (self->priv->log_model, &iter, LOG_COL_REVISION,
+ revision, -1);
+
+ g_object_unref (revision);
+ }
+
+ giggle_graph_renderer_validate_model (GIGGLE_GRAPH_RENDERER (self->priv->graph_renderer),
+ GTK_TREE_MODEL (self->priv->log_model),
+ 0);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (log_view),
+ GTK_TREE_MODEL (self->priv->log_model));
+ g_object_unref (self->priv->log_model);
+
+ g_object_unref (command);
+}
+
+static void
+refresh_log (GitLogPane *self)
+{
+ Git *plugin;
+ GitLogCommand *log_command;
+
+ plugin = ANJUTA_PLUGIN_GIT (anjuta_dock_pane_get_plugin (ANJUTA_DOCK_PANE (self)));
+
+ /* We don't support filters for now */
+ log_command = git_log_command_new (plugin->project_root_directory,
+ self->priv->selected_branch,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ g_signal_connect (G_OBJECT (log_command), "command-finished",
+ G_CALLBACK (on_log_command_finished),
+ self);
+
+ gtk_list_store_clear (self->priv->log_model);
+
+ anjuta_command_start (ANJUTA_COMMAND (log_command));
+}
+
+static void
+on_ref_command_finished (AnjutaCommand *command, guint return_code,
+ GitLogPane *self)
+{
+ Git *plugin;
+ GitBranchListCommand *branch_list_command;
+
+ plugin = ANJUTA_PLUGIN_GIT (anjuta_dock_pane_get_plugin (ANJUTA_DOCK_PANE (self)));
+
+ if (self->priv->refs)
+ g_hash_table_unref (self->priv->refs);
+
+ self->priv->refs = git_ref_command_get_refs (GIT_REF_COMMAND (command));
+
+ /* Refresh the branch display after the refs get updated */
+ branch_list_command = git_branch_list_command_new (plugin->project_root_directory,
+ GIT_BRANCH_TYPE_ALL);
+
+ g_signal_connect (G_OBJECT (branch_list_command), "command-started",
+ G_CALLBACK (on_branch_list_command_started),
+ self);
+
+ g_signal_connect (G_OBJECT (branch_list_command), "command-finished",
+ G_CALLBACK (on_branch_list_command_finished),
+ self);
+
+ g_signal_connect (G_OBJECT (branch_list_command), "command-finished",
+ G_CALLBACK (g_object_unref),
+ NULL);
+
+ g_signal_connect (G_OBJECT (branch_list_command), "data-arrived",
+ G_CALLBACK (on_branch_list_command_data_arrived),
+ self);
+
+ anjuta_command_start (ANJUTA_COMMAND (branch_list_command));
+}
+
+static void
on_branch_combo_changed (GtkComboBox *combo_box, GitLogPane *self)
{
GtkTreeModel *log_branch_combo_model;
@@ -172,9 +291,242 @@ on_branch_combo_changed (GtkComboBox *combo_box, GitLogPane *self)
self->priv->selected_branch = g_strdup (branch);
g_free (branch);
+
+ /* Refresh the log after the branches are refreshed so that everything
+ * happens in a consistent order (refs, branches, log) and that
+ * the log only gets refreshed once. Doing the refresh here also
+ * lets us kill two birds with one stone: we can handle refreshes and
+ * different branch selections all in one place. */
+ refresh_log (self);
}
}
+
+static void
+author_cell_function (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
+ GtkTreeModel *model, GtkTreeIter *iter,
+ gpointer user_data)
+{
+ GitRevision *revision;
+ gchar *author;
+
+ gtk_tree_model_get (model, iter, LOG_COL_REVISION, &revision, -1);
+ author = git_revision_get_author (revision);
+
+ g_object_unref (revision);
+
+ g_object_set (renderer, "text", author, NULL);
+
+ g_free (author);
+}
+
+static void
+date_cell_function (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
+ GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data)
+{
+ GitRevision *revision;
+ gchar *date;
+
+ gtk_tree_model_get (model, iter, LOG_COL_REVISION, &revision, -1);
+ date = git_revision_get_formatted_date (revision);
+
+ g_object_unref (revision);
+
+ g_object_set (renderer, "text", date, NULL);
+
+ g_free (date);
+}
+
+static void
+short_log_cell_function (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
+ GtkTreeModel *model, GtkTreeIter *iter,
+ gpointer user_data)
+{
+ GitRevision *revision;
+ gchar *short_log;
+
+ gtk_tree_model_get (model, iter, LOG_COL_REVISION, &revision, -1);
+ short_log = git_revision_get_short_log (revision);
+
+ g_object_unref (revision);
+
+ g_object_set (renderer, "text", short_log, NULL);
+
+ g_free (short_log);
+}
+
+static void
+ref_icon_cell_function (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
+ GtkTreeModel *model, GtkTreeIter *iter,
+ GitLogPane *self)
+{
+ GitRevision *revision;
+ gchar *sha;
+
+ gtk_tree_model_get (model, iter, LOG_COL_REVISION, &revision, -1);
+ sha = git_revision_get_sha (revision);
+
+ g_object_unref (revision);
+
+ if (g_hash_table_lookup_extended (self->priv->refs, sha, NULL, NULL))
+ g_object_set (renderer, "stock-id", GTK_STOCK_INFO, NULL);
+ else
+ g_object_set (renderer, "stock-id", "", NULL);
+
+ g_free (sha);
+}
+
+static gboolean
+on_log_view_query_tooltip (GtkWidget *log_view, gint x, gint y,
+ gboolean keyboard_mode, GtkTooltip *tooltip,
+ GitLogPane *self)
+{
+ gboolean ret;
+ GtkTreeViewColumn *ref_icon_column;
+ gint bin_x;
+ gint bin_y;
+ GtkTreeViewColumn *current_column;
+ GtkTreePath *path;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GitRevision *revision;
+ gchar *sha;
+ GList *ref_list;
+ GList *current_ref;
+ GString *tooltip_string;
+ gchar *ref_name;
+ GitRefType ref_type;
+
+ ret = FALSE;
+
+ ref_icon_column = gtk_tree_view_get_column (GTK_TREE_VIEW (log_view), 0);
+
+ gtk_tree_view_convert_widget_to_bin_window_coords (GTK_TREE_VIEW (log_view),
+ x, y, &bin_x, &bin_y);
+ gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (log_view), bin_x,
+ bin_y, &path, ¤t_column, NULL, NULL);
+
+ /* We need to be in the ref icon column */
+ if (current_column == ref_icon_column)
+ {
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (log_view));
+ gtk_tree_model_get_iter (model, &iter, path);
+
+ gtk_tree_model_get (model, &iter, LOG_COL_REVISION, &revision, -1);
+ sha = git_revision_get_sha (revision);
+
+ g_object_unref (revision);
+
+ ref_list = g_hash_table_lookup (self->priv->refs, sha);
+ g_free (sha);
+
+ if (ref_list)
+ {
+ current_ref = ref_list;
+ tooltip_string = g_string_new ("");
+
+ while (current_ref)
+ {
+ ref_name = git_ref_get_name (GIT_REF (current_ref->data));
+ ref_type = git_ref_get_ref_type (GIT_REF (current_ref->data));
+
+ if (tooltip_string->len > 0)
+ g_string_append (tooltip_string, "\n");
+
+ switch (ref_type)
+ {
+ case GIT_REF_TYPE_BRANCH:
+ g_string_append_printf (tooltip_string,
+ _("<b>Branch:</b> %s"),
+ ref_name);
+ break;
+ case GIT_REF_TYPE_TAG:
+ g_string_append_printf (tooltip_string,
+ _("<b>Tag:</b> %s"),
+ ref_name);
+ break;
+ case GIT_REF_TYPE_REMOTE:
+ g_string_append_printf (tooltip_string,
+ _("<b>Remote:</b> %s"),
+ ref_name);
+ break;
+ default:
+ break;
+ }
+
+ g_free (ref_name);
+ current_ref = g_list_next (current_ref);
+ }
+
+ gtk_tooltip_set_markup (tooltip, tooltip_string->str);
+ g_string_free (tooltip_string, TRUE);
+
+ ret = TRUE;
+ }
+ }
+
+ gtk_tree_path_free (path);
+ return ret;
+
+
+}
+
+static void
+on_log_message_command_finished (AnjutaCommand *command, guint return_code,
+ GitLogPane *self)
+{
+ GtkWidget *log_text_view;
+ GtkTextBuffer *buffer;
+ gchar *log_message;
+
+ log_text_view = GTK_WIDGET (gtk_builder_get_object (self->priv->builder,
+ "log_text_view"));
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (log_text_view));
+ log_message = git_log_message_command_get_message (GIT_LOG_MESSAGE_COMMAND (command));
+
+ gtk_text_buffer_set_text (buffer, log_message, strlen (log_message));
+
+ g_free (log_message);
+ g_object_unref (command);
+}
+
+static gboolean
+on_log_view_row_selected (GtkTreeSelection *selection,
+ GtkTreeModel *model,
+ GtkTreePath *path,
+ gboolean path_currently_selected,
+ GitLogPane *self)
+{
+ Git *plugin;
+ GtkTreeIter iter;
+ GitRevision *revision;
+ gchar *sha;
+ GitLogMessageCommand *log_message_command;
+
+ if (!path_currently_selected)
+ {
+ plugin = ANJUTA_PLUGIN_GIT (anjuta_dock_pane_get_plugin (ANJUTA_DOCK_PANE (self)));
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, LOG_COL_REVISION, &revision, -1);
+ sha = git_revision_get_sha (revision);
+
+ log_message_command = git_log_message_command_new (plugin->project_root_directory,
+ sha);
+
+ g_free (sha);
+ g_object_unref (revision);
+
+ g_signal_connect (G_OBJECT (log_message_command), "command-finished",
+ G_CALLBACK (on_log_message_command_finished),
+ self);
+
+ anjuta_command_start (ANJUTA_COMMAND (log_message_command));
+ }
+
+ return TRUE;
+}
+
static void
git_log_pane_init (GitLogPane *self)
{
@@ -185,7 +537,17 @@ git_log_pane_init (GitLogPane *self)
NULL};
GError *error = NULL;
GtkTreeView *log_view;
+ GtkTreeViewColumn *ref_icon_column;
+ GtkTreeViewColumn *graph_column;
+ GtkTreeViewColumn *short_log_column;
+ GtkTreeViewColumn *author_column;
+ GtkTreeViewColumn *date_column;
+ GtkCellRenderer *ref_icon_renderer;
+ GtkCellRenderer *short_log_renderer;
+ GtkCellRenderer *author_renderer;
+ GtkCellRenderer *date_renderer;
GtkComboBox *branch_combo;
+ GtkTreeSelection *selection;
self->priv = g_new0 (GitLogPanePriv, 1);
self->priv->builder = gtk_builder_new ();
@@ -200,14 +562,76 @@ git_log_pane_init (GitLogPane *self)
log_view = GTK_TREE_VIEW (gtk_builder_get_object (self->priv->builder,
"log_view"));
+ ref_icon_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (self->priv->builder,
+ "ref_icon_column"));
+ graph_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (self->priv->builder,
+ "graph_column"));
+ short_log_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (self->priv->builder,
+ "short_log_column"));
+ author_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (self->priv->builder,
+ "author_column"));
+ date_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (self->priv->builder,
+ "date_column"));
+ ref_icon_renderer = GTK_CELL_RENDERER (gtk_builder_get_object (self->priv->builder,
+ "ref_icon_renderer"));
+ author_renderer = GTK_CELL_RENDERER (gtk_builder_get_object (self->priv->builder,
+ "author_renderer"));
+ date_renderer = GTK_CELL_RENDERER (gtk_builder_get_object (self->priv->builder,
+ "date_renderer"));
branch_combo = GTK_COMBO_BOX (gtk_builder_get_object (self->priv->builder,
"branch_combo"));
+ selection = gtk_tree_view_get_selection (log_view);
/* Set up the log model */
self->priv->log_model = gtk_list_store_new (1, GIT_TYPE_REVISION);
+ /* Ref icon column */
+ gtk_tree_view_column_set_cell_data_func (ref_icon_column, ref_icon_renderer,
+ (GtkTreeCellDataFunc) ref_icon_cell_function,
+ self, NULL);
+
+
+ /* Graph column */
+ self->priv->graph_renderer = giggle_graph_renderer_new ();
+
+ gtk_tree_view_column_pack_start (graph_column, self->priv->graph_renderer,
+ TRUE);
+ gtk_tree_view_column_add_attribute (graph_column, self->priv->graph_renderer,
+ "revision", 0);
+
+ /* Short log column. We have to create this render ouselves becuause Glade
+ * doesn't seem to give us to option to pack it with expand */
+ short_log_renderer = gtk_cell_renderer_text_new ();
+ g_object_set (G_OBJECT (short_log_renderer), "ellipsize",
+ PANGO_ELLIPSIZE_END, NULL);
+ gtk_tree_view_column_pack_start (short_log_column, short_log_renderer,
+ TRUE);
+ gtk_tree_view_column_set_cell_data_func (short_log_column, short_log_renderer,
+ (GtkTreeCellDataFunc) short_log_cell_function,
+ NULL, NULL);
+
+ /* Author column */
+ gtk_tree_view_column_set_cell_data_func (author_column, author_renderer,
+ (GtkTreeCellDataFunc) author_cell_function,
+ NULL, NULL);
+
+ /* Date column */
+ gtk_tree_view_column_set_cell_data_func (date_column, date_renderer,
+ (GtkTreeCellDataFunc) date_cell_function,
+ NULL, NULL);
+
gtk_tree_view_set_model (log_view, GTK_TREE_MODEL (self->priv->log_model));
+ /* Ref icon tooltip */
+ g_signal_connect (G_OBJECT (log_view), "query-tooltip",
+ G_CALLBACK (on_log_view_query_tooltip),
+ self);
+
+ /* Log message display */
+ gtk_tree_selection_set_select_function (selection,
+ (GtkTreeSelectionFunc) on_log_view_row_selected,
+ self, NULL);
+
/* Branch handling */
self->priv->branches_table = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_free);
@@ -263,24 +687,8 @@ git_log_pane_new (Git *plugin)
self = g_object_new (GIT_TYPE_LOG_PANE, "plugin", plugin, NULL);
- g_signal_connect (G_OBJECT (plugin->local_branch_list_command),
- "command-started",
- G_CALLBACK (on_local_branch_list_command_started),
- self);
-
- g_signal_connect (G_OBJECT (plugin->remote_branch_list_command),
- "command-finished",
- G_CALLBACK (on_remote_branch_list_command_finished),
- self);
-
- g_signal_connect (G_OBJECT (plugin->local_branch_list_command),
- "data-arrived",
- G_CALLBACK (on_branch_list_command_data_arrived),
- self);
-
- g_signal_connect (G_OBJECT (plugin->remote_branch_list_command),
- "data-arrived",
- G_CALLBACK (on_branch_list_command_data_arrived),
+ g_signal_connect (G_OBJECT (plugin->ref_command), "command-finished",
+ G_CALLBACK (on_ref_command_finished),
self);
return ANJUTA_DOCK_PANE (self);
diff --git a/plugins/git/git-log-pane.h b/plugins/git/git-log-pane.h
index 85e5e43..4845f84 100644
--- a/plugins/git/git-log-pane.h
+++ b/plugins/git/git-log-pane.h
@@ -23,7 +23,9 @@
#include <glib-object.h>
#include "git-pane.h"
#include "git-log-command.h"
+#include "git-log-message-command.h"
#include "git-ref-command.h"
+#include "giggle-graph-renderer.h"
G_BEGIN_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]