[Commits] [SCM] claws branch, master, updated. 3.9.3-217-g0dbb415

colin at claws-mail.org colin at claws-mail.org
Thu May 22 21:10:06 CEST 2014


The branch master of project "claws" (Claws Mail) has been updated
       via  0dbb415b36c512aa23ef1eb71d48cb7d78c72be5 (commit)
      from  eba3ff6f6f06cf91fe0016a706073696d3839531 (commit)


- Log -----------------------------------------------------------------
commit 0dbb415b36c512aa23ef1eb71d48cb7d78c72be5
Author: Colin Leroy <colin at colino.net>
Date:   Thu May 22 20:57:01 2014 +0200

    Fix Undo after wrapping a paragraph, which undid every line wrap one by one, and make it atomic.

diff --git a/src/compose.c b/src/compose.c
index 55c34ed..5da0cc0 100644
--- a/src/compose.c
+++ b/src/compose.c
@@ -4695,9 +4695,14 @@ static void compose_wrap_all_full(Compose *compose, gboolean force)
 	buffer = gtk_text_view_get_buffer(text);
 
 	gtk_text_buffer_get_start_iter(buffer, &iter);
+
+	undo_wrapping(compose->undostruct, TRUE);
+
 	while (!gtk_text_iter_is_end(&iter) && modified)
 		modified = compose_beautify_paragraph(compose, &iter, force);
 
+	undo_wrapping(compose->undostruct, FALSE);
+
 }
 
 static void compose_set_title(Compose *compose)
diff --git a/src/undo.c b/src/undo.c
index 0111733..ec24e6f 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -46,6 +46,15 @@ struct _UndoInfo
 	gint mergeable;
 };
 
+struct _UndoWrap
+{
+	gint lock;
+	gchar *pre_wrap_content;
+	gint start_pos;
+	gint end_pos;
+	gint len_change;
+};
+
 static void undo_free_list	(GList	       **list_pointer);
 static void undo_check_size	(UndoMain	*undostruct);
 static gint undo_merge		(GList		*list,
@@ -526,10 +535,147 @@ void undo_unblock(UndoMain *undostruct)
 					  undostruct);
 }
 
+/* Init the WrapInfo structure */
+static void init_wrap_undo(UndoMain *undostruct)
+{
+	GtkTextBuffer *buffer;
+	GtkTextIter start, end;
+
+	cm_return_if_fail(undostruct != NULL);
+	cm_return_if_fail(undostruct->wrap_info == NULL);
+
+	undostruct->wrap_info = g_new0(UndoWrap, 1);
+
+	/* Save the whole buffer as original contents. We'll retain the
+	 * changed region when exiting wrap mode.
+	 */
+	buffer = gtk_text_view_get_buffer(undostruct->textview);
+	gtk_text_buffer_get_start_iter(buffer, &start);
+	gtk_text_buffer_get_end_iter(buffer, &end);
+	undostruct->wrap_info->pre_wrap_content
+		= gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
+
+	undostruct->wrap_info->lock = 0;
+
+	/* start_pos == -1 means nothing changed yet. */
+	undostruct->wrap_info->start_pos = -1;
+	undostruct->wrap_info->end_pos = -1;
+	undostruct->wrap_info->len_change = 0;
+}
+
+static void end_wrap_undo(UndoMain *undostruct)
+{
+	GtkTextBuffer *buffer;
+	GtkTextIter start, end;
+	gchar *old_contents = NULL;
+	gchar *cur_contents = NULL;
+	gchar *new_contents = NULL;
+
+	cm_return_if_fail(undostruct != NULL);
+	cm_return_if_fail(undostruct->wrap_info != NULL);
+
+	/* If start_pos is still == -1, it means nothing changed. */
+	if (undostruct->wrap_info->start_pos == -1)
+		goto cleanup;
+
+	/* get the whole new (wrapped) contents */
+	buffer = gtk_text_view_get_buffer(undostruct->textview);
+	gtk_text_buffer_get_start_iter(buffer, &start);
+	gtk_text_buffer_get_end_iter(buffer, &end);
+	cur_contents = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
+
+	debug_print("wrapping done from %d to %d, len change: %d\n",
+		undostruct->wrap_info->start_pos,
+		undostruct->wrap_info->end_pos,
+		undostruct->wrap_info->len_change);
+
+	/* keep the relevant old unwrapped part, which is what
+	 * was between start_pos & end_pos - len_change
+	 */
+	old_contents = g_utf8_substring(
+			undostruct->wrap_info->pre_wrap_content,
+			undostruct->wrap_info->start_pos,
+			undostruct->wrap_info->end_pos
+			- undostruct->wrap_info->len_change);
+
+	/* and get the changed contents, from start_pos to end_pos. */
+	new_contents = g_utf8_substring(
+			cur_contents,
+			undostruct->wrap_info->start_pos,
+			undostruct->wrap_info->end_pos);
+
+	/* add the deleted (unwrapped) text to the undo pile */
+	undo_add(old_contents,
+		 undostruct->wrap_info->start_pos,
+		 undostruct->wrap_info->end_pos
+		  - undostruct->wrap_info->len_change,
+		 UNDO_ACTION_REPLACE_DELETE,
+		 undostruct);
+
+	/* add the inserted (wrapped) text to the undo pile */
+	undo_add(new_contents,
+		 undostruct->wrap_info->start_pos,
+		 undostruct->wrap_info->end_pos,
+		 UNDO_ACTION_REPLACE_INSERT,
+		 undostruct);
+
+	g_free(old_contents);
+	g_free(cur_contents);
+	g_free(new_contents);
+cleanup:
+	g_free(undostruct->wrap_info->pre_wrap_content);
+	g_free(undostruct->wrap_info);
+	undostruct->wrap_info = NULL;
+}
+
+static void update_wrap_undo(UndoMain *undostruct, const gchar *text, int start, 
+			     int end, UndoAction action)
+{
+	gint len = end - start;
+
+	/* If we don't yet have a start position, or farther than
+	 * current, store it.
+	 */
+	if (undostruct->wrap_info->start_pos == -1
+	 || start < undostruct->wrap_info->start_pos) {
+		undostruct->wrap_info->start_pos = start;
+	}
+
+	if (action == UNDO_ACTION_INSERT) {
+		/* If inserting, the end of the region is at the end of the
+		 * change, and the total length of the changed region
+		 * increases.
+		 */
+		undostruct->wrap_info->end_pos = end;
+		undostruct->wrap_info->len_change += len;
+	} else if (action == UNDO_ACTION_DELETE) {
+		/* If deleting, the end of the region is at the start of the
+		 * change, and the total length of the changed region
+		 * decreases.
+		 */
+		undostruct->wrap_info->end_pos = start;
+		undostruct->wrap_info->len_change -= len;
+	}
+}
+
+/* Set wrapping mode, in which changes are agglomerated until
+ * the end of wrapping mode.
+ */
 void undo_wrapping(UndoMain *undostruct, gboolean wrap)
 {
-//	debug_print("undo wrapping now %d\n", wrap);
-	undostruct->wrap = wrap;
+	if (wrap) {
+		/* Start (or go deeper in) wrapping mode */
+		if (undostruct->wrap_info == NULL)
+			init_wrap_undo(undostruct);
+		undostruct->wrap_info->lock++;
+	} else if (undostruct->wrap_info != NULL) {
+		/* exit (& possible stop) one level of wrapping mode */
+		undostruct->wrap_info->lock--;
+		if (undostruct->wrap_info->lock == 0)
+			end_wrap_undo(undostruct);
+	} else {
+		g_warning("undo already out of wrap mode");
+	}
 }
 
 void undo_insert_text_cb(GtkTextBuffer *textbuf, GtkTextIter *iter,
@@ -538,29 +684,22 @@ void undo_insert_text_cb(GtkTextBuffer *textbuf, GtkTextIter *iter,
 {
 	gchar *text_to_insert;
 	gint pos;
+	glong utf8_len;
+
 	if (prefs_common.undolevels <= 0) return;
 
 	pos = gtk_text_iter_get_offset(iter);
-	if (undostruct->wrap && undostruct->undo) {
-		UndoInfo *last_undo = undostruct->undo->data;
-		if (last_undo && (last_undo->action == UNDO_ACTION_INSERT
-				  || last_undo->action == UNDO_ACTION_REPLACE_INSERT)
-		&&  last_undo->start_pos < pos && last_undo->end_pos > pos) {
-			GtkTextIter start,end;
-			last_undo->end_pos += g_utf8_strlen(new_text, -1);
-			gtk_text_buffer_get_iter_at_offset(textbuf, &start, last_undo->start_pos);
-			gtk_text_buffer_get_iter_at_offset(textbuf, &end, last_undo->end_pos);
-			g_free(last_undo->text);
-			last_undo->text = gtk_text_buffer_get_text(textbuf, &start, &end, FALSE);
-			debug_print("add:undo upd %d-%d\n", last_undo->start_pos, last_undo->end_pos);
-			return;
-		} else if (last_undo)
-			debug_print("add:last: %d, %d-%d (%d)\n", last_undo->action,
-				last_undo->start_pos, last_undo->end_pos, pos);
-	} 
 	Xstrndup_a(text_to_insert, new_text, new_text_length, return);
-	debug_print("add:undo add %d-%ld\n", pos, pos + g_utf8_strlen(text_to_insert, -1));
-	undo_add(text_to_insert, pos, pos + g_utf8_strlen(text_to_insert, -1),
+	utf8_len = g_utf8_strlen(text_to_insert, -1);
+
+	if (undostruct->wrap_info != NULL) {
+		update_wrap_undo(undostruct, text_to_insert, 
+				 pos, pos + utf8_len, UNDO_ACTION_INSERT);
+		return;
+	}
+
+	debug_print("add:undo add %d-%ld\n", pos, utf8_len);
+	undo_add(text_to_insert, pos, pos + utf8_len,
 		 UNDO_ACTION_INSERT, undostruct);
 }
 
@@ -578,23 +717,9 @@ void undo_delete_text_cb(GtkTextBuffer *textbuf, GtkTextIter *start,
 	start_pos = gtk_text_iter_get_offset(start);
 	end_pos   = gtk_text_iter_get_offset(end);
 
-	if (undostruct->wrap && undostruct->undo) {
-		UndoInfo *last_undo = undostruct->undo->data;
-		if (last_undo && (last_undo->action == UNDO_ACTION_INSERT
-				  || last_undo->action == UNDO_ACTION_REPLACE_INSERT)
-		&&  last_undo->start_pos < start_pos && last_undo->end_pos > end_pos) {
-			GtkTextIter start,end;
-			last_undo->end_pos -= g_utf8_strlen(text_to_delete, -1);
-			gtk_text_buffer_get_iter_at_offset(textbuf, &start, last_undo->start_pos);
-			gtk_text_buffer_get_iter_at_offset(textbuf, &end, last_undo->end_pos);
-			g_free(last_undo->text);
-			last_undo->text = gtk_text_buffer_get_text(textbuf, &start, &end, FALSE);
-			debug_print("del:undo upd %d-%d\n", last_undo->start_pos, last_undo->end_pos);
-			return;
-		} else if (last_undo)
-			debug_print("del:last: %d, %d-%d (%d)\n", last_undo->action,
-				last_undo->start_pos, last_undo->end_pos, start_pos);
-		
+	if (undostruct->wrap_info != NULL) {
+		update_wrap_undo(undostruct, text_to_delete, start_pos, end_pos, UNDO_ACTION_DELETE);
+		return;
 	} 
 	debug_print("del:undo add %d-%d\n", start_pos, end_pos);
 	undo_add(text_to_delete, start_pos, end_pos, UNDO_ACTION_DELETE,
diff --git a/src/undo.h b/src/undo.h
index 292eff3..3f7634b 100644
--- a/src/undo.h
+++ b/src/undo.h
@@ -42,6 +42,7 @@ typedef enum
 } UndoState;
 
 typedef struct _UndoMain UndoMain;
+typedef struct _UndoWrap UndoWrap;
 
 typedef void (*UndoChangeStateFunc)	(UndoMain	*undostruct,
 					 gint		 undo_state,
@@ -62,7 +63,8 @@ struct _UndoMain
 	gboolean redo_state : 1;
 
 	gint paste;
-	gint wrap;
+
+	UndoWrap *wrap_info;
 };
 
 UndoMain *undo_init		(GtkWidget		*text);

-----------------------------------------------------------------------

Summary of changes:
 src/compose.c |    5 ++
 src/undo.c    |  201 ++++++++++++++++++++++++++++++++++++++++++++++-----------
 src/undo.h    |    4 +-
 3 files changed, 171 insertions(+), 39 deletions(-)


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list