commit 4efc16efe626ee0a7d0b5b4620d6614f0ce88a7a
Author: Sebastien Ponce <sebastien.ponce_wine@m4x.org>
Date:   Thu May 26 13:47:58 2011 +0200

    implemented different ways to look at diffs : by hunks, by file or all at once

diff --git a/src/giggle-diff-view.c b/src/giggle-diff-view.c
index 469115e..38239e9 100644
--- a/src/giggle-diff-view.c
+++ b/src/giggle-diff-view.c
@@ -42,6 +42,7 @@ struct GiggleDiffViewPriv {
 	gchar       *search_term;
 
 	int          current_hunk;
+	int          current_style;
 	GArray      *files, *hunks;
 	GtkTextTag  *invalid_char;
 
@@ -71,10 +72,34 @@ G_DEFINE_TYPE_WITH_CODE (GiggleDiffView, giggle_diff_view, GTK_SOURCE_TYPE_VIEW,
 enum {
 	PROP_0,
 	PROP_CURRENT_FILE,
+	PROP_N_FILES,
 	PROP_CURRENT_HUNK,
 	PROP_N_HUNKS,
+	PROP_CURRENT_STYLE,
 };
 
+#define GIGGLE_DIFF_STYLE_TYPE (giggle_diff_style_type ())
+static GType
+giggle_diff_style_type (void)
+{
+  static GType diff_style_type = 0;
+
+  if (!diff_style_type) {
+    static GEnumValue style_types[] = {
+      { STYLE_CHUNK, "Chunk by chunk", "chunk" },
+      { STYLE_FILE,  "File by file",   "file"  },
+      { STYLE_ALL,   "All in one",     "all" },
+      { 0, NULL, NULL },
+    };
+
+    diff_style_type =
+	g_enum_register_static ("giggle_diff_style",
+				style_types);
+  }
+
+  return diff_style_type;
+}
+
 inline static GiggleDiffViewFile *
 diff_view_get_file (GiggleDiffViewPriv *priv,
 		    unsigned            i)
@@ -153,6 +178,10 @@ diff_view_get_property (GObject    *object,
 		g_value_set_string (value, giggle_diff_view_get_current_file (view));
 		break;
 
+	case PROP_N_FILES:
+		g_value_set_int (value, priv->files->len);
+		break;
+
 	case PROP_CURRENT_HUNK:
 		g_value_set_int (value, priv->current_hunk);
 		break;
@@ -161,6 +190,10 @@ diff_view_get_property (GObject    *object,
 		g_value_set_int (value, priv->hunks->len);
 		break;
 
+	case PROP_CURRENT_STYLE:
+		g_value_set_int (value, priv->current_style);
+		break;
+
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
 		break;
@@ -224,46 +257,97 @@ diff_view_set_current_hunk (GiggleDiffView *view,
 	int                 hunk_offset;
 	GiggleDiffViewHunk *hunk = NULL;
 	GiggleDiffViewFile *file = NULL;
+	GiggleDiffViewFile *curfile = NULL;
 	GtkTextBuffer      *buffer;
 	GtkTextIter         iter;
+	GtkTextMark        *curhunk_mark = NULL;
+	gboolean            firsthunk = TRUE;
 
 	g_return_if_fail (hunk_index >= -1);
 	g_return_if_fail (hunk_index < (int) priv->hunks->len);
 
+	// get current file
 	priv->current_hunk = hunk_index;
+	if (hunk_index < 0) return;
+	hunk = diff_view_get_hunk (priv, priv->current_hunk);
+	if (hunk)
+		curfile = diff_view_get_file (priv, hunk->file);
 
-	hunk = diff_view_get_hunk (priv, hunk_index);
-
-	if (hunk && hunk_index >= 0)
-		file = diff_view_get_file (priv, hunk->file);
+	// get first hunk to be displayed
+	if (priv->current_style == STYLE_FILE)
+		for (hunk_index = 0; (guint) hunk_index < priv->hunks->len; ++hunk_index) {
+			hunk = diff_view_get_hunk (priv, hunk_index);
+			file = diff_view_get_file (priv, hunk->file);
+			if (file == curfile)
+				break;
+		}
+	if (priv->current_style == STYLE_ALL)
+		hunk_index = 0;
 
 	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
 	gtk_text_buffer_set_text (buffer, "", 0);
 
-	if (file) {
-		gtk_text_buffer_get_end_iter (buffer, &iter);
-		diff_view_insert_text (view, &iter, file->header, -1);
-
-		hunk_offset = gtk_text_iter_get_offset (&iter);
-		diff_view_insert_text (view, &iter, hunk->text, -1);
+	while (hunk_index < (int)priv->hunks->len) {
+		hunk = diff_view_get_hunk (priv, hunk_index);
 
-		if (hunk->errors) {
-			for (i = 0; i < hunk->errors->len; i += 2) {
-				int first = g_array_index (hunk->errors, int, i);
-				int last = g_array_index (hunk->errors, int, i + 1);
-
-				GtkTextIter start = iter, end = iter;
+		if (hunk)
+			file = diff_view_get_file (priv, hunk->file);
 
-				gtk_text_iter_set_offset (&start, first + hunk_offset);
-				gtk_text_iter_set_offset (&end, last + hunk_offset);
+		if (priv->current_style == STYLE_FILE)
+			if (curfile != file)
+				break;
 
-				gtk_text_buffer_apply_tag (buffer, priv->invalid_char, &start, &end);
+		if (file) {
+			
+			if (!firsthunk)
+				gtk_text_buffer_insert_at_cursor(buffer, "\n", 1);
+			gtk_text_buffer_get_end_iter (buffer, &iter);
+			if (hunk_index == priv->current_hunk)
+				curhunk_mark = gtk_text_buffer_create_mark (buffer, NULL,
+									    &iter, TRUE);
+
+			if ((curfile != file) || firsthunk)
+				diff_view_insert_text (view, &iter, file->header, -1);
+			firsthunk = FALSE;
+
+			hunk_offset = gtk_text_iter_get_offset (&iter);
+			diff_view_insert_text (view, &iter, hunk->text, -1);
+			
+			if (hunk->errors) {
+				for (i = 0; i < hunk->errors->len; i += 2) {
+					int first = g_array_index (hunk->errors, int, i);
+					int last = g_array_index (hunk->errors, int, i + 1);
+
+					GtkTextIter start = iter, end = iter;
+
+					gtk_text_iter_set_offset (&start, first + hunk_offset);
+					gtk_text_iter_set_offset (&end, last + hunk_offset);
+
+					gtk_text_buffer_apply_tag (buffer, priv->invalid_char, &start, &end);
+				}
 			}
 		}
+		if (priv->current_style == STYLE_CHUNK) break;
+		hunk_index++;
+	}
+	if (curhunk_mark) {
+		gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
+					      curhunk_mark, 0.0, TRUE, 0.0, 0.0);
+		gtk_text_buffer_delete_mark (buffer, curhunk_mark);
 	}
 }
 
 static void
+diff_view_set_current_style (GiggleDiffView *view,
+			     gint            style)
+{
+	GiggleDiffViewPriv *priv = GET_PRIV (view);
+
+	priv->current_style = style;
+	diff_view_set_current_hunk(view, priv->current_hunk);
+}
+
+static void
 diff_view_set_property (GObject      *object,
 			guint         param_id,
 			const GValue *value,
@@ -275,6 +359,11 @@ diff_view_set_property (GObject      *object,
 					    g_value_get_int (value));
 		break;
 
+	case PROP_CURRENT_STYLE:
+		diff_view_set_current_style (GIGGLE_DIFF_VIEW (object),
+					     g_value_get_enum (value));
+		break;
+
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
 		break;
@@ -352,6 +441,15 @@ giggle_diff_view_class_init (GiggleDiffViewClass *class)
 				  0, G_MAXINT, 0,
 				  G_PARAM_READABLE));
 
+	g_object_class_install_property (
+		object_class,
+		PROP_CURRENT_STYLE,
+		g_param_spec_enum ("current-style",
+				   "Current Style",
+				   "Current style of the diff display",
+				   GIGGLE_DIFF_STYLE_TYPE, STYLE_CHUNK,
+				   G_PARAM_READWRITE));
+
 	g_type_class_add_private (object_class, sizeof (GiggleDiffViewPriv));
 }
 
@@ -442,6 +540,7 @@ giggle_diff_view_init (GiggleDiffView *diff_view)
 	priv->files = g_array_new (FALSE, TRUE, sizeof (GiggleDiffViewFile));
 	priv->hunks = g_array_new (FALSE, TRUE, sizeof (GiggleDiffViewHunk));
 	priv->current_hunk = -1;
+	priv->current_style = STYLE_CHUNK;
 
 	gtk_text_view_set_editable (GTK_TEXT_VIEW (diff_view), FALSE);
 	gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (diff_view), FALSE);
@@ -735,8 +834,8 @@ giggle_diff_view_scroll_to_file (GiggleDiffView *diff_view,
 	GiggleDiffViewPriv *priv;
 	GiggleDiffViewHunk *hunk;
 	GiggleDiffViewFile *file;
-	GtkTextMark        *mark;
-	gint                i;
+        GtkTextMark        *mark;
+ 	gint                i;
 
 	g_return_if_fail (GIGGLE_IS_DIFF_VIEW (diff_view));
 	g_return_if_fail (NULL != filename);
@@ -747,7 +846,7 @@ giggle_diff_view_scroll_to_file (GiggleDiffView *diff_view,
 		mark = gtk_text_buffer_get_mark
 			(gtk_text_view_get_buffer (GTK_TEXT_VIEW (diff_view)),
 			 filename);
-
+ 
 		if (mark) {
 			gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (diff_view),
 						      mark, 0.0, TRUE, 0.0, 0.0);
@@ -757,34 +856,63 @@ giggle_diff_view_scroll_to_file (GiggleDiffView *diff_view,
 			hunk = diff_view_get_hunk (priv, i);
 			file = diff_view_get_file (priv, hunk->file);
 
-			if (!strcmp (file->filename, filename)) {
-				if (i != priv->current_hunk)
-					giggle_diff_view_set_current_hunk (diff_view, i);
+                       if (!strcmp (file->filename, filename)) {
+			       giggle_diff_view_set_current_hunk (diff_view, i);
 
-				break;
-			}
+                               break;
+                       }
 		}
 	}
 }
 
+int
+giggle_diff_view_get_current_file_nb (GiggleDiffView *diff_view)
+{
+       GiggleDiffViewPriv *priv;
+       GiggleDiffViewHunk *hunk = NULL;
+ 
+       g_return_val_if_fail (GIGGLE_IS_DIFF_VIEW (diff_view), 0);
+
+       priv = GET_PRIV (diff_view);
+
+       if (priv->current_hunk >= 0)
+	       hunk = diff_view_get_hunk (priv, priv->current_hunk);
+       if (hunk)
+               return hunk->file;
+
+       return 0;
+}
+
 const char *
 giggle_diff_view_get_current_file (GiggleDiffView *diff_view)
 {
-	GiggleDiffViewPriv *priv;
-	GiggleDiffViewHunk *hunk = NULL;
-	GiggleDiffViewFile *file = NULL;
+       GiggleDiffViewPriv *priv;
+       GiggleDiffViewFile *file = NULL;
+       int file_nb;
 
-	g_return_val_if_fail (GIGGLE_IS_DIFF_VIEW (diff_view), NULL);
+       g_return_val_if_fail (GIGGLE_IS_DIFF_VIEW (diff_view), NULL);
 
-	priv = GET_PRIV (diff_view);
+       priv = GET_PRIV (diff_view);
 
-	if (priv->current_hunk >= 0)
-		hunk = diff_view_get_hunk (priv, priv->current_hunk);
-	if (hunk)
-		file = diff_view_get_file (priv, hunk->file);
-	if (file)
-		return file->filename;
+       file_nb = giggle_diff_view_get_current_file_nb(diff_view);
+       file = diff_view_get_file (priv, file_nb);
+       if (file)
+               return file->filename;
+ 
+       return NULL;
+}
 
-	return NULL;
+void
+giggle_diff_view_set_current_style (GiggleDiffView *diff_view,
+				    int             style)
+{
+	g_return_if_fail (GIGGLE_IS_DIFF_VIEW (diff_view));
+	g_object_set (diff_view, "current-style", style, NULL);
 }
 
+int
+giggle_diff_view_get_current_style (GiggleDiffView *diff_view)
+{
+	g_return_val_if_fail (GIGGLE_IS_DIFF_VIEW (diff_view), -1);
+	return GET_PRIV (diff_view)->current_style;
+}
diff --git a/src/giggle-diff-view.h b/src/giggle-diff-view.h
index 6b9f3b7..6eb8381 100644
--- a/src/giggle-diff-view.h
+++ b/src/giggle-diff-view.h
@@ -37,6 +37,12 @@ G_BEGIN_DECLS
 #define GIGGLE_IS_DIFF_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIGGLE_TYPE_DIFF_VIEW))
 #define GIGGLE_DIFF_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIGGLE_TYPE_DIFF_VIEW, GiggleDiffViewClass))
 
+enum {
+	STYLE_CHUNK,
+	STYLE_FILE,
+	STYLE_ALL,
+} giggle_diff_style;
+
 typedef struct GiggleDiffView      GiggleDiffView;
 typedef struct GiggleDiffViewClass GiggleDiffViewClass;
 
@@ -57,11 +63,14 @@ void               giggle_diff_view_set_revisions     (GiggleDiffView *diff_view
 						       GList          *files);
 void               giggle_diff_view_diff_current      (GiggleDiffView *diff_view,
 						       GList          *files);
-
 void               giggle_diff_view_set_current_hunk  (GiggleDiffView *diff_view,
 						       int             hunk_index);
+void               giggle_diff_view_set_current_style (GiggleDiffView *diff_view,
+						       gint            style);
 int                giggle_diff_view_get_current_hunk  (GiggleDiffView *diff_view);
 
+int                giggle_diff_view_get_current_style (GiggleDiffView *diff_view);
+
 int                giggle_diff_view_get_n_hunks       (GiggleDiffView *diff_view);
 
 void               giggle_diff_view_scroll_to_file    (GiggleDiffView *diff_view,
@@ -69,6 +78,8 @@ void               giggle_diff_view_scroll_to_file    (GiggleDiffView *diff_view
 
 const char *       giggle_diff_view_get_current_file  (GiggleDiffView *diff_view);
 
+int                giggle_diff_view_get_current_file_nb (GiggleDiffView *diff_view);
+
 G_END_DECLS
 
 #endif /* __GIGGLE_DIFF_VIEW_H__ */
diff --git a/src/giggle-view-diff.c b/src/giggle-view-diff.c
index 1d2d22a..749ef0d 100644
--- a/src/giggle-view-diff.c
+++ b/src/giggle-view-diff.c
@@ -85,7 +85,7 @@ view_diff_update_status (GiggleViewDiff *view)
 	GiggleViewDiffPriv *priv;
 	GtkAction	   *action;
 	char		   *format, *markup;
-	int		    current_hunk, n_hunks;
+	int		    current_hunk, n_hunks, current_style;
 	char		   *current_file;
 
 	priv = GET_PRIV (view);
@@ -93,7 +93,9 @@ view_diff_update_status (GiggleViewDiff *view)
 	g_object_get (priv->diff_view,
 		      "current-file", &current_file,
 		      "current-hunk", &current_hunk,
-		      "n-hunks", &n_hunks, NULL);
+		      "n-hunks", &n_hunks,
+		      "current-style", &current_style,
+		      NULL);
 
 	if (priv->action_group) {
 		gtk_action_group_set_sensitive (priv->action_group, n_hunks > 0);
@@ -377,3 +379,17 @@ giggle_view_diff_set_revisions (GiggleViewDiff *view,
 	view_diff_update_status (view);
 }
 
+void
+giggle_view_diff_set_style (GiggleViewDiff *view,
+			    gint style)
+{
+	GiggleViewDiffPriv *priv;
+
+	g_return_if_fail (GIGGLE_IS_VIEW_DIFF (view));
+
+	priv = GET_PRIV (view);
+
+	giggle_diff_view_set_current_style (GIGGLE_DIFF_VIEW (priv->diff_view), style);
+
+	view_diff_update_status (view);
+}
diff --git a/src/giggle-view-diff.h b/src/giggle-view-diff.h
index 16fc7bb..7c1df17 100644
--- a/src/giggle-view-diff.h
+++ b/src/giggle-view-diff.h
@@ -52,6 +52,9 @@ void		   giggle_view_diff_set_revisions     (GiggleViewDiff *view,
 						       GiggleRevision *revision2,
 						       GList          *files);
 
+void		   giggle_view_diff_set_style         (GiggleViewDiff *view,
+						       gint style);
+
 G_END_DECLS
 
 #endif /* __GIGGLE_VIEW_DIFF_H__ */
diff --git a/src/giggle-view-history.c b/src/giggle-view-history.c
index 3a174a1..317a44a 100644
--- a/src/giggle-view-history.c
+++ b/src/giggle-view-history.c
@@ -875,6 +875,20 @@ giggle_view_history_set_graph_visible (GiggleViewHistory *view,
 		GIGGLE_REV_LIST_VIEW (priv->revision_list), visible);
 }
 
+void
+giggle_view_history_set_view_style (GiggleViewHistory *view,
+				    gint              style)
+{
+	GiggleViewHistoryPriv *priv;
+
+	g_return_if_fail (GIGGLE_IS_VIEW_HISTORY (view));
+
+	priv = view->priv;
+
+	giggle_view_diff_set_style (
+		GIGGLE_VIEW_DIFF (priv->view_diff), style);
+}
+
 gboolean
 giggle_view_history_select (GiggleViewHistory *view,
 			    GiggleRevision    *revision)
diff --git a/src/giggle-view-history.h b/src/giggle-view-history.h
index 67a0b69..54857dd 100644
--- a/src/giggle-view-history.h
+++ b/src/giggle-view-history.h
@@ -53,6 +53,9 @@ GtkWidget *        giggle_view_history_new               (GtkUIManager      *man
 void               giggle_view_history_set_graph_visible (GiggleViewHistory *view,
 							  gboolean           visible);
 
+void               giggle_view_history_set_view_style (GiggleViewHistory *view,
+						       gint           style);
+
 gboolean           giggle_view_history_select            (GiggleViewHistory *view,
 							  GiggleRevision    *revision);
 
diff --git a/src/giggle-window.c b/src/giggle-window.c
index 62627f0..55f6396 100644
--- a/src/giggle-window.c
+++ b/src/giggle-window.c
@@ -854,6 +854,20 @@ window_action_view_graph_cb (GtkAction    *action,
 }
 
 static void
+window_action_view_diff_cb (GtkRadioAction *action,
+			    GtkRadioAction *current,
+			    GiggleWindow *window)
+{
+	GiggleWindowPriv *priv;
+	gint             current_value;
+
+	priv = window->priv;
+
+	current_value = gtk_radio_action_get_current_value (current);
+	giggle_view_history_set_view_style (GIGGLE_VIEW_HISTORY (priv->history_view), current_value);
+}
+
+static void
 window_action_refresh_history (GtkAction    *action,
 			       GiggleWindow *window)
 {
@@ -1097,6 +1111,18 @@ window_create_ui_manager (GiggleWindow *window)
 		},
 	};
 
+	static const GtkRadioActionEntry radio_action_entries[] = {
+		{ "ShowDiffChunk", NULL,
+		  N_("Show diffs by chunk"), NULL, NULL, 0
+		},
+		{ "ShowDiffFile", NULL,
+		  N_("Show diffs by file"), NULL, NULL, 1
+		},
+		{ "ShowDiffAll", NULL,
+		  N_("Show all diffs"), NULL, NULL, 2
+		},
+	};
+
 	static const GtkActionEntry project_action_entries[] = {
 		{ "Properties", GTK_STOCK_PROPERTIES, NULL,
 		  "<alt>Return", N_("Show and edit project properties"),
@@ -1143,6 +1169,10 @@ window_create_ui_manager (GiggleWindow *window)
 		"      <placeholder name='ViewShell'/>"
 		"      <separator/>"
 		"      <menuitem action='ShowGraph'/>"
+		"      <separator/>"
+		"      <menuitem action='ShowDiffChunk'/>"
+		"      <menuitem action='ShowDiffFile'/>"
+		"      <menuitem action='ShowDiffAll'/>"
 		"      <placeholder name='ViewMenuPreferences'/>"
 		"      <separator/>"
 		"      <menuitem action='RefreshHistory'/>"
@@ -1205,6 +1235,10 @@ window_create_ui_manager (GiggleWindow *window)
 					     G_N_ELEMENTS (toggle_action_entries),
 					     window);
 
+	gtk_action_group_add_radio_actions (action_group, radio_action_entries,
+					    G_N_ELEMENTS (radio_action_entries),
+					    0, G_CALLBACK (window_action_view_diff_cb),
+					    window);
 	gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, 0);
 	g_object_unref (action_group);
 
