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@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@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.