SF.net SVN: geany: [878] trunk

eht16 at users.sourceforge.net eht16 at xxxxx
Tue Oct 10 16:02:51 UTC 2006


Revision: 878
          http://svn.sourceforge.net/geany/?rev=878&view=rev
Author:   eht16
Date:     2006-10-10 09:02:41 -0700 (Tue, 10 Oct 2006)

Log Message:
-----------
Finished new Undo system. Now some more actions can be undone and also redone.

Modified Paths:
--------------
    trunk/ChangeLog
    trunk/src/callbacks.c
    trunk/src/document.c
    trunk/src/document.h
    trunk/src/sci_cb.c

Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2006-10-10 14:27:58 UTC (rev 877)
+++ trunk/ChangeLog	2006-10-10 16:02:41 UTC (rev 878)
@@ -1,6 +1,13 @@
 2006-10-10  Enrico Tröger  <enrico.troeger at uvena.de>
 
  * src/document.c: Connect only once to the "sci-notify" signal.
+ * scintilla/CellBuffer.cxx, scintilla/Document.cxx,
+   scintilla/include/Scintilla.h:
+   Applied patch from Armel Asselin (thanks). It adds SC_START_ACTION
+   notification which is required for Geany's new Undo system.
+ * src/document.c, src/sci_cb.c, src/callbacks.c:
+   Finished new Undo system. Now some more actions can be undone and
+   also redone.
 
 
 2006-10-09  Nick Treleaven  <nick.treleaven at btinternet.com>

Modified: trunk/src/callbacks.c
===================================================================
--- trunk/src/callbacks.c	2006-10-10 14:27:58 UTC (rev 877)
+++ trunk/src/callbacks.c	2006-10-10 16:02:41 UTC (rev 878)
@@ -2432,15 +2432,12 @@
 	gint idx = document_get_cur_idx();
 	guint i = GPOINTER_TO_INT(user_data);
 
-	if (app->ignore_callback || idx < 0 || encodings[i].charset == NULL ||
+	if (app->ignore_callback || ! DOC_IDX_VALID(idx) || encodings[i].charset == NULL ||
 		utils_strcmp(encodings[i].charset, doc_list[idx].encoding)) return;
 
-	// old charset string will be freed with the undo buffer
-	document_undo_add(idx, UNDO_ENCODING, doc_list[idx].encoding);
-	doc_list[idx].encoding = g_strdup(encodings[i].charset);
-	ui_update_statusbar(idx, -1);
-	gtk_widget_set_sensitive(lookup_widget(app->window, "menu_write_unicode_bom1"),
-			utils_is_unicode_charset(doc_list[idx].encoding));
+	document_undo_add(idx, UNDO_ENCODING, g_strdup(doc_list[idx].encoding));
+
+	document_set_encoding(idx, encodings[i].charset);
 }
 
 
@@ -2492,9 +2489,10 @@
 
 		if (idx == -1 || ! doc_list[idx].is_valid) return;
 
+		document_undo_add(idx, UNDO_BOM, GINT_TO_POINTER(doc_list[idx].has_bom));
+
 		doc_list[idx].has_bom = ! doc_list[idx].has_bom;
 
-		document_undo_add(idx, UNDO_BOM, GINT_TO_POINTER(! doc_list[idx].has_bom));
 		ui_update_statusbar(idx, -1);
 	}
 }

Modified: trunk/src/document.c
===================================================================
--- trunk/src/document.c	2006-10-10 14:27:58 UTC (rev 877)
+++ trunk/src/document.c	2006-10-10 16:02:41 UTC (rev 878)
@@ -68,7 +68,11 @@
 document_replace_range(gint idx, const gchar *find_text, const gchar *replace_text,
 	gint flags, gint start, gint end, gboolean escaped_chars);
 
+static void document_undo_clear(gint idx);
+static void document_redo_add(gint idx, guint type, gpointer data);
 
+
+
 /* returns the index of the notebook page which has the given filename
  * is_tm_filename is needed when passing TagManager filenames because they are
  * dereferenced, and would not match the link filename. */
@@ -362,7 +366,6 @@
 		doc_list[idx].has_bom = FALSE;
 		doc_list[idx].tm_file = NULL;
 		document_undo_clear(idx);
-		document_redo_clear(idx);
 		if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(app->notebook)) == 0)
 		{
 			ui_update_tag_list(-1, FALSE);
@@ -388,10 +391,19 @@
 
 	g_assert(idx != -1);
 
+	sci_set_undo_collection(doc_list[idx].sci, FALSE); // avoid creation of an undo action
 	sci_clear_all(doc_list[idx].sci);
 	sci_set_text(doc_list[idx].sci, template);
 	g_free(template);
 
+#ifdef G_OS_WIN32
+	sci_set_eol_mode(doc_list[idx].sci, SC_EOL_CRLF);
+#else
+	sci_set_eol_mode(doc_list[idx].sci, SC_EOL_LF);
+#endif
+	sci_set_undo_collection(doc_list[idx].sci, TRUE);
+	sci_empty_undo_buffer(doc_list[idx].sci);
+
 	doc_list[idx].encoding = g_strdup(encodings[app->pref_editor_default_encoding].charset);
 	//document_set_filetype(idx, (ft == NULL) ? filetypes[GEANY_FILETYPES_ALL] : ft);
 	document_set_filetype(idx, ft);	// also clears taglist
@@ -402,13 +414,8 @@
 	doc_list[idx].changed = FALSE;
 	document_set_text_changed(idx);
 	ui_document_show_hide(idx); //update the document menu
-#ifdef G_OS_WIN32
-	sci_set_eol_mode(doc_list[idx].sci, SC_EOL_CRLF);
-#else
-	sci_set_eol_mode(doc_list[idx].sci, SC_EOL_LF);
-#endif
+
 	sci_set_line_numbers(doc_list[idx].sci, app->show_linenumber_margin, 0);
-	sci_empty_undo_buffer(doc_list[idx].sci);
 	sci_goto_pos(doc_list[idx].sci, 0, TRUE);
 
 	// "the" SCI signal (connect after initial setup(i.e. adding text))
@@ -637,15 +644,17 @@
 	if (idx == -1) return -1;	// really should not happen
 
 	// set editor mode and add the text to the ScintillaObject
-	sci_set_text(doc_list[idx].sci, data);	// NULL terminated data; avoids modifying sci
+	sci_set_undo_collection(doc_list[idx].sci, FALSE); // avoid creation of an undo action
+	sci_empty_undo_buffer(doc_list[idx].sci);
+	sci_set_text(doc_list[idx].sci, data);	// NULL terminated data
+
 	editor_mode = utils_get_line_endings(data, size);
 	sci_set_eol_mode(doc_list[idx].sci, editor_mode);
+	sci_set_line_numbers(doc_list[idx].sci, app->show_linenumber_margin, 0);
 
-	sci_set_line_numbers(doc_list[idx].sci, app->show_linenumber_margin, 0);
-	sci_set_savepoint(doc_list[idx].sci);
-	sci_empty_undo_buffer(doc_list[idx].sci);
-	// get the modification time from file and keep it
-	doc_list[idx].mtime = st.st_mtime;
+	sci_set_undo_collection(doc_list[idx].sci, TRUE);
+
+	doc_list[idx].mtime = st.st_mtime; // get the modification time from file and keep it
 	doc_list[idx].changed = FALSE;
 	doc_list[idx].file_name = g_strdup(utf8_filename);
 	doc_list[idx].encoding = enc;
@@ -676,6 +685,7 @@
 	else
 	{	// reloading
 		document_update_tag_list(idx, TRUE);
+		document_undo_clear(idx);
 	}
 
 	document_set_text_changed(idx);
@@ -1494,11 +1504,26 @@
 	}
 }
 
+
+void document_set_encoding(gint idx, const gchar *new_encoding)
+{
+	if (! DOC_IDX_VALID(idx) || new_encoding == NULL ||
+		utils_strcmp(new_encoding, doc_list[idx].encoding)) return;
+
+	g_free(doc_list[idx].encoding);
+	doc_list[idx].encoding = g_strdup(new_encoding);
+
+	ui_update_statusbar(idx, -1);
+	gtk_widget_set_sensitive(lookup_widget(app->window, "menu_write_unicode_bom1"),
+			utils_is_unicode_charset(doc_list[idx].encoding));
+}
+
+
 /* own Undo / Redo implementation to be able to undo / redo changes
  * to the encoding or the Unicode BOM (which are Scintilla independet).
  * All Scintilla events are stored in the undo / redo buffer and are passed through. */
 
-/* Clears the Undo buffer (to be called after saving a file or when closing the document) */
+/* Clears the Undo and Redo buffer (to be called when reloading or closing the document) */
 void document_undo_clear(gint idx)
 {
 	undo_action *a;
@@ -1519,17 +1544,6 @@
 	}
 	doc_list[idx].undo_actions = NULL;
 
-	doc_list[idx].changed = FALSE;
-	if (! app->quitting) document_set_text_changed(idx);
-}
-
-
-/* Clears the Redo buffer (to be called after saving a file or when closing the document) */
-void document_redo_clear(gint idx)
-{
-/*
-	undo_action *a;
-
 	while (g_trash_stack_height(&doc_list[idx].redo_actions) > 0)
 	{
 		a = g_trash_stack_pop(&doc_list[idx].redo_actions);
@@ -1548,7 +1562,9 @@
 
 	doc_list[idx].changed = FALSE;
 	if (! app->quitting) document_set_text_changed(idx);
-*/
+
+	//geany_debug("%s: new undo stack height: %d, new redo stack height: %d", __func__,
+				//g_trash_stack_height(&doc_list[idx].undo_actions), g_trash_stack_height(&doc_list[idx].redo_actions));
 }
 
 
@@ -1556,7 +1572,7 @@
 {
 	undo_action *action;
 
-	if (idx == -1 || ! doc_list[idx].is_valid) return;
+	if (! DOC_IDX_VALID(idx)) return;
 
 	action = g_new0(undo_action, 1);
 	action->type = type;
@@ -1568,19 +1584,15 @@
 	document_set_text_changed(idx);
 	ui_update_popup_reundo_items(idx);
 
-	{
-		geany_debug("%s: new stack height: %d, added type: %d", __func__,
-				g_trash_stack_height(&doc_list[idx].undo_actions), action->type);
-	}
+	//geany_debug("%s: new stack height: %d, added type: %d", __func__,
+				//g_trash_stack_height(&doc_list[idx].undo_actions), action->type);
 }
 
 
 gboolean document_can_undo(gint idx)
 {
-	return sci_can_undo(doc_list[idx].sci);
+	if (! DOC_IDX_VALID(idx)) return FALSE;
 
-	if (idx == -1 || ! doc_list[idx].is_valid) return FALSE;
-
 	if (g_trash_stack_height(&doc_list[idx].undo_actions) > 0 || sci_can_undo(doc_list[idx].sci))
 		return TRUE;
 	else
@@ -1588,31 +1600,96 @@
 }
 
 
+void document_undo(gint idx)
+{
+	undo_action *action;
+
+	if (! DOC_IDX_VALID(idx)) return;
+
+	action = g_trash_stack_pop(&doc_list[idx].undo_actions);
+
+	if (action == NULL)
+	{
+		// fallback, should not be necessary
+		geany_debug("%s: fallback used", __func__);
+		sci_undo(doc_list[idx].sci);
+	}
+	else
+	{
+		switch (action->type)
+		{
+			case UNDO_SCINTILLA:
+			{
+				document_redo_add(idx, UNDO_SCINTILLA, NULL);
+
+				sci_undo(doc_list[idx].sci);
+				break;
+			}
+			case UNDO_BOM:
+			{
+				document_redo_add(idx, UNDO_BOM, GINT_TO_POINTER(doc_list[idx].has_bom));
+
+				doc_list[idx].has_bom = GPOINTER_TO_INT(action->data);
+				ui_update_statusbar(idx, -1);
+				ui_document_show_hide(idx);
+				break;
+			}
+			case UNDO_ENCODING:
+			{
+				// use the "old" encoding
+				document_redo_add(idx, UNDO_ENCODING, g_strdup(doc_list[idx].encoding));
+
+				document_set_encoding(idx, (const gchar*)action->data);
+
+				app->ignore_callback = TRUE;
+				encodings_select_radio_item((const gchar*)action->data);
+				app->ignore_callback = FALSE;
+
+				g_free(action->data);
+				break;
+			}
+			default: break;
+		}
+	}
+	g_free(action); // free the action which was taken from the stack
+
+	if (g_trash_stack_height(&doc_list[idx].undo_actions) == 0)
+	{
+		doc_list[idx].changed = FALSE;
+		document_set_text_changed(idx);
+	}
+	else
+		doc_list[idx].changed = TRUE;
+
+	ui_update_popup_reundo_items(idx);
+	//geany_debug("%s: new stack height: %d", __func__, g_trash_stack_height(&doc_list[idx].undo_actions));
+}
+
+
 gboolean document_can_redo(gint idx)
 {
-	if (idx == -1 || ! doc_list[idx].is_valid) return FALSE;
+	if (! DOC_IDX_VALID(idx)) return FALSE;
 
-	return sci_can_redo(doc_list[idx].sci);
+	if (g_trash_stack_height(&doc_list[idx].redo_actions) > 0 || sci_can_redo(doc_list[idx].sci))
+		return TRUE;
+	else
+		return FALSE;
 }
 
 
-void document_undo(gint idx)
+void document_redo(gint idx)
 {
 	undo_action *action;
 
-#if 1
-	sci_undo(doc_list[idx].sci);
-	return;
-#endif
+	if (! DOC_IDX_VALID(idx)) return;
 
-	if (idx == -1 || ! doc_list[idx].is_valid) return;
+	action = g_trash_stack_pop(&doc_list[idx].redo_actions);
 
-	action = g_trash_stack_pop(&doc_list[idx].undo_actions);
-
 	if (action == NULL)
 	{
 		// fallback, should not be necessary
-		sci_undo(doc_list[idx].sci);
+		geany_debug("%s: fallback used", __func__);
+		sci_redo(doc_list[idx].sci);
 	}
 	else
 	{
@@ -1620,13 +1697,15 @@
 		{
 			case UNDO_SCINTILLA:
 			{
-				geany_debug("undo: Scintilla");
-				sci_undo(doc_list[idx].sci);
+				document_undo_add(idx, UNDO_SCINTILLA, NULL);
+
+				sci_redo(doc_list[idx].sci);
 				break;
 			}
 			case UNDO_BOM:
 			{
-				geany_debug("undo: BOM");
+				document_undo_add(idx, UNDO_BOM, GINT_TO_POINTER(doc_list[idx].has_bom));
+
 				doc_list[idx].has_bom = GPOINTER_TO_INT(action->data);
 				ui_update_statusbar(idx, -1);
 				ui_document_show_hide(idx);
@@ -1634,28 +1713,46 @@
 			}
 			case UNDO_ENCODING:
 			{
-				geany_debug("undo: Encoding");
-				doc_list[idx].encoding = (gchar*) action->data;
-				ui_update_statusbar(idx, -1);
-				encodings_select_radio_item(doc_list[idx].encoding);
-				gtk_widget_set_sensitive(lookup_widget(app->window, "menu_write_unicode_bom1"),
-								utils_is_unicode_charset(doc_list[idx].encoding));
+				document_undo_add(idx, UNDO_ENCODING, g_strdup(doc_list[idx].encoding));
+
+				document_set_encoding(idx, (const gchar*)action->data);
+
+				app->ignore_callback = TRUE;
+				encodings_select_radio_item((const gchar*)action->data);
+				app->ignore_callback = FALSE;
+
+				g_free(action->data);
 				break;
 			}
 			default: break;
 		}
 	}
+	g_free(action); // free the action which was taken from the stack
 
-	if (g_trash_stack_height(&doc_list[idx].undo_actions) == 0) doc_list[idx].changed = FALSE;
 	ui_update_popup_reundo_items(idx);
-	geany_debug("%s: new stack height: %d", __func__, g_trash_stack_height(&doc_list[idx].undo_actions));
+	//geany_debug("%s: new stack height: %d", __func__, g_trash_stack_height(&doc_list[idx].redo_actions));
 }
 
 
-void document_redo(gint idx)
+static void document_redo_add(gint idx, guint type, gpointer data)
 {
-	if (idx == -1 || ! doc_list[idx].is_valid) return;
+	undo_action *action;
 
-	sci_redo(doc_list[idx].sci);
+	if (! DOC_IDX_VALID(idx)) return;
+
+	action = g_new0(undo_action, 1);
+	action->type = type;
+	action->data = data;
+
+	g_trash_stack_push(&doc_list[idx].redo_actions, action);
+
+	doc_list[idx].changed = TRUE;
+	document_set_text_changed(idx);
+	ui_update_popup_reundo_items(idx);
+
+	//geany_debug("%s: new stack height: %d, added type: %d", __func__,
+				//g_trash_stack_height(&doc_list[idx].redo_actions), action->type);
 }
 
+
+

Modified: trunk/src/document.h
===================================================================
--- trunk/src/document.h	2006-10-10 14:27:58 UTC (rev 877)
+++ trunk/src/document.h	2006-10-10 16:02:41 UTC (rev 878)
@@ -175,11 +175,14 @@
 
 void document_ensure_final_newline(gint idx);
 
+void document_set_encoding(gint idx, const gchar *new_encoding);
 
 
 /* own Undo / Redo implementation to be able to undo / redo changes
  * to the encoding or the Unicode BOM (which are Scintilla independet).
  * All Scintilla events are stored in the undo / redo buffer and are passed through. */
+
+// available UNDO actions, UNDO_SCINTILLA is a pseudo action to trigger Scintilla's undo management
 enum
 {
 	UNDO_SCINTILLA = 0,
@@ -188,11 +191,13 @@
 	UNDO_ACTIONS_MAX
 };
 
+// an undo action, also used for redo actions
 typedef struct
 {
-	GTrashStack *next;
-	guint type;	// to identify the action
-	gpointer *data; // the old value (before the change)
+	GTrashStack *next;	// pointer to the next stack element(required for the GTrashStack)
+	guint type;			// to identify the action
+	gpointer *data; 	// the old value (before the change), in case of a redo action it contains
+						// the new value
 } undo_action;
 
 gboolean document_can_undo(gint idx);
@@ -205,8 +210,4 @@
 
 void document_undo_add(gint idx, guint type, gpointer data);
 
-void document_undo_clear(gint idx);
-
-void document_redo_clear(gint idx);
-
 #endif

Modified: trunk/src/sci_cb.c
===================================================================
--- trunk/src/sci_cb.c	2006-10-10 14:27:58 UTC (rev 877)
+++ trunk/src/sci_cb.c	2006-10-10 16:02:41 UTC (rev 878)
@@ -153,26 +153,16 @@
 #endif
 			break;
 		}
-		case 2023:
+ 		case SCN_MODIFIED:
 		{
-			geany_debug("Undo notification");
-			break;
-		}
-/*		case SCN_KEY:
-		{
-			//geany_debug("key notification triggered with %c", nt->ch);
-			break;
-		}
-		case SCN_MODIFIED:
-		{
-			if (nt->modificationType  & SC_MOD_INSERTTEXT ||
-				nt->modificationType & SC_MOD_DELETETEXT)
+			if (nt->modificationType & SC_START_ACTION && ! app->ignore_callback)
 			{
+				// get notified about undo changes
 				document_undo_add(idx, UNDO_SCINTILLA, NULL);
 			}
 			break;
 		}
-*/		case SCN_CHARADDED:
+		case SCN_CHARADDED:
 		{
 			gint pos = sci_get_current_position(sci);
 


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.



More information about the Commits mailing list