[gitg] Added 'changes' panel
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gitg] Added 'changes' panel
- Date: Mon, 31 May 2010 22:17:29 +0000 (UTC)
commit 7f8fad1e7db08721735d12121b36986ecd797030
Author: Jesse van den Kieboom <jessevdk gnome org>
Date: Mon May 31 23:51:09 2010 +0200
Added 'changes' panel
gitg/Makefile.am | 82 +-
gitg/gitg-revision-changes-panel.c | 937 ++++++++++++++++++++
gitg/gitg-revision-changes-panel.h | 34 +
gitg/gitg-revision-changes.ui | 76 ++
...es-view-panel.c => gitg-revision-files-panel.c} | 45 +-
gitg/gitg-revision-files-panel.h | 61 ++
gitg/gitg-revision-files-view-panel.h | 61 --
gitg/gitg-window.c | 6 +-
8 files changed, 1178 insertions(+), 124 deletions(-)
---
diff --git a/gitg/Makefile.am b/gitg/Makefile.am
index 1a1e86d..633cce8 100644
--- a/gitg/Makefile.am
+++ b/gitg/Makefile.am
@@ -11,48 +11,48 @@ AM_CPPFLAGS = \
-DGITG_DATADIR=\""$(datadir)/gitg"\" \
-DGITG_LOCALEDIR=\""$(datadir)/locale"\"
-NOINST_H_FILES = \
- gitg-branch-actions.h \
- gitg-cell-renderer-path.h \
- gitg-commit-view.h \
- gitg-data-binding.h \
- gitg-diff-line-renderer.h \
- gitg-diff-view.h \
- gitg-dirs.h \
- gitg-dnd.h \
- gitg-label-renderer.h \
- gitg-preferences-dialog.h \
- gitg-preferences.h \
- gitg-repository-dialog.h \
- gitg-revision-panel.h \
- gitg-revision-files-view-panel.h \
- gitg-revision-view.h \
- gitg-settings.h \
- gitg-utils.h \
- gitg-window.h \
+NOINST_H_FILES = \
+ gitg-branch-actions.h \
+ gitg-cell-renderer-path.h \
+ gitg-commit-view.h \
+ gitg-data-binding.h \
+ gitg-diff-line-renderer.h \
+ gitg-diff-view.h \
+ gitg-dirs.h \
+ gitg-dnd.h \
+ gitg-label-renderer.h \
+ gitg-preferences-dialog.h \
+ gitg-preferences.h \
+ gitg-repository-dialog.h \
+ gitg-revision-panel.h \
+ gitg-revision-files-panel.h \
+ gitg-revision-changes-panel.h \
+ gitg-settings.h \
+ gitg-utils.h \
+ gitg-window.h \
gseal-gtk-compat.h
-gitg_SOURCES = \
- $(BUILT_SOURCES) \
- gitg.c \
- gitg-branch-actions.c \
- gitg-cell-renderer-path.c \
- gitg-commit-view.c \
- gitg-data-binding.c \
- gitg-diff-line-renderer.c \
- gitg-diff-view.c \
- gitg-dirs.c \
- gitg-dnd.c \
- gitg-label-renderer.c \
- gitg-preferences.c \
- gitg-preferences-dialog.c \
- gitg-repository-dialog.c \
- gitg-revision-panel.c \
- gitg-revision-files-view-panel.c \
- gitg-revision-view.c \
- gitg-settings.c \
- gitg-utils.c \
- gitg-window.c \
+gitg_SOURCES = \
+ $(BUILT_SOURCES) \
+ gitg.c \
+ gitg-branch-actions.c \
+ gitg-cell-renderer-path.c \
+ gitg-commit-view.c \
+ gitg-data-binding.c \
+ gitg-diff-line-renderer.c \
+ gitg-diff-view.c \
+ gitg-dirs.c \
+ gitg-dnd.c \
+ gitg-label-renderer.c \
+ gitg-preferences.c \
+ gitg-preferences-dialog.c \
+ gitg-repository-dialog.c \
+ gitg-revision-panel.c \
+ gitg-revision-files-panel.c \
+ gitg-revision-changes-panel.c \
+ gitg-settings.c \
+ gitg-utils.c \
+ gitg-window.c \
$(NOINST_H_FILES)
gitg_LDADD = \
@@ -71,7 +71,7 @@ ui_DATA = \
gitg-preferences.ui \
gitg-tag.ui \
gitg-repository.ui \
- gitg-revision-view.ui \
+ gitg-revision-changes.ui \
gitg-revision-files-view.ui
EXTRA_DIST = \
diff --git a/gitg/gitg-revision-changes-panel.c b/gitg/gitg-revision-changes-panel.c
new file mode 100644
index 0000000..c023055
--- /dev/null
+++ b/gitg/gitg-revision-changes-panel.c
@@ -0,0 +1,937 @@
+#include "gitg-revision-changes-panel.h"
+
+#include <gtksourceview/gtksourceview.h>
+#include <gtksourceview/gtksourcelanguagemanager.h>
+#include <gtksourceview/gtksourcestyleschememanager.h>
+#include <string.h>
+#include <libgitg/gitg-repository.h>
+#include <libgitg/gitg-revision.h>
+#include <libgitg/gitg-runner.h>
+#include <libgitg/gitg-hash.h>
+#include "gitg-diff-view.h"
+#include "gitg-utils.h"
+#include <glib/gi18n.h>
+
+#include "gitg-revision-panel.h"
+
+#define GITG_REVISION_CHANGES_PANEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_REVISION_CHANGES_PANEL, GitgRevisionChangesPanelPrivate))
+
+struct _GitgRevisionChangesPanelPrivate
+{
+ GtkWidget *panel_widget;
+ GtkBuilder *builder;
+
+ GtkSourceView *diff;
+ GtkTreeView *diff_files;
+ GtkListStore *list_store_diff_files;
+
+ GitgRunner *diff_runner;
+ GitgRunner *diff_files_runner;
+
+ GitgRepository *repository;
+ GitgRevision *revision;
+ GSList *cached_headers;
+};
+
+typedef enum
+{
+ DIFF_FILE_STATUS_NONE,
+ DIFF_FILE_STATUS_NEW,
+ DIFF_FILE_STATUS_MODIFIED,
+ DIFF_FILE_STATUS_DELETED
+} DiffFileStatus;
+
+typedef struct
+{
+ GitgDiffIter iter;
+} CachedHeader;
+
+typedef struct
+{
+ gint refcount;
+
+ gchar index_from[GITG_HASH_SHA_SIZE + 1];
+ gchar index_to[GITG_HASH_SHA_SIZE + 1];
+ DiffFileStatus status;
+ gchar *filename;
+
+ gboolean visible;
+ GitgDiffIter iter;
+} DiffFile;
+
+static void gitg_revision_panel_iface_init (GitgRevisionPanelInterface *iface);
+static void on_header_added (GitgDiffView *view, GitgDiffIter *iter, GitgRevisionChangesPanel *self);
+static void on_diff_files_selection_changed (GtkTreeSelection *selection, GitgRevisionChangesPanel *self);
+
+G_DEFINE_TYPE_EXTENDED (GitgRevisionChangesPanel,
+ gitg_revision_changes_panel,
+ G_TYPE_OBJECT,
+ 0,
+ G_IMPLEMENT_INTERFACE (GITG_TYPE_REVISION_PANEL,
+ gitg_revision_panel_iface_init));
+
+static void set_revision (GitgRevisionChangesPanel *panel,
+ GitgRepository *repository,
+ GitgRevision *revision);
+
+static DiffFile *
+diff_file_new (gchar const *from,
+ gchar *to,
+ gchar const *status,
+ gchar const *filename)
+{
+ DiffFile *f = g_slice_new (DiffFile);
+
+ strncpy (f->index_from, from, GITG_HASH_SHA_SIZE);
+ strncpy (f->index_to, to, GITG_HASH_SHA_SIZE);
+
+ f->index_from[GITG_HASH_SHA_SIZE] = '\0';
+ f->index_to[GITG_HASH_SHA_SIZE] = '\0';
+ f->visible = FALSE;
+
+ DiffFileStatus st;
+
+ switch (*status)
+ {
+ case 'A':
+ st = DIFF_FILE_STATUS_NEW;
+ break;
+ case 'D':
+ st = DIFF_FILE_STATUS_DELETED;
+ break;
+ default:
+ st = DIFF_FILE_STATUS_MODIFIED;
+ break;
+ }
+
+ f->status = st;
+ f->filename = g_strdup (filename);
+ f->refcount = 1;
+
+ return f;
+}
+
+static DiffFile *
+diff_file_copy (DiffFile *f)
+{
+ g_atomic_int_inc (&f->refcount);
+ return f;
+}
+
+static void
+diff_file_unref (DiffFile *f)
+{
+ if (!g_atomic_int_dec_and_test (&f->refcount))
+ {
+ return;
+ }
+
+ g_free (f->filename);
+ g_slice_free (DiffFile, f);
+}
+
+static GType
+diff_file_get_type ()
+{
+ static GType gtype = 0;
+
+ if (!G_UNLIKELY(gtype))
+ {
+ gtype = g_boxed_type_register_static ("DiffFile",
+ (GBoxedCopyFunc)diff_file_copy,
+ (GBoxedFreeFunc)diff_file_unref);
+ }
+
+ return gtype;
+}
+
+static void
+revision_files_icon (GtkTreeViewColumn *column,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GitgRevisionChangesPanel *self)
+{
+ DiffFile *f;
+ gtk_tree_model_get (model, iter, 0, &f, -1);
+
+ gchar const *id = NULL;
+
+ switch (f->status)
+ {
+ case DIFF_FILE_STATUS_NEW:
+ id = GTK_STOCK_NEW;
+ break;
+ case DIFF_FILE_STATUS_MODIFIED:
+ id = GTK_STOCK_EDIT;
+ break;
+ case DIFF_FILE_STATUS_DELETED:
+ id = GTK_STOCK_DELETE;
+ break;
+ default:
+ break;
+ }
+
+ g_object_set (G_OBJECT(renderer), "stock-id", id, NULL);
+ diff_file_unref (f);
+}
+
+static void
+revision_files_name (GtkTreeViewColumn *column,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GitgRevisionChangesPanel *self)
+{
+ DiffFile *f;
+ gtk_tree_model_get (model, iter, 0, &f, -1);
+
+ g_object_set (G_OBJECT(renderer), "text", f->filename, NULL);
+
+ diff_file_unref (f);
+}
+
+static gboolean
+diff_file_visible (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ DiffFile *f;
+ gtk_tree_model_get (model, iter, 0, &f, -1);
+
+ if (!f)
+ {
+ return FALSE;
+ }
+
+ gboolean ret = f->visible;
+ diff_file_unref (f);
+
+ return ret;
+}
+
+static gboolean
+on_diff_files_button_press (GtkTreeView *treeview,
+ GdkEventButton *event,
+ GitgRevisionChangesPanel *view)
+{
+ if (event->button != 1)
+ {
+ return FALSE;
+ }
+
+ if (event->window != gtk_tree_view_get_bin_window (treeview))
+ {
+ return FALSE;
+ }
+
+ GtkTreePath *path;
+
+ if (!gtk_tree_view_get_path_at_pos (treeview,
+ event->x,
+ event->y,
+ &path,
+ NULL,
+ NULL,
+ NULL))
+ {
+ return FALSE;
+ }
+
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
+ gboolean ret = FALSE;
+
+ if (gtk_tree_selection_path_is_selected (selection, path) &&
+ gtk_tree_selection_count_selected_rows (selection) == 1)
+ {
+ /* deselect */
+ gtk_tree_selection_unselect_path (selection, path);
+ ret = TRUE;
+ }
+
+ gtk_tree_path_free (path);
+ return ret;
+}
+
+static void
+gitg_revision_panel_update_impl (GitgRevisionPanel *panel,
+ GitgRepository *repository,
+ GitgRevision *revision)
+{
+ GitgRevisionChangesPanel *changes_panel;
+
+ changes_panel = GITG_REVISION_CHANGES_PANEL (panel);
+
+ set_revision (changes_panel, repository, revision);
+}
+
+static gchar *
+gitg_revision_panel_get_label_impl (GitgRevisionPanel *panel)
+{
+ return g_strdup (_("Changes"));
+}
+
+static void
+initialize_ui (GitgRevisionChangesPanel *changes_panel)
+{
+ GitgRevisionChangesPanelPrivate *priv = changes_panel->priv;
+
+ priv->diff = GTK_SOURCE_VIEW (gtk_builder_get_object (priv->builder,
+ "revision_diff"));
+
+ priv->diff_files = GTK_TREE_VIEW (gtk_builder_get_object (priv->builder,
+ "tree_view_revision_files"));
+
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (priv->diff_files);
+
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+
+ g_signal_connect (selection,
+ "changed",
+ G_CALLBACK (on_diff_files_selection_changed),
+ changes_panel);
+
+ g_signal_connect (priv->diff_files,
+ "button-press-event",
+ G_CALLBACK (on_diff_files_button_press),
+ changes_panel);
+
+ priv->list_store_diff_files = gtk_list_store_new (1, diff_file_get_type ());
+
+ GtkTreeModel *filter;
+
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL(priv->list_store_diff_files),
+ NULL);
+ gtk_tree_view_set_model (priv->diff_files, filter);
+
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+ diff_file_visible,
+ NULL,
+ NULL);
+
+ GtkTreeViewColumn *column;
+
+ column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (priv->builder,
+ "revision_files_column_icon"));
+
+ gtk_tree_view_column_set_cell_data_func (column,
+ GTK_CELL_RENDERER (gtk_builder_get_object (priv->builder,
+ "revision_files_cell_renderer_icon")),
+ (GtkTreeCellDataFunc)revision_files_icon,
+ changes_panel,
+ NULL);
+
+ column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (priv->builder,
+ "revision_files_column_name"));
+ gtk_tree_view_column_set_cell_data_func (column,
+ GTK_CELL_RENDERER (gtk_builder_get_object (priv->builder,
+ "revision_files_cell_renderer_name")),
+ (GtkTreeCellDataFunc)revision_files_name,
+ changes_panel,
+ NULL);
+
+ GtkSourceLanguageManager *manager;
+ GtkSourceLanguage *language;
+ GtkSourceBuffer *buffer;
+
+ manager = gtk_source_language_manager_get_default ();
+ language = gtk_source_language_manager_get_language (manager, "gitgdiff");
+ buffer = gtk_source_buffer_new_with_language (language);
+
+ g_object_unref (language);
+
+ GtkSourceStyleSchemeManager *scheme_manager;
+ GtkSourceStyleScheme *scheme;
+
+ scheme_manager = gtk_source_style_scheme_manager_get_default ();
+ scheme = gtk_source_style_scheme_manager_get_scheme (scheme_manager,
+ "gitg");
+ gtk_source_buffer_set_style_scheme (buffer, scheme);
+
+ gitg_utils_set_monospace_font (GTK_WIDGET (priv->diff));
+ gtk_text_view_set_buffer (GTK_TEXT_VIEW (priv->diff),
+ GTK_TEXT_BUFFER (buffer));
+
+ g_signal_connect (priv->diff,
+ "header-added",
+ G_CALLBACK (on_header_added),
+ changes_panel);
+}
+
+static GtkWidget *
+gitg_revision_panel_get_panel_impl (GitgRevisionPanel *panel)
+{
+ GtkBuilder *builder;
+ GtkWidget *ret;
+ GitgRevisionChangesPanel *changes_panel;
+
+ changes_panel = GITG_REVISION_CHANGES_PANEL (panel);
+
+ if (changes_panel->priv->panel_widget)
+ {
+ return changes_panel->priv->panel_widget;
+ }
+
+ builder = gitg_utils_new_builder ("gitg-revision-changes.ui");
+ changes_panel->priv->builder = builder;
+
+ ret = GTK_WIDGET (gtk_builder_get_object (builder, "revision_changes_page"));
+ changes_panel->priv->panel_widget = ret;
+
+ initialize_ui (changes_panel);
+
+ return ret;
+}
+
+static void
+gitg_revision_panel_iface_init (GitgRevisionPanelInterface *iface)
+{
+ iface->update = gitg_revision_panel_update_impl;
+ iface->get_label = gitg_revision_panel_get_label_impl;
+ iface->get_panel = gitg_revision_panel_get_panel_impl;
+}
+
+static void
+free_cached_header (gpointer header)
+{
+ g_slice_free (CachedHeader, header);
+}
+
+static void
+free_cached_headers (GitgRevisionChangesPanel *changes_panel)
+{
+ g_slist_foreach (changes_panel->priv->cached_headers,
+ (GFunc)free_cached_header,
+ NULL);
+
+ g_slist_free (changes_panel->priv->cached_headers);
+
+ changes_panel->priv->cached_headers = NULL;
+}
+
+
+static void
+gitg_revision_changes_panel_finalize (GObject *object)
+{
+ free_cached_headers (GITG_REVISION_CHANGES_PANEL (object));
+
+ G_OBJECT_CLASS (gitg_revision_changes_panel_parent_class)->finalize (object);
+}
+
+static void
+gitg_revision_changes_panel_dispose (GObject *object)
+{
+ GitgRevisionChangesPanel *changes_panel;
+
+ changes_panel = GITG_REVISION_CHANGES_PANEL (object);
+
+ set_revision (changes_panel, NULL, NULL);
+
+ if (changes_panel->priv->diff_files_runner)
+ {
+ g_object_unref (changes_panel->priv->diff_files_runner);
+ changes_panel->priv->diff_files_runner = NULL;
+ }
+
+ if (changes_panel->priv->diff_files_runner)
+ {
+ g_object_unref (changes_panel->priv->diff_runner);
+ changes_panel->priv->diff_runner = NULL;
+ }
+
+ if (changes_panel->priv->builder)
+ {
+ g_object_unref (changes_panel->priv->builder);
+ }
+
+ G_OBJECT_CLASS (gitg_revision_changes_panel_parent_class)->dispose (object);
+}
+
+static void
+gitg_revision_changes_panel_class_init (GitgRevisionChangesPanelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gitg_revision_changes_panel_finalize;
+ object_class->dispose = gitg_revision_changes_panel_dispose;
+
+ g_type_class_add_private (object_class, sizeof(GitgRevisionChangesPanelPrivate));
+}
+
+static void
+reload_diff (GitgRevisionChangesPanel *changes_panel)
+{
+ GtkTreeSelection *selection;
+
+ // First cancel a possibly still running diff
+ gitg_runner_cancel (changes_panel->priv->diff_runner);
+ gitg_runner_cancel (changes_panel->priv->diff_files_runner);
+
+ free_cached_headers (changes_panel);
+
+ // Clear the buffer
+ GtkTextBuffer *buffer;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (changes_panel->priv->diff));
+ gtk_text_buffer_set_text (buffer, "", 0);
+
+ selection = gtk_tree_view_get_selection (changes_panel->priv->diff_files);
+ g_signal_handlers_block_by_func (selection,
+ G_CALLBACK (on_diff_files_selection_changed),
+ changes_panel);
+
+ gtk_list_store_clear (changes_panel->priv->list_store_diff_files);
+
+ g_signal_handlers_unblock_by_func (selection,
+ G_CALLBACK (on_diff_files_selection_changed),
+ changes_panel);
+
+ if (!changes_panel->priv->revision)
+ {
+ return;
+ }
+
+ gchar sign = gitg_revision_get_sign (changes_panel->priv->revision);
+
+ switch (sign)
+ {
+ case 't':
+ gitg_repository_run_commandv (changes_panel->priv->repository,
+ changes_panel->priv->diff_runner,
+ NULL,
+ "diff",
+ "--cached",
+ "-M",
+ "--pretty=format:%s%n%n%b",
+ "--encoding=UTF-8",
+ "--no-color",
+ NULL);
+ break;
+ case 'u':
+ gitg_repository_run_commandv (changes_panel->priv->repository,
+ changes_panel->priv->diff_runner,
+ NULL,
+ "diff",
+ "-M",
+ "--pretty=format:%s%n%n%b",
+ "--encoding=UTF-8",
+ "--no-color",
+ NULL);
+ break;
+ default:
+ {
+ gchar *hash = gitg_revision_get_sha1 (changes_panel->priv->revision);
+ gitg_repository_run_commandv (changes_panel->priv->repository,
+ changes_panel->priv->diff_runner,
+ NULL,
+ "show",
+ "-M",
+ "--pretty=format:%s%n%n%b",
+ "--encoding=UTF-8",
+ "--no-color",
+ hash,
+ NULL);
+
+ g_free (hash);
+ }
+ break;
+ }
+}
+
+static void
+set_revision (GitgRevisionChangesPanel *changes_panel,
+ GitgRepository *repository,
+ GitgRevision *revision)
+{
+ if (changes_panel->priv->repository == repository &&
+ changes_panel->priv->revision == revision)
+ {
+ return;
+ }
+
+ if (changes_panel->priv->diff_runner)
+ {
+ gitg_runner_cancel (changes_panel->priv->diff_runner);
+ }
+
+ if (changes_panel->priv->diff_files_runner)
+ {
+ gitg_runner_cancel (changes_panel->priv->diff_files_runner);
+ }
+
+ if (changes_panel->priv->repository)
+ {
+ g_object_unref (changes_panel->priv->repository);
+ }
+
+ if (changes_panel->priv->revision)
+ {
+ gitg_revision_unref (changes_panel->priv->revision);
+ }
+
+ if (repository)
+ {
+ changes_panel->priv->repository = g_object_ref (repository);
+ }
+ else
+ {
+ changes_panel->priv->repository = NULL;
+ }
+
+ if (revision)
+ {
+ changes_panel->priv->revision = gitg_revision_ref (revision);
+ }
+ else
+ {
+ changes_panel->priv->revision = NULL;
+ }
+
+ if (changes_panel->priv->repository && changes_panel->priv->revision)
+ {
+ reload_diff (changes_panel);
+ }
+}
+
+static void
+on_diff_files_begin_loading (GitgRunner *runner,
+ GitgRevisionChangesPanel *self)
+{
+ GdkCursor *cursor = gdk_cursor_new (GDK_WATCH);
+ gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (self->priv->diff_files)),
+ cursor);
+ gdk_cursor_unref (cursor);
+}
+
+static void
+on_diff_files_end_loading (GitgRunner *runner,
+ gboolean cancelled,
+ GitgRevisionChangesPanel *self)
+{
+ gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET(self->priv->diff_files)),
+ NULL);
+}
+
+static gboolean
+match_indices (DiffFile *f,
+ gchar const *from,
+ gchar const *to)
+{
+ return g_str_has_prefix (f->index_from, from) &&
+ (g_str_has_prefix (f->index_to, to) ||
+ g_str_has_prefix (f->index_to, "0000000"));
+}
+
+static void
+visible_from_cached_headers (GitgRevisionChangesPanel *view,
+ DiffFile *f)
+{
+ GSList *item;
+
+ for (item = view->priv->cached_headers; item; item = g_slist_next (item))
+ {
+ CachedHeader *header = (CachedHeader *)item->data;
+ gchar *from;
+ gchar *to;
+
+ gitg_diff_iter_get_index (&header->iter, &from, &to);
+
+ if (gitg_diff_iter_get_index (&header->iter, &from, &to) && match_indices (f, from, to))
+ {
+ f->visible = TRUE;
+ f->iter = header->iter;
+
+ return;
+ }
+ }
+}
+
+static void
+add_diff_file (GitgRevisionChangesPanel *view,
+ DiffFile *f)
+{
+ GtkTreeIter iter;
+ gtk_list_store_append (view->priv->list_store_diff_files, &iter);
+
+ /* see if it is in the cached headers */
+ visible_from_cached_headers (view, f);
+ gtk_list_store_set (view->priv->list_store_diff_files, &iter, 0, f, -1);
+}
+
+static void
+on_diff_files_update (GitgRunner *runner,
+ gchar **buffer,
+ GitgRevisionChangesPanel *self)
+{
+ gchar **line;
+
+ while (*(line = buffer++))
+ {
+ if (**line == '\0')
+ {
+ continue;
+ }
+
+ // Count parents
+ gint parents = 0;
+ gchar *ptr = *line;
+
+ while (*(ptr++) == ':')
+ {
+ ++parents;
+ }
+
+ gint numparts = 3 + 2 * parents;
+ gchar **parts = g_strsplit (ptr, " ", numparts);
+
+ if (g_strv_length (parts) == numparts)
+ {
+ gchar **files = g_strsplit (parts[numparts - 1], "\t", -1);
+
+ DiffFile *f = diff_file_new (parts[parents + 1], parts[numparts - 2], files[0], files[1]);
+
+ add_diff_file (self, f);
+ diff_file_unref (f);
+
+ g_strfreev (files);
+ }
+
+ g_strfreev (parts);
+ }
+}
+
+static void
+on_diff_begin_loading (GitgRunner *runner,
+ GitgRevisionChangesPanel *self)
+{
+ GdkCursor *cursor = gdk_cursor_new (GDK_WATCH);
+ gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET(self->priv->diff)),
+ cursor);
+ gdk_cursor_unref (cursor);
+}
+
+static void
+on_diff_end_loading (GitgRunner *runner,
+ gboolean cancelled,
+ GitgRevisionChangesPanel *self)
+{
+ gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET(self->priv->diff)),
+ NULL);
+
+ if (cancelled)
+ {
+ return;
+ }
+
+ gchar sign = gitg_revision_get_sign (self->priv->revision);
+
+ if (sign == 't' || sign == 'u')
+ {
+ gchar *head = gitg_repository_parse_head (self->priv->repository);
+ const gchar *cached = NULL;
+
+ if (sign == 't')
+ cached = "--cached";
+
+ gitg_repository_run_commandv (self->priv->repository,
+ self->priv->diff_files_runner,
+ NULL,
+ "diff-index",
+ "--raw",
+ "-M",
+ "--abbrev=40",
+ head,
+ cached,
+ NULL);
+ g_free (head);
+ }
+ else
+ {
+ gchar *sha = gitg_revision_get_sha1 (self->priv->revision);
+ gitg_repository_run_commandv (self->priv->repository,
+ self->priv->diff_files_runner,
+ NULL,
+ "show",
+ "--encoding=UTF-8",
+ "--raw",
+ "-M",
+ "--pretty=format:",
+ "--abbrev=40",
+ sha,
+ NULL);
+ g_free (sha);
+ }
+}
+
+static void
+on_diff_update (GitgRunner *runner,
+ gchar **buffer,
+ GitgRevisionChangesPanel *self)
+{
+ gchar *line;
+ GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW(self->priv->diff));
+ GtkTextIter iter;
+
+ gtk_text_buffer_get_end_iter (buf, &iter);
+
+ while ((line = *buffer++))
+ {
+ gtk_text_buffer_insert (buf, &iter, line, -1);
+ gtk_text_buffer_insert (buf, &iter, "\n", -1);
+ }
+}
+
+static void
+gitg_revision_changes_panel_init (GitgRevisionChangesPanel *self)
+{
+ self->priv = GITG_REVISION_CHANGES_PANEL_GET_PRIVATE (self);
+
+ self->priv->diff_runner = gitg_runner_new (2000);
+
+ g_signal_connect (self->priv->diff_runner,
+ "begin-loading",
+ G_CALLBACK (on_diff_begin_loading),
+ self);
+
+ g_signal_connect (self->priv->diff_runner,
+ "update",
+ G_CALLBACK (on_diff_update),
+ self);
+
+ g_signal_connect (self->priv->diff_runner,
+ "end-loading",
+ G_CALLBACK (on_diff_end_loading),
+ self);
+
+ self->priv->diff_files_runner = gitg_runner_new (2000);
+
+ g_signal_connect (self->priv->diff_files_runner,
+ "begin-loading",
+ G_CALLBACK(on_diff_files_begin_loading),
+ self);
+
+ g_signal_connect (self->priv->diff_files_runner,
+ "update",
+ G_CALLBACK(on_diff_files_update),
+ self);
+
+ g_signal_connect (self->priv->diff_files_runner,
+ "end-loading",
+ G_CALLBACK(on_diff_files_end_loading),
+ self);
+}
+
+static gboolean
+find_diff_file (GitgRevisionChangesPanel *view,
+ GitgDiffIter *iter,
+ GtkTreeIter *it,
+ DiffFile **f)
+{
+ gchar *from;
+ gchar *to;
+
+ if (!gitg_diff_iter_get_index (iter, &from, &to))
+ {
+ return FALSE;
+ }
+
+ GtkTreeModel *model = GTK_TREE_MODEL (view->priv->list_store_diff_files);
+
+ if (!gtk_tree_model_get_iter_first (model, it))
+ {
+ return FALSE;
+ }
+
+ do
+ {
+ gtk_tree_model_get (model, it, 0, f, -1);
+
+ if (match_indices (*f, from, to))
+ {
+ return TRUE;
+ }
+
+ diff_file_unref (*f);
+ } while (gtk_tree_model_iter_next (model, it));
+
+ return FALSE;
+}
+
+static void
+on_header_added (GitgDiffView *view,
+ GitgDiffIter *iter,
+ GitgRevisionChangesPanel *self)
+{
+ GtkTreeIter it;
+ DiffFile *f;
+
+ if (find_diff_file (self, iter, &it, &f))
+ {
+ if (!f->visible)
+ {
+ f->visible = TRUE;
+ f->iter = *iter;
+
+ diff_file_unref (f);
+
+ GtkTreeModel *model = GTK_TREE_MODEL (self->priv->list_store_diff_files);
+ GtkTreePath *path = gtk_tree_model_get_path (model, &it);
+
+ gtk_tree_model_row_changed (model, path, &it);
+ gtk_tree_path_free (path);
+ }
+ }
+ else
+ {
+ /* Insert in cached headers */
+ CachedHeader *header = g_slice_new (CachedHeader);
+ header->iter = *iter;
+
+ self->priv->cached_headers = g_slist_prepend (self->priv->cached_headers, header);
+ }
+}
+
+typedef struct
+{
+ gint numselected;
+ GtkTreeSelection *selection;
+} ForeachSelectionData;
+
+static gboolean
+foreach_selection_changed (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ ForeachSelectionData *data)
+{
+ gboolean visible = data->numselected == 0 ||
+ gtk_tree_selection_path_is_selected (data->selection,
+ path);
+
+ DiffFile *f = NULL;
+ gtk_tree_model_get (model, iter, 0, &f, -1);
+
+ if (f->visible)
+ {
+ gitg_diff_iter_set_visible (&f->iter, visible);
+ }
+
+ diff_file_unref (f);
+ return FALSE;
+}
+
+static void
+on_diff_files_selection_changed (GtkTreeSelection *selection,
+ GitgRevisionChangesPanel *self)
+{
+ ForeachSelectionData data = {
+ gtk_tree_selection_count_selected_rows (selection),
+ selection
+ };
+
+ gtk_tree_model_foreach (gtk_tree_view_get_model (self->priv->diff_files),
+ (GtkTreeModelForeachFunc)foreach_selection_changed,
+ &data);
+}
+
diff --git a/gitg/gitg-revision-changes-panel.h b/gitg/gitg-revision-changes-panel.h
new file mode 100644
index 0000000..0741d00
--- /dev/null
+++ b/gitg/gitg-revision-changes-panel.h
@@ -0,0 +1,34 @@
+#ifndef __GITG_REVISION_CHANGES_PANEL_H__
+#define __GITG_REVISION_CHANGES_PANEL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GITG_TYPE_REVISION_CHANGES_PANEL (gitg_revision_changes_panel_get_type ())
+#define GITG_REVISION_CHANGES_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REVISION_CHANGES_PANEL, GitgRevisionChangesPanel))
+#define GITG_REVISION_CHANGES_PANEL_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REVISION_CHANGES_PANEL, GitgRevisionChangesPanel const))
+#define GITG_REVISION_CHANGES_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_REVISION_CHANGES_PANEL, GitgRevisionChangesPanelClass))
+#define GITG_IS_REVISION_CHANGES_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_REVISION_CHANGES_PANEL))
+#define GITG_IS_REVISION_CHANGES_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_REVISION_CHANGES_PANEL))
+#define GITG_REVISION_CHANGES_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_REVISION_CHANGES_PANEL, GitgRevisionChangesPanelClass))
+
+typedef struct _GitgRevisionChangesPanel GitgRevisionChangesPanel;
+typedef struct _GitgRevisionChangesPanelClass GitgRevisionChangesPanelClass;
+typedef struct _GitgRevisionChangesPanelPrivate GitgRevisionChangesPanelPrivate;
+
+struct _GitgRevisionChangesPanel {
+ GObject parent;
+
+ GitgRevisionChangesPanelPrivate *priv;
+};
+
+struct _GitgRevisionChangesPanelClass {
+ GObjectClass parent_class;
+};
+
+GType gitg_revision_changes_panel_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GITG_REVISION_CHANGES_PANEL_H__ */
diff --git a/gitg/gitg-revision-changes.ui b/gitg/gitg-revision-changes.ui
new file mode 100644
index 0000000..bd1ec7b
--- /dev/null
+++ b/gitg/gitg-revision-changes.ui
@@ -0,0 +1,76 @@
+<?xml version="1.0"?>
+<interface>
+ <object class="GtkVBox" id="revision_changes_page">
+ <property name="visible">True</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkHPaned" id="hpaned_revision_view">
+ <property name="visible">True</property>
+ <property name="position">200</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolled_window_revision_files">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">etched-in</property>
+ <child>
+ <object class="GtkTreeView" id="tree_view_revision_files">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <child>
+ <object class="GtkTreeViewColumn" id="revision_files_column_icon">
+ <property name="sizing">fixed</property>
+ <property name="fixed_width">20</property>
+ <property name="title">Icon</property>
+ <child>
+ <object class="GtkCellRendererPixbuf" id="revision_files_cell_renderer_icon"/>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="revision_files_column_name">
+ <property name="title">Filename</property>
+ <child>
+ <object class="GtkCellRendererText" id="revision_files_cell_renderer_name"/>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="resize">False</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolled_window_details">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">etched-in</property>
+ <child>
+ <object class="GitgDiffView" id="revision_diff">
+ <property name="editable">False</property>
+ <property name="cursor_visible">False</property>
+ <property name="show_line_numbers">False</property>
+ <property name="tab_width">4</property>
+ <property name="diff_enabled">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/gitg/gitg-revision-files-view-panel.c b/gitg/gitg-revision-files-panel.c
similarity index 95%
rename from gitg/gitg-revision-files-view-panel.c
rename to gitg/gitg-revision-files-panel.c
index 1ccd5ea..2afa08b 100644
--- a/gitg/gitg-revision-files-view-panel.c
+++ b/gitg/gitg-revision-files-panel.c
@@ -1,5 +1,5 @@
/*
- * gitg-revision-tree-view.c
+ * gitg-revision-files-panel.c
* This file is part of gitg - git repository viewer
*
* Copyright (C) 2009 - Jesse van den Kieboom
@@ -29,14 +29,14 @@
#include <libgitg/gitg-revision.h>
#include <libgitg/gitg-runner.h>
-#include "gitg-revision-files-view-panel.h"
+#include "gitg-revision-files-panel.h"
#include "gitg-utils.h"
#include "gitg-revision-panel.h"
#include "gitg-dirs.h"
#define GITG_REVISION_FILES_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_REVISION_FILES_VIEW, GitgRevisionFilesViewPrivate))
-#define GITG_REVISION_FILES_VIEW_PANEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_REVISION_FILES_VIEW_PANEL, GitgRevisionFilesViewPanelPrivate))
+#define GITG_REVISION_FILES_PANEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_REVISION_FILES_PANEL, GitgRevisionFilesPanelPrivate))
enum
{
@@ -80,7 +80,7 @@ struct _GitgRevisionFilesViewClass
GtkHPanedClass parent_class;
};
-struct _GitgRevisionFilesViewPanelPrivate
+struct _GitgRevisionFilesPanelPrivate
{
GitgRevisionFilesView *panel;
};
@@ -94,8 +94,8 @@ static void gitg_revision_panel_iface_init (GitgRevisionPanelInterface *iface);
static void load_node (GitgRevisionFilesView *view, GtkTreeIter *parent);
static gchar *node_identity (GitgRevisionFilesView *view, GtkTreeIter *iter);
-G_DEFINE_TYPE_EXTENDED (GitgRevisionFilesViewPanel,
- gitg_revision_files_view_panel,
+G_DEFINE_TYPE_EXTENDED (GitgRevisionFilesPanel,
+ gitg_revision_files_panel,
G_TYPE_OBJECT,
0,
G_IMPLEMENT_INTERFACE (GITG_TYPE_REVISION_PANEL,
@@ -144,6 +144,12 @@ set_revision (GitgRevisionFilesView *files_view,
GitgRepository *repository,
GitgRevision *revision)
{
+ if (files_view->priv->repository == repository &&
+ files_view->priv->revision == revision)
+ {
+ return;
+ }
+
gitg_runner_cancel (files_view->priv->loader);
gtk_tree_store_clear (files_view->priv->store);
@@ -179,7 +185,6 @@ set_revision (GitgRevisionFilesView *files_view,
{
load_tree (files_view);
}
-
}
static void
@@ -576,9 +581,9 @@ gitg_revision_panel_update_impl (GitgRevisionPanel *panel,
GitgRepository *repository,
GitgRevision *revision)
{
- GitgRevisionFilesViewPanel *files_view_panel;
+ GitgRevisionFilesPanel *files_view_panel;
- files_view_panel = GITG_REVISION_FILES_VIEW_PANEL (panel);
+ files_view_panel = GITG_REVISION_FILES_PANEL (panel);
set_revision (files_view_panel->priv->panel, repository, revision);
}
@@ -594,9 +599,9 @@ gitg_revision_panel_get_panel_impl (GitgRevisionPanel *panel)
{
GtkBuilder *builder;
GtkWidget *ret;
- GitgRevisionFilesViewPanel *files_view_panel;
+ GitgRevisionFilesPanel *files_view_panel;
- files_view_panel = GITG_REVISION_FILES_VIEW_PANEL (panel);
+ files_view_panel = GITG_REVISION_FILES_PANEL (panel);
if (files_view_panel->priv->panel)
{
@@ -640,11 +645,11 @@ gitg_revision_files_view_class_init (GitgRevisionFilesViewClass *klass)
}
static void
-gitg_revision_files_view_panel_dispose (GObject *object)
+gitg_revision_files_panel_dispose (GObject *object)
{
- GitgRevisionFilesViewPanel *panel;
+ GitgRevisionFilesPanel *panel;
- panel = GITG_REVISION_FILES_VIEW_PANEL (object);
+ panel = GITG_REVISION_FILES_PANEL (object);
if (panel->priv->panel)
{
@@ -652,17 +657,17 @@ gitg_revision_files_view_panel_dispose (GObject *object)
panel->priv->panel = NULL;
}
- G_OBJECT_CLASS (gitg_revision_files_view_panel_parent_class)->dispose (object);
+ G_OBJECT_CLASS (gitg_revision_files_panel_parent_class)->dispose (object);
}
static void
-gitg_revision_files_view_panel_class_init (GitgRevisionFilesViewPanelClass *klass)
+gitg_revision_files_panel_class_init (GitgRevisionFilesPanelClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = gitg_revision_files_view_panel_dispose;
+ object_class->dispose = gitg_revision_files_panel_dispose;
- g_type_class_add_private (object_class, sizeof (GitgRevisionFilesViewPanelPrivate));
+ g_type_class_add_private (object_class, sizeof (GitgRevisionFilesPanelPrivate));
}
static gchar *
@@ -980,9 +985,9 @@ gitg_revision_files_view_init (GitgRevisionFilesView *self)
}
static void
-gitg_revision_files_view_panel_init (GitgRevisionFilesViewPanel *self)
+gitg_revision_files_panel_init (GitgRevisionFilesPanel *self)
{
- self->priv = GITG_REVISION_FILES_VIEW_PANEL_GET_PRIVATE (self);
+ self->priv = GITG_REVISION_FILES_PANEL_GET_PRIVATE (self);
}
static gchar *
diff --git a/gitg/gitg-revision-files-panel.h b/gitg/gitg-revision-files-panel.h
new file mode 100644
index 0000000..220aa21
--- /dev/null
+++ b/gitg/gitg-revision-files-panel.h
@@ -0,0 +1,61 @@
+/*
+ * gitg-revision-files-panel.h
+ * This file is part of gitg - git repository view_paneler
+ *
+ * Copyright (C) 2009 - Jesse van den Kieboom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GITG_REVISION_FILES_PANEL__H__
+#define __GITG_REVISION_FILES_PANEL__H__
+
+#include <gtk/gtk.h>
+#include <libgitg/gitg-repository.h>
+#include <libgitg/gitg-revision.h>
+
+G_BEGIN_DECLS
+
+#define GITG_TYPE_REVISION_FILES_PANEL (gitg_revision_files_panel_get_type ())
+#define GITG_REVISION_FILES_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REVISION_FILES_PANEL, GitgRevisionFilesPanel))
+#define GITG_REVISION_FILES_PANEL_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REVISION_FILES_PANEL, GitgRevisionFilesPanel const))
+#define GITG_REVISION_FILES_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_REVISION_FILES_PANEL, GitgRevisionFilesPanelClass))
+#define GITG_IS_REVISION_FILES_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_REVISION_FILES_PANEL))
+#define GITG_IS_REVISION_FILES_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_REVISION_FILES_PANEL))
+#define GITG_REVISION_FILES_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_REVISION_FILES_PANEL, GitgRevisionFilesViewPanelClass))
+
+typedef struct _GitgRevisionFilesPanel GitgRevisionFilesPanel;
+typedef struct _GitgRevisionFilesPanelClass GitgRevisionFilesPanelClass;
+typedef struct _GitgRevisionFilesPanelPrivate GitgRevisionFilesPanelPrivate;
+
+struct _GitgRevisionFilesPanel
+{
+ GObject parent;
+
+ GitgRevisionFilesPanelPrivate *priv;
+};
+
+struct _GitgRevisionFilesPanelClass
+{
+ GObjectClass parent_class;
+};
+
+GType gitg_revision_files_panel_get_type (void) G_GNUC_CONST;
+GType gitg_revision_files_view_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GITG_REVISION_FILES_PANEL__H__ */
diff --git a/gitg/gitg-window.c b/gitg/gitg-window.c
index e201059..8064c42 100644
--- a/gitg/gitg-window.c
+++ b/gitg/gitg-window.c
@@ -44,7 +44,8 @@
#include "gitg-preferences.h"
#include "gitg-utils.h"
#include "gitg-revision-panel.h"
-#include "gitg-revision-files-view-panel.h"
+#include "gitg-revision-changes-panel.h"
+#include "gitg-revision-files-panel.h"
#define DYNAMIC_ACTION_DATA_KEY "GitgDynamicActionDataKey"
#define DYNAMIC_ACTION_DATA_REMOTE_KEY "GitgDynamicActionDataRemoteKey"
@@ -948,7 +949,8 @@ gitg_window_parser_finished (GtkBuildable *buildable,
gtk_builder_connect_signals (builder, window);
// Initialize revision panels
- add_revision_panel (window, GITG_TYPE_REVISION_FILES_VIEW_PANEL);
+ add_revision_panel (window, GITG_TYPE_REVISION_CHANGES_PANEL);
+ add_revision_panel (window, GITG_TYPE_REVISION_FILES_PANEL);
// Connect signals
GtkTreeSelection *selection = gtk_tree_view_get_selection (window->priv->tree_view);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]