[Xfce4-commits] <mousepad:master> * mousepad/mousepad-window.c: Use the switch-page signal instead of a notify on the page property. * mousepad/mousepad-*: Remove deprecated tooltip api when compiled with Gtk+ >= 2.12. * mousepad/mousepad-replace-dialog.c: Connect tab switch signal for updating the dialog status when switching tabs. * mousepad/mousepad-undo.c: Fix issues with the undo manager. It now works with a points system (chars: 1pt, space/tab: 10pts, new line: 25pts). A step contains 30pts, whole words and spaces are merged. This way the undo steps feel more consistent. Properly keep the number of visible undo steps < 100. Store document save point in the undo manager, when you undo to this points the document will not be modified, but the history is not erased either when saving. * mousepad/Makefile.am: Add DGTK_DISABLE_DEPRECATED and DGDK_DISABLE_DEPRECATED.
Nick Schermer
noreply at xfce.org
Sat May 5 21:31:07 CEST 2012
Updating branch refs/heads/master
to d1075d569a475bc2e16dfaab0209e1e4d0c8dec0 (commit)
from 1d7bef769029aae39ddcecb6c529177393363dcf (commit)
commit d1075d569a475bc2e16dfaab0209e1e4d0c8dec0
Author: Nick Schermer <nick at xfce.org>
Date: Mon Dec 10 19:36:58 2007 +0000
* mousepad/mousepad-window.c: Use the switch-page signal instead
of a notify on the page property.
* mousepad/mousepad-*: Remove deprecated tooltip api when compiled
with Gtk+ >= 2.12.
* mousepad/mousepad-replace-dialog.c: Connect tab switch signal for
updating the dialog status when switching tabs.
* mousepad/mousepad-undo.c: Fix issues with the undo manager. It
now works with a points system (chars: 1pt, space/tab: 10pts,
new line: 25pts). A step contains 30pts, whole words and spaces
are merged. This way the undo steps feel more consistent.
Properly keep the number of visible undo steps < 100.
Store document save point in the undo manager, when you undo to
this points the document will not be modified, but the history
is not erased either when saving.
* mousepad/Makefile.am: Add DGTK_DISABLE_DEPRECATED and
DGDK_DISABLE_DEPRECATED.
(Old svn revision: 26454)
ChangeLog | 20 ++
mousepad/Makefile.am | 2 +
mousepad/mousepad-document.c | 8 +-
mousepad/mousepad-private.h | 7 +
mousepad/mousepad-replace-dialog.c | 30 ++-
mousepad/mousepad-replace-dialog.h | 2 +
mousepad/mousepad-statusbar.c | 2 +-
mousepad/mousepad-undo.c | 621 +++++++++++++++++++++---------------
mousepad/mousepad-undo.h | 2 +
mousepad/mousepad-util.c | 4 +-
mousepad/mousepad-util.h | 2 +
mousepad/mousepad-window.c | 110 ++++---
12 files changed, 500 insertions(+), 310 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 2c1a270..dbc8aa4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
2007-12-08 Nick Schermer <nick at xfce.org>
+ * mousepad/mousepad-window.c: Use the switch-page signal instead
+ of a notify on the page property.
+ * mousepad/mousepad-*: Remove deprecated tooltip api when compiled
+ with Gtk+ >= 2.12.
+ * mousepad/mousepad-replace-dialog.c: Connect tab switch signal for
+ updating the dialog status when switching tabs.
+ * mousepad/mousepad-undo.c: Fix issues with the undo manager. It
+ now works with a points system (chars: 1pt, space/tab: 10pts,
+ new line: 25pts). A step contains 30pts, whole words and spaces
+ are merged. This way the undo steps feel more consistent.
+ Properly keep the number of visible undo steps < 100.
+ Store document save point in the undo manager, when you undo to
+ this points the document will not be modified, but the history
+ is not erased either when saving.
+ * mousepad/Makefile.am: Add DGTK_DISABLE_DEPRECATED and
+ DGDK_DISABLE_DEPRECATED.
+
+
+2007-12-08 Nick Schermer <nick at xfce.org>
+
* mousepad/mousepad-{dialog,window}.c: Show save as button in
question dialog for readonly documents. Also add the modified
readonly documents to the save-as queue when running save all.
diff --git a/mousepad/Makefile.am b/mousepad/Makefile.am
index 7e97461..1d1b787 100644
--- a/mousepad/Makefile.am
+++ b/mousepad/Makefile.am
@@ -11,6 +11,8 @@ INCLUDES = \
-DLIBEXECDIR=\"$(libexecdir)\" \
-DPACKAGE_LOCALE_DIR=\"$(localedir)\" \
-DG_DISABLE_DEPRECATED \
+ -DGTK_DISABLE_DEPRECATED \
+ -DGDK_DISABLE_DEPRECATED \
$(PLATFORM_CPPFLAGS)
bin_PROGRAMS = \
diff --git a/mousepad/mousepad-document.c b/mousepad/mousepad-document.c
index 9dce17c..f2d2b68 100644
--- a/mousepad/mousepad-document.c
+++ b/mousepad/mousepad-document.c
@@ -422,7 +422,7 @@ mousepad_document_filename_changed (MousepadDocument *document,
gtk_label_set_text (GTK_LABEL (document->priv->label), utf8_basename);
/* set the tab tooltip */
- mousepad_util_set_tooltip (document->priv->ebox, utf8_filename);
+ mousepad_widget_set_tooltip_text (document->priv->ebox, utf8_filename);
/* update label color */
mousepad_document_label_color (document);
@@ -545,7 +545,7 @@ mousepad_document_get_tab_label (MousepadDocument *document)
/* the ebox */
document->priv->ebox = g_object_new (GTK_TYPE_EVENT_BOX, "border-width", 2, "visible-window", FALSE, NULL);
gtk_box_pack_start (GTK_BOX (hbox), document->priv->ebox, TRUE, TRUE, 0);
- mousepad_util_set_tooltip (document->priv->ebox, document->priv->utf8_filename);
+ mousepad_widget_set_tooltip_text (document->priv->ebox, document->priv->utf8_filename);
gtk_widget_show (document->priv->ebox);
/* create the label */
@@ -566,10 +566,10 @@ mousepad_document_get_tab_label (MousepadDocument *document)
style = gtk_rc_style_new ();
style->xthickness = style->ythickness = 0;
gtk_widget_modify_style (button, style);
- gtk_rc_style_unref (style);
+ g_object_unref (G_OBJECT (style));
/* pack button, add signal and tooltip */
- mousepad_util_set_tooltip (button, _("Close this tab"));
+ mousepad_widget_set_tooltip_text (button, _("Close this tab"));
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (mousepad_document_tab_button_clicked), document);
gtk_widget_show (button);
diff --git a/mousepad/mousepad-private.h b/mousepad/mousepad-private.h
index 8a9fa77..c6d6730 100644
--- a/mousepad/mousepad-private.h
+++ b/mousepad/mousepad-private.h
@@ -95,6 +95,13 @@ G_BEGIN_DECLS
#define G_UNLIKELY(expr) (expr)
#endif
+/* tooltip api */
+#if GTK_CHECK_VERSION (2,12,0)
+#define mousepad_widget_set_tooltip_text(widget,text) (gtk_widget_set_tooltip_text (widget, text))
+#else
+#define mousepad_widget_set_tooltip_text(widget,text) (mousepad_util_set_tooltip (widget, text))
+#endif
+
G_END_DECLS
#endif /* !__MOUSEPAD_PRIVATE_H__ */
diff --git a/mousepad/mousepad-replace-dialog.c b/mousepad/mousepad-replace-dialog.c
index 9057766..b9827d5 100644
--- a/mousepad/mousepad-replace-dialog.c
+++ b/mousepad/mousepad-replace-dialog.c
@@ -355,7 +355,7 @@ mousepad_replace_dialog_response (GtkWidget *widget,
MousepadReplaceDialog *dialog = MOUSEPAD_REPLACE_DIALOG (widget);
gint matches;
const gchar *search_str, *replace_str;
- gchar *hits_str;
+ gchar *message;
/* close dialog */
if (response_id == MOUSEPAD_RESPONSE_CLOSE)
@@ -456,15 +456,19 @@ mousepad_replace_dialog_response (GtkWidget *widget,
/* emit the signal */
g_signal_emit (G_OBJECT (dialog), dialog_signals[SEARCH], 0, flags, search_str, replace_str, &matches);
- /* set search widget result */
+ /* reset counter */
+ if (response_id == MOUSEPAD_RESPONSE_REPLACE && dialog->replace_all)
+ matches = 0;
+
+ /* update entry color */
mousepad_util_entry_error (dialog->search_entry, matches == 0);
- /* update hits counter */
+ /* update counter */
if (dialog->replace_all)
{
- hits_str = g_strdup_printf ("%d %s", matches, matches == 1 ? _("occurence") : _("occurences"));
- gtk_label_set_markup (GTK_LABEL (dialog->hits_label), hits_str);
- g_free (hits_str);
+ message = g_strdup_printf (ngettext ("%d occurence", "%d occurences", matches), matches);
+ gtk_label_set_markup (GTK_LABEL (dialog->hits_label), message);
+ g_free (message);
}
}
@@ -634,6 +638,14 @@ mousepad_replace_dialog_history_insert_text (const gchar *text)
+GtkWidget *
+mousepad_replace_dialog_new (void)
+{
+ return g_object_new (MOUSEPAD_TYPE_REPLACE_DIALOG, NULL);
+}
+
+
+
void
mousepad_replace_dialog_history_clean (void)
{
@@ -658,8 +670,8 @@ mousepad_replace_dialog_history_clean (void)
-GtkWidget *
-mousepad_replace_dialog_new (void)
+void
+mousepad_replace_dialog_page_switched (MousepadReplaceDialog *dialog)
{
- return g_object_new (MOUSEPAD_TYPE_REPLACE_DIALOG, NULL);
+ mousepad_replace_dialog_changed (dialog);
}
diff --git a/mousepad/mousepad-replace-dialog.h b/mousepad/mousepad-replace-dialog.h
index e66ad2d..b5cb629 100644
--- a/mousepad/mousepad-replace-dialog.h
+++ b/mousepad/mousepad-replace-dialog.h
@@ -36,6 +36,8 @@ GtkWidget *mousepad_replace_dialog_new (void);
void mousepad_replace_dialog_history_clean (void);
+void mousepad_replace_dialog_page_switched (MousepadReplaceDialog *dialog);
+
G_END_DECLS
#endif /* !__MOUSEPAD_REPLACE_DIALOG_H__ */
diff --git a/mousepad/mousepad-statusbar.c b/mousepad/mousepad-statusbar.c
index 613bc05..462c98a 100644
--- a/mousepad/mousepad-statusbar.c
+++ b/mousepad/mousepad-statusbar.c
@@ -149,7 +149,7 @@ mousepad_statusbar_init (MousepadStatusbar *statusbar)
ebox = gtk_event_box_new ();
gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, TRUE, 0);
gtk_event_box_set_visible_window (GTK_EVENT_BOX (ebox), FALSE);
- mousepad_util_set_tooltip (ebox, _("Toggle the overwrite mode"));
+ mousepad_widget_set_tooltip_text (ebox, _("Toggle the overwrite mode"));
g_signal_connect (G_OBJECT (ebox), "button-press-event", G_CALLBACK (mousepad_statusbar_overwrite_clicked), statusbar);
gtk_widget_show (ebox);
diff --git a/mousepad/mousepad-undo.c b/mousepad/mousepad-undo.c
index 6d6b213..ab0adf0 100644
--- a/mousepad/mousepad-undo.c
+++ b/mousepad/mousepad-undo.c
@@ -23,7 +23,15 @@
#include <mousepad/mousepad-undo.h>
-#define DEFAULT_CACHE_SIZE (50)
+/* global */
+#define MOUSEPAD_UNDO_MAX_STEPS (100) /* maximum number of undo steps */
+#define MOUSEPAD_UNDO_BUFFER_SIZE (40) /* buffer size */
+
+/* points system */
+#define MOUSEPAD_UNDO_POINTS (30) /* maximum points in a step */
+#define MOUSEPAD_UNDO_POINTS_CHAR (1) /* points for a character */
+#define MOUSEPAD_UNDO_POINTS_WORD_BREAK (10) /* points for a word break */
+#define MOUSEPAD_UNDO_POINTS_NEW_LINE (25) /* points for a new line */
@@ -33,31 +41,34 @@ typedef enum _MousepadUndoAction MousepadUndoAction;
-static void mousepad_undo_class_init (MousepadUndoClass *klass);
-static void mousepad_undo_init (MousepadUndo *undo);
-static void mousepad_undo_finalize (GObject *object);
-static void mousepad_undo_emit_signals (MousepadUndo *undo);
-static void mousepad_undo_step_free (MousepadUndoStep *step,
- MousepadUndo *undo);
-static void mousepad_undo_step_perform (MousepadUndo *undo,
- gboolean redo);
-static void mousepad_undo_cache_to_step (MousepadUndo *undo);
-static void mousepad_undo_cache_reset_needle (MousepadUndo *undo);
-static void mousepad_undo_cache_update (MousepadUndo *undo,
- MousepadUndoAction action,
- gint start,
- gint end,
- const gchar *text);
-static void mousepad_undo_buffer_insert (GtkTextBuffer *buffer,
- GtkTextIter *pos,
- const gchar *text,
- gint length,
- MousepadUndo *undo);
-static void mousepad_undo_buffer_delete (GtkTextBuffer *buffer,
- GtkTextIter *start_iter,
- GtkTextIter *end_iter,
- MousepadUndo *undo);
-
+static void mousepad_undo_class_init (MousepadUndoClass *klass);
+static void mousepad_undo_init (MousepadUndo *undo);
+static void mousepad_undo_finalize (GObject *object);
+static void mousepad_undo_emit_signals (MousepadUndo *undo);
+static void mousepad_undo_step_free (MousepadUndoStep *step);
+static void mousepad_undo_step (MousepadUndo *undo,
+ gboolean redo);
+static void mousepad_undo_cache_reset (MousepadUndo *undo);
+static void mousepad_undo_clear_oldest_step (MousepadUndo *undo);
+static void mousepad_undo_cache_to_step (MousepadUndo *undo);
+static void mousepad_undo_needle_reset (MousepadUndo *undo);
+static void mousepad_undo_buffer_changed (MousepadUndo *undo,
+ MousepadUndoAction action,
+ const gchar *text,
+ gint length,
+ gint start_offset,
+ gint end_offset);
+static void mousepad_undo_buffer_insert (GtkTextBuffer *buffer,
+ GtkTextIter *pos,
+ const gchar *text,
+ gint length,
+ MousepadUndo *undo);
+static void mousepad_undo_buffer_delete (GtkTextBuffer *buffer,
+ GtkTextIter *start_iter,
+ GtkTextIter *end_iter,
+ MousepadUndo *undo);
+static void mousepad_undo_buffer_begin_user_action (GtkTextBuffer *buffer,
+ MousepadUndo *undo);
enum
@@ -74,27 +85,8 @@ struct _MousepadUndoClass
enum _MousepadUndoAction
{
- INSERT, /* insert action */
- DELETE, /* delete action */
-};
-
-struct _MousepadUndoCache
-{
- /* string to cache inserted or deleted character */
- GString *string;
-
- /* current cached action */
- MousepadUndoAction action;
-
- /* cache start and end positions */
- gint start;
- gint end;
-
- /* whether the last character was a word breaking character */
- guint is_space : 1;
-
- /* whether the changes in the cache are part of a group */
- guint in_group : 1;
+ INSERT, /* insert action */
+ DELETE, /* delete action */
};
struct _MousepadUndo
@@ -102,26 +94,48 @@ struct _MousepadUndo
GObject __parent__;
/* the text buffer we're monitoring */
- GtkTextBuffer *buffer;
+ GtkTextBuffer *buffer;
/* whether the undo manager is locked */
- gint locked;
+ gint locked;
- /* whether we should put multiple changes into one action */
- gint grouping;
+ /* whether multiple changes are merged */
+ gint grouping;
/* whether we can undo or redo */
- guint can_undo : 1;
- guint can_redo : 1;
+ guint can_undo : 1;
+ guint can_redo : 1;
/* list containing the steps */
- GList *steps;
+ GList *steps;
+
+ /* number of steps */
+ gint n_steps;
/* steps list pointer when undoing */
- GList *needle;
+ GList *needle;
+
+ /* element in the last when saving */
+ GList *saved;
+
+ /* string holding the deleted characters */
+ GString *cache;
- /* internal cache */
- MousepadUndoCache cache;
+ /* start and end positions of the cache */
+ gint cache_start;
+ gint cache_end;
+
+ /* if the last character in the cache is a space */
+ guint cache_is_space : 1;
+
+ /* if the changes in the cache are part of a group */
+ guint cache_in_group : 1;
+
+ /* current action in the cache */
+ MousepadUndoAction cache_action;
+
+ /* number of points assigned to the cache */
+ gint cache_points;
};
struct _MousepadUndoStep
@@ -129,8 +143,8 @@ struct _MousepadUndoStep
/* step action */
MousepadUndoAction action;
- /* pointer to the string or another entry in the list */
- gpointer data;
+ /* deleted string */
+ gchar *data;
/* start and end positions */
gint start;
@@ -203,17 +217,16 @@ mousepad_undo_init (MousepadUndo *undo)
/* initialize */
undo->locked = 0;
undo->grouping = 0;
+ undo->n_steps = 0;
undo->can_undo = FALSE;
undo->can_redo = FALSE;
undo->steps = NULL;
undo->needle = NULL;
+ undo->saved = NULL;
/* initialize the cache */
- undo->cache.string = NULL;
- undo->cache.start = -1;
- undo->cache.end = -1;
- undo->cache.is_space = FALSE;
- undo->cache.in_group = FALSE;
+ undo->cache = NULL;
+ mousepad_undo_cache_reset (undo);
}
@@ -243,7 +256,7 @@ mousepad_undo_emit_signals (MousepadUndo *undo)
gboolean can_undo, can_redo;
/* detect if we can undo or redo */
- can_undo = (undo->needle != NULL);
+ can_undo = (undo->needle != NULL || undo->cache_start != undo->cache_end);
can_redo = (undo->needle == NULL || g_list_previous (undo->needle) != NULL);
/* emit signals if needed */
@@ -263,13 +276,8 @@ mousepad_undo_emit_signals (MousepadUndo *undo)
static void
-mousepad_undo_step_free (MousepadUndoStep *step,
- MousepadUndo *undo)
+mousepad_undo_step_free (MousepadUndoStep *step)
{
- /* remove from the list */
- if (G_LIKELY (undo))
- undo->steps = g_list_remove (undo->steps, step);
-
/* free the string */
g_free (step->data);
@@ -280,15 +288,15 @@ mousepad_undo_step_free (MousepadUndoStep *step,
static void
-mousepad_undo_step_perform (MousepadUndo *undo,
- gboolean redo)
+mousepad_undo_step (MousepadUndo *undo,
+ gboolean redo)
{
MousepadUndoStep *step;
MousepadUndoAction action;
- GList *li;
GtkTextIter start_iter, end_iter;
+ GList *li;
- /* lock for updates */
+ /* lock */
mousepad_undo_lock (undo);
/* flush the cache */
@@ -306,63 +314,64 @@ mousepad_undo_step_perform (MousepadUndo *undo,
/* freeze buffer notifications */
g_object_freeze_notify (G_OBJECT (undo->buffer));
- for (li = undo->needle; li != NULL; li = redo ? li->prev : li->next)
+ for (li = undo->needle; li != NULL; li = (redo ? li->prev : li->next))
{
- /* get the step data */
+ /* get the step */
step = li->data;
- if (G_LIKELY (step))
- {
- /* get the action */
- action = step->action;
+ /* get the action */
+ action = step->action;
- /* invert the action if we redo */
- if (redo)
- action = (action == INSERT ? DELETE : INSERT);
+ /* invert the action if needed */
+ if (redo)
+ action = (action == INSERT ? DELETE : INSERT);
- /* get the start iter position */
- gtk_text_buffer_get_iter_at_offset (undo->buffer, &start_iter, step->start);
+ /* get the start iter */
+ gtk_text_buffer_get_iter_at_offset (undo->buffer, &start_iter, step->start);
- switch (action)
- {
- case INSERT:
- /* get the end iter */
- gtk_text_buffer_get_iter_at_offset (undo->buffer, &end_iter, step->end);
+ switch (action)
+ {
+ case INSERT:
+ /* debug check */
+ _mousepad_return_if_fail (step->data == NULL);
- /* set the string we're going to remove for redo */
- if (step->data == NULL)
- step->data = gtk_text_buffer_get_slice (undo->buffer, &start_iter, &end_iter, TRUE);
+ /* get the end iter */
+ gtk_text_buffer_get_iter_at_offset (undo->buffer, &end_iter, step->end);
- /* delete the inserted text */
- gtk_text_buffer_delete (undo->buffer, &start_iter, &end_iter);
- break;
+ /* set the deleted for redo */
+ step->data = gtk_text_buffer_get_slice (undo->buffer, &start_iter, &end_iter, TRUE);
- case DELETE:
- _mousepad_return_if_fail (step->data != NULL);
+ /* delete the inserted text */
+ gtk_text_buffer_delete (undo->buffer, &start_iter, &end_iter);
+ break;
- /* insert the deleted text */
- gtk_text_buffer_insert (undo->buffer, &start_iter, (gchar *)step->data, -1);
- break;
+ case DELETE:
+ /* debug check */
+ _mousepad_return_if_fail (step->data != NULL);
- default:
- _mousepad_assert_not_reached ();
- break;
- }
+ /* insert the deleted text */
+ gtk_text_buffer_insert (undo->buffer, &start_iter, step->data, -1);
- /* set the cursor, we scroll to the cursor in mousepad-document */
- gtk_text_buffer_place_cursor (undo->buffer, &start_iter);
+ /* and cleanup */
+ g_free (step->data);
+ step->data = NULL;
+ break;
+
+ default:
+ _mousepad_assert_not_reached ();
+ break;
}
+ /* get the previous item when we redo */
if (redo)
{
- /* get the previous step to see if it's part of a group */
if (g_list_previous (li) != NULL)
step = g_list_previous (li)->data;
else
step = NULL;
}
- /* as long as the step is part of a group, we continue */
+ /* break when the step is not part of a group */
if (step == NULL || step->in_group == FALSE)
break;
}
@@ -370,191 +379,267 @@ mousepad_undo_step_perform (MousepadUndo *undo,
/* thawn buffer notifications */
g_object_thaw_notify (G_OBJECT (undo->buffer));
- /* set the needle element */
+ /* set the needle */
if (redo)
undo->needle = li;
else
undo->needle = g_list_next (li);
+ /* check if we've somehow reached the save point */
+ gtk_text_buffer_set_modified (undo->buffer, undo->needle != undo->saved);
+
/* emit undo and redo signals */
mousepad_undo_emit_signals (undo);
- /* release the lock */
+ /* unlock */
mousepad_undo_unlock (undo);
}
static void
-mousepad_undo_cache_to_step (MousepadUndo *undo)
+mousepad_undo_clear_oldest_step (MousepadUndo *undo)
{
+ GList *li, *lprev;
MousepadUndoStep *step;
+ gint to_remove;
- /* leave when the cache is empty */
- if (undo->cache.start == undo->cache.end)
- return;
+ _mousepad_return_if_fail (undo->n_steps > MOUSEPAD_UNDO_MAX_STEPS);
- /* allocate slice */
- step = g_slice_new0 (MousepadUndoStep);
+ /* number of steps to remove */
+ to_remove = undo->n_steps - MOUSEPAD_UNDO_MAX_STEPS;
- /* set step data */
- step->action = undo->cache.action;
- step->start = undo->cache.start;
- step->end = undo->cache.end;
- step->in_group = undo->cache.in_group;
-
- if (step->action == DELETE)
- {
- /* set the step string and allocate a new one */
- step->data = g_string_free (undo->cache.string, FALSE);
- undo->cache.string = NULL;
- }
- else
+ /* get end of steps list and remove the entire group */
+ for (li = g_list_last (undo->steps); li != NULL; li = lprev)
{
- /* set the data to null on insert actions */
- step->data = NULL;
+ step = li->data;
+
+ /* update counters */
+ if (step->in_group == FALSE)
+ {
+ if (to_remove == 0)
+ break;
+
+ /* update counter */
+ to_remove--;
+ undo->n_steps--;
+ }
+
+ /* cleanup */
+ mousepad_undo_step_free (step);
+
+ /* previous step */
+ lprev = li->prev;
+
+ /* remove from list */
+ undo->steps = g_list_delete_link (undo->steps, li);
}
+}
- /* prepend the new step */
- undo->steps = g_list_prepend (undo->steps, step);
- /* reset the needle */
- undo->needle = undo->steps;
- /* reset the cache */
- undo->cache.start = undo->cache.end = -1;
- undo->cache.is_space = FALSE;
- undo->cache.in_group = FALSE;
+static void
+mousepad_undo_cache_reset (MousepadUndo *undo)
+{
+ _mousepad_return_if_fail (undo->cache == NULL);
+
+ /* reset variables */
+ undo->cache_start = undo->cache_end = -1;
+ undo->cache_in_group = FALSE;
+ undo->cache_is_space = FALSE;
+ undo->cache_points = 0;
}
static void
-mousepad_undo_cache_reset_needle (MousepadUndo *undo)
+mousepad_undo_cache_to_step (MousepadUndo *undo)
{
- gint i;
+ MousepadUndoStep *step;
- /* make sure the needle is the start of the list */
- if (undo->needle != undo->steps)
+ /* only add when the cache contains changes */
+ if (G_LIKELY (undo->cache_start != undo->cache_end))
{
- /* walk from the start to the needle and remove them */
- for (i = g_list_position (undo->steps, undo->needle); i > 0; i--)
- mousepad_undo_step_free (g_list_first (undo->steps)->data, undo);
+ /* make sure the needle has been reset */
+ _mousepad_return_if_fail (undo->needle == undo->steps);
+
+ /* allocate slice */
+ step = g_slice_new0 (MousepadUndoStep);
+
+ /* set data */
+ step->action = undo->cache_action;
+ step->start = undo->cache_start;
+ step->end = undo->cache_end;
+ step->in_group = undo->cache_in_group;
+
+ /* increase real step counter */
+ if (step->in_group == FALSE)
+ if (++undo->n_steps > MOUSEPAD_UNDO_MAX_STEPS)
+ mousepad_undo_clear_oldest_step (undo);
+
+ if (step->action == DELETE)
+ {
+ /* free cache and set the data */
+ step->data = g_string_free (undo->cache, FALSE);
+
+ /* null the cache */
+ undo->cache = NULL;
+ }
+ else
+ {
+ /* null the data */
+ step->data = NULL;
+ }
+
+ /* prepend the new step */
+ undo->needle = undo->steps = g_list_prepend (undo->steps, step);
- /* check needle */
- _mousepad_return_if_fail (undo->needle == undo->needle);
+ /* reset the cache */
+ mousepad_undo_cache_reset (undo);
}
+
+ g_message ("%d steps", undo->n_steps);
}
static void
-mousepad_undo_cache_update (MousepadUndo *undo,
- MousepadUndoAction action,
- gint start,
- gint end,
- const gchar *text)
+mousepad_undo_needle_reset (MousepadUndo *undo)
{
- gint length;
- guchar c;
+ MousepadUndoStep *step;
+
+ /* remove steps from the list until we reach the needle */
+ while (undo->steps != undo->needle)
+ {
+ step = undo->steps->data;
- /* length of the text */
- length = ABS (end - start);
+ /* decrease real step counter */
+ if (step->in_group == FALSE)
+ undo->n_steps--;
- /* initialize the cache, if not already done */
- if (undo->cache.string == NULL && action == DELETE)
- undo->cache.string = g_string_sized_new (DEFAULT_CACHE_SIZE);
+ /* free the step data */
+ mousepad_undo_step_free (step);
+
+ /* delete the element from the list */
+ undo->steps = g_list_delete_link (undo->steps, undo->steps);
+ }
+
+ /* debug check */
+ _mousepad_return_if_fail (undo->needle == undo->steps);
+}
- /* check if we should start a new step before handling this one */
+
+
+static void
+mousepad_undo_buffer_changed (MousepadUndo *undo,
+ MousepadUndoAction action,
+ const gchar *text,
+ gint length,
+ gint start_offset,
+ gint end_offset)
+{
+ gunichar c;
+ gboolean is_space, is_newline;
+
+ /* when grouping is 0 we going to detect if it's needed to create a
+ * new step (existing data in buffer, points, etc). when grouping is
+ * > 0 it means we're already inside a group and thus merge as much
+ * as possible. */
if (undo->grouping == 0)
{
- if (undo->cache.in_group == TRUE)
+ if (length > 1 || undo->cache_in_group)
{
- /* force a new step if the new step is not part of a group and the
- * content in the cache is */
- goto force_new_step;
+ /* the buffer contains still data from a grouped step or more then one
+ * character has been changed. in this case we always create a new step */
+ goto create_new_step;
}
- else if (length == 1)
+ else /* single char changed */
{
- /* get the character */
+ /* get the changed character */
c = g_utf8_get_char (text);
- /* detect if the character is a word breaking char */
- if (g_unichar_isspace (c))
- {
- /* the char is a word breaker. we don't care if the previous
- * one was one too, because we merge multiple spaces/tabs/newlines
- * into one step */
- undo->cache.is_space = TRUE;
- }
- else if (undo->cache.is_space)
+ /* if the character is a space */
+ is_space = g_unichar_isspace (c);
+
+ /* when the maximum number of points has been passed and the
+ * last charater in the buffer differs from the new one, we
+ * force a new step */
+ if (undo->cache_points > MOUSEPAD_UNDO_POINTS
+ && undo->cache_is_space != is_space)
{
- /* the new character is not a work breaking char, but the
- * previous one was, force a new step */
- goto force_new_step;
+ goto create_new_step;
}
- }
- else
- {
- /* grouping is not enabled and multiple chars are inseted or
- * deleted, force a new step */
- goto force_new_step;
+
+ /* set the new last character type */
+ undo->cache_is_space = is_space;
+
+ /* if the changed character is a new line */
+ is_newline = (c == '\n' || c == '\r');
+
+ /* update the point statistics */
+ if (is_newline)
+ undo->cache_points += MOUSEPAD_UNDO_POINTS_NEW_LINE;
+ else if (is_space)
+ undo->cache_points += MOUSEPAD_UNDO_POINTS_WORD_BREAK;
+ else
+ undo->cache_points += MOUSEPAD_UNDO_POINTS_CHAR;
}
}
- /* handle the buffer change and try to append it to the cache */
- if (undo->cache.action == action
+ /* try to merge the new change with the buffer. if this is not possible
+ * new put the cache in a new step and insert the last change in the buffer */
+ if (undo->cache_action == action
&& action == INSERT
- && undo->cache.end == start)
+ && undo->cache_end == start_offset)
{
- /* we can append with the previous insert change, update end postion */
- undo->cache.end = end;
+ /* we can merge with the previous insert */
+ undo->cache_end = end_offset;
}
- else if (undo->cache.action == action
+ else if (undo->cache_action == action
&& action == DELETE
- && undo->cache.start == end)
+ && undo->cache_start == end_offset)
{
- /* we can append with the previous delete change, update */
- undo->cache.start = start;
+ /* we can merge with the previous delete */
+ undo->cache_start = start_offset;
+
+ /* label */
+ prepend_deleted_text:
+
+ /* create a new cache if needed */
+ if (undo->cache == NULL)
+ undo->cache = g_string_sized_new (MOUSEPAD_UNDO_BUFFER_SIZE);
/* prepend removed characters */
- undo->cache.string = g_string_prepend_len (undo->cache.string, text, length);
+ undo->cache = g_string_prepend_len (undo->cache, text, length);
}
else
{
/* label */
- force_new_step:
+ create_new_step:
- /* reset the needle */
- mousepad_undo_cache_reset_needle (undo);
+ /* reset the needle of the steps list */
+ mousepad_undo_needle_reset (undo);
- /* we cannot cache with the previous change, put the cache into a step */
+ /* put the cache in a new step */
mousepad_undo_cache_to_step (undo);
- /* start a new cache */
- undo->cache.action = action;
- undo->cache.start = start;
- undo->cache.end = end;
- undo->cache.in_group = (undo->grouping > 0);
+ /* set the new cache variables */
+ undo->cache_start = start_offset;
+ undo->cache_end = end_offset;
+ undo->cache_action = action;
+ undo->cache_is_space = FALSE;
+ undo->cache_in_group = (undo->grouping > 0);
+ /* prepend deleted text */
if (action == DELETE)
- {
- undo->cache.string = g_string_sized_new (DEFAULT_CACHE_SIZE);
- undo->cache.string = g_string_prepend_len (undo->cache.string, text, length);
- }
+ goto prepend_deleted_text;
}
/* increase the grouping counter */
undo->grouping++;
- /* stuff has been added to the cache, so we can undo now */
- if (undo->can_undo != TRUE)
- {
- undo->can_undo = TRUE;
-
- /* emit the can-undo signal */
- g_signal_emit (G_OBJECT (undo), undo_signals[CAN_UNDO], 0, undo->can_undo);
- }
+ /* emit signals */
+ mousepad_undo_emit_signals (undo);
}
@@ -566,21 +651,22 @@ mousepad_undo_buffer_insert (GtkTextBuffer *buffer,
gint length,
MousepadUndo *undo)
{
- gint start, end;
+ gint start_pos, end_pos;
_mousepad_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
_mousepad_return_if_fail (buffer == undo->buffer);
/* leave when locked */
- if (G_UNLIKELY (undo->locked > 0))
- return;
-
- /* buffer positions */
- start = gtk_text_iter_get_offset (pos);
- end = start + length;
+ if (G_LIKELY (undo->locked == 0))
+ {
+ /* buffer positions */
+ start_pos = gtk_text_iter_get_offset (pos);
+ end_pos = start_pos + length;
- /* update the cache */
- mousepad_undo_cache_update (undo, INSERT, start, end, text);
+ /* handle the change */
+ mousepad_undo_buffer_changed (undo, INSERT, text,
+ length, start_pos, end_pos);
+ }
}
@@ -592,29 +678,33 @@ mousepad_undo_buffer_delete (GtkTextBuffer *buffer,
MousepadUndo *undo)
{
gchar *text;
- gint start, end;
+ gint start_pos, end_pos;
_mousepad_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
_mousepad_return_if_fail (buffer == undo->buffer);
- /* leave when locked */
- if (G_UNLIKELY (undo->locked > 0))
- return;
-
- /* get the removed string */
- text = gtk_text_buffer_get_slice (buffer, start_iter, end_iter, FALSE);
+ /* no nothing when locked */
+ if (G_LIKELY (undo->locked == 0))
+ {
+ /* get the removed string */
+ text = gtk_text_buffer_get_slice (buffer, start_iter, end_iter, FALSE);
- /* buffer positions */
- start = gtk_text_iter_get_offset (start_iter);
- end = gtk_text_iter_get_offset (end_iter);
+ /* buffer positions */
+ start_pos = gtk_text_iter_get_offset (start_iter);
+ end_pos = gtk_text_iter_get_offset (end_iter);
- /* update the cache */
- mousepad_undo_cache_update (undo, DELETE, start, end, text);
+ /* handle the change */
+ mousepad_undo_buffer_changed (undo, DELETE, text,
+ ABS (start_pos - end_pos),
+ start_pos, end_pos);
- /* cleanup */
- g_free (text);
+ /* cleanup */
+ g_free (text);
+ }
}
+
+
static void
mousepad_undo_buffer_begin_user_action (GtkTextBuffer *buffer,
MousepadUndo *undo)
@@ -622,15 +712,16 @@ mousepad_undo_buffer_begin_user_action (GtkTextBuffer *buffer,
_mousepad_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
_mousepad_return_if_fail (buffer == undo->buffer);
- /* leave when locked */
- if (G_UNLIKELY (undo->locked > 0))
- return;
-
- /* reset the grouping couter */
- undo->grouping = 0;
+ /* only reset the group counter when not locked */
+ if (G_LIKELY (undo->locked == 0))
+ {
+ /* reset the grouping counter */
+ undo->grouping = 0;
+ }
}
+
MousepadUndo *
mousepad_undo_new (GtkTextBuffer *buffer)
{
@@ -665,19 +756,21 @@ mousepad_undo_clear (MousepadUndo *undo)
mousepad_undo_lock (undo);
/* clear cache string */
- if (G_LIKELY (undo->cache.string))
- g_string_free (undo->cache.string, TRUE);
+ if (G_LIKELY (undo->cache))
+ g_string_free (undo->cache, TRUE);
/* cleanup the undo steps */
for (li = undo->steps; li != NULL; li = li->next)
- mousepad_undo_step_free (li->data, undo);
+ mousepad_undo_step_free (li->data);
/* free the list */
g_list_free (undo->steps);
/* null */
- undo->steps = undo->needle = NULL;
- undo->cache.string = NULL;
+ undo->steps = undo->needle = undo->saved = NULL;
+ undo->cache = NULL;
+ undo->n_steps = 0;
+ mousepad_undo_cache_reset (undo);
/* release lock */
mousepad_undo_unlock (undo);
@@ -708,6 +801,26 @@ mousepad_undo_unlock (MousepadUndo *undo)
+void
+mousepad_undo_save_point (MousepadUndo *undo)
+{
+ _mousepad_return_if_fail (MOUSEPAD_IS_UNDO (undo));
+
+ /* reset the needle */
+ mousepad_undo_needle_reset (undo);
+
+ /* make sure the buffer is flushed */
+ mousepad_undo_cache_to_step (undo);
+
+ /* store the current needle position */
+ undo->saved = undo->needle;
+
+ /* TODO remove */
+ g_message ("store save point");
+}
+
+
+
gboolean
mousepad_undo_can_undo (MousepadUndo *undo)
{
@@ -735,7 +848,7 @@ mousepad_undo_do_undo (MousepadUndo *undo)
_mousepad_return_if_fail (mousepad_undo_can_undo (undo));
/* undo the last step */
- mousepad_undo_step_perform (undo, FALSE);
+ mousepad_undo_step (undo, FALSE);
}
@@ -747,5 +860,5 @@ mousepad_undo_do_redo (MousepadUndo *undo)
_mousepad_return_if_fail (mousepad_undo_can_redo (undo));
/* redo the last undo-ed step */
- mousepad_undo_step_perform (undo, TRUE);
+ mousepad_undo_step (undo, TRUE);
}
diff --git a/mousepad/mousepad-undo.h b/mousepad/mousepad-undo.h
index 2e37977..9a92d90 100644
--- a/mousepad/mousepad-undo.h
+++ b/mousepad/mousepad-undo.h
@@ -40,6 +40,8 @@ void mousepad_undo_lock (MousepadUndo *undo);
void mousepad_undo_unlock (MousepadUndo *undo);
+void mousepad_undo_save_point (MousepadUndo *undo);
+
gboolean mousepad_undo_can_undo (MousepadUndo *undo);
gboolean mousepad_undo_can_redo (MousepadUndo *undo);
diff --git a/mousepad/mousepad-util.c b/mousepad/mousepad-util.c
index 947507e..fdb2281 100644
--- a/mousepad/mousepad-util.c
+++ b/mousepad/mousepad-util.c
@@ -473,7 +473,7 @@ mousepad_util_dialog_header (GtkDialog *dialog,
}
-
+#if !GTK_CHECK_VERSION (2,12,0)
void
mousepad_util_set_tooltip (GtkWidget *widget,
const gchar *string)
@@ -490,7 +490,7 @@ mousepad_util_set_tooltip (GtkWidget *widget,
/* setup the tooltip for the widget */
gtk_tooltips_set_tip (tooltips, widget, string, NULL);
}
-
+#endif
gint
diff --git a/mousepad/mousepad-util.h b/mousepad/mousepad-util.h
index 687b415..bd5d20a 100644
--- a/mousepad/mousepad-util.h
+++ b/mousepad/mousepad-util.h
@@ -91,8 +91,10 @@ void mousepad_util_dialog_header (GtkDialog *dialog,
const gchar *subtitle,
const gchar *icon);
+#if !GTK_CHECK_VERSION (2,12,0)
void mousepad_util_set_tooltip (GtkWidget *widget,
const gchar *string);
+#endif
gint mousepad_util_get_real_line_offset (const GtkTextIter *iter,
gint tab_size);
diff --git a/mousepad/mousepad-window.c b/mousepad/mousepad-window.c
index 34ba8a4..3fa577a 100644
--- a/mousepad/mousepad-window.c
+++ b/mousepad/mousepad-window.c
@@ -104,8 +104,9 @@ static gboolean mousepad_window_close_document (MousepadW
static void mousepad_window_set_title (MousepadWindow *window);
/* notebook signals */
-static void mousepad_window_notebook_notified (GtkNotebook *notebook,
- GParamSpec *pspec,
+static void mousepad_window_notebook_switch_page (GtkNotebook *notebook,
+ GtkNotebookPage *page,
+ guint page_num,
MousepadWindow *window);
static void mousepad_window_notebook_reordered (GtkNotebook *notebook,
GtkWidget *page,
@@ -689,7 +690,7 @@ mousepad_window_init (MousepadWindow *window)
#endif
/* connect signals to the notebooks */
- g_signal_connect (G_OBJECT (window->notebook), "notify::page", G_CALLBACK (mousepad_window_notebook_notified), window);
+ g_signal_connect (G_OBJECT (window->notebook), "switch-page", G_CALLBACK (mousepad_window_notebook_switch_page), window);
g_signal_connect (G_OBJECT (window->notebook), "page-reordered", G_CALLBACK (mousepad_window_notebook_reordered), window);
g_signal_connect (G_OBJECT (window->notebook), "page-added", G_CALLBACK (mousepad_window_notebook_added), window);
g_signal_connect (G_OBJECT (window->notebook), "page-removed", G_CALLBACK (mousepad_window_notebook_removed), window);
@@ -710,6 +711,7 @@ mousepad_window_init (MousepadWindow *window)
/* allow drops in the window */
gtk_drag_dest_set (GTK_WIDGET (window), GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, drop_targets, G_N_ELEMENTS (drop_targets), GDK_ACTION_COPY | GDK_ACTION_MOVE);
g_signal_connect (G_OBJECT (window), "drag-data-received", G_CALLBACK (mousepad_window_drag_data_received), window);
+
}
@@ -1136,6 +1138,9 @@ mousepad_window_add (MousepadWindow *window,
_mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
_mousepad_return_if_fail (GTK_IS_NOTEBOOK (window->notebook));
+ /* get the active tab before we switch to the new one */
+ prev_active = window->active;
+
/* create the tab label */
label = mousepad_document_get_tab_label (document);
@@ -1152,21 +1157,21 @@ mousepad_window_add (MousepadWindow *window,
/* show the document */
gtk_widget_show (GTK_WIDGET (document));
- /* get the active tab before we switch to the new one */
- prev_active = window->active;
-
- /* switch to the new tab */
- gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), page);
+ /* don't bother about this when there was no previous active page (startup) */
+ if (G_LIKELY (prev_active != NULL))
+ {
+ /* switch to the new tab */
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), page);
+
+ /* destroy the previous tab if it was not modified, untitled and the new tab is not untitled */
+ if (gtk_text_buffer_get_modified (prev_active->buffer) == FALSE
+ && mousepad_file_get_filename (prev_active->file) == NULL
+ && mousepad_file_get_filename (document->file) != NULL)
+ gtk_widget_destroy (GTK_WIDGET (prev_active));
+ }
/* make sure the textview is focused in the new document */
mousepad_document_focus_textview (document);
-
- /* destroy the previous tab if it was not modified, untitled and the new tab is not untitled */
- if (prev_active != NULL
- && gtk_text_buffer_get_modified (prev_active->buffer) == FALSE
- && mousepad_file_get_filename (prev_active->file) == NULL
- && mousepad_file_get_filename (document->file) != NULL)
- gtk_widget_destroy (GTK_WIDGET (prev_active));
}
@@ -1265,31 +1270,34 @@ mousepad_window_set_title (MousepadWindow *window)
* Notebook Signal Functions
**/
static void
-mousepad_window_notebook_notified (GtkNotebook *notebook,
- GParamSpec *pspec,
- MousepadWindow *window)
+mousepad_window_notebook_switch_page (GtkNotebook *notebook,
+ GtkNotebookPage *page,
+ guint page_num,
+ MousepadWindow *window)
{
- gint page_num;
+ MousepadDocument *document;
_mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
-
- /* get the current page */
- page_num = gtk_notebook_get_current_page (notebook);
+ _mousepad_return_if_fail (GTK_IS_NOTEBOOK (notebook));
/* get the new active document */
- if (G_LIKELY (page_num != -1))
- window->active = MOUSEPAD_DOCUMENT (gtk_notebook_get_nth_page (notebook, page_num));
- else
- g_assert_not_reached ();
+ document = MOUSEPAD_DOCUMENT (gtk_notebook_get_nth_page (notebook, page_num));
- /* set the window title */
- mousepad_window_set_title (window);
+ /* only update when really changed */
+ if (G_LIKELY (window->active != document))
+ {
+ /* set new active document */
+ window->active = document;
+
+ /* set the window title */
+ mousepad_window_set_title (window);
- /* update the menu actions */
- mousepad_window_update_actions (window);
+ /* update the menu actions */
+ mousepad_window_update_actions (window);
- /* update the statusbar */
- mousepad_document_send_signals (window->active);
+ /* update the statusbar */
+ mousepad_document_send_signals (window->active);
+ }
}
@@ -3278,7 +3286,12 @@ mousepad_window_action_save (GtkAction *action,
/* update the window title */
mousepad_window_set_title (window);
- if (G_UNLIKELY (succeed == FALSE))
+ if (G_LIKELY (succeed))
+ {
+ /* store the save state in the undo manager */
+ mousepad_undo_save_point (document->undo);
+ }
+ else
{
/* show the error */
mousepad_dialogs_show_error (GTK_WINDOW (window), error, _("Failed to save the document"));
@@ -3390,9 +3403,16 @@ mousepad_window_action_save_all (GtkAction *action,
/* try to save the file */
succeed = mousepad_file_save (MOUSEPAD_DOCUMENT (document)->file, &error);
- /* break on problems */
- if (G_UNLIKELY (succeed == FALSE))
- break;
+ if (G_LIKELY (succeed))
+ {
+ /* store save state */
+ mousepad_undo_save_point (MOUSEPAD_DOCUMENT (document)->undo);
+ }
+ else
+ {
+ /* break on problems */
+ break;
+ }
}
}
@@ -3854,20 +3874,31 @@ mousepad_window_action_find_previous (GtkAction *action,
}
+static void
+mousepad_window_action_replace_switch_page (MousepadWindow *window)
+{
+ _mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+ _mousepad_return_if_fail (MOUSEPAD_IS_REPLACE_DIALOG (window->replace_dialog));
+ _mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+ /* page switched */
+ mousepad_replace_dialog_page_switched (MOUSEPAD_REPLACE_DIALOG (window->replace_dialog));
+}
+
static void
mousepad_window_action_replace_destroy (MousepadWindow *window)
{
_mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
- /* TODO disconnect tab switch signal */
+ /* disconnect tab switch signal */
+ g_signal_handlers_disconnect_by_func (G_OBJECT (window->notebook), mousepad_window_action_replace_switch_page, window);
/* reset the dialog variable */
window->replace_dialog = NULL;
}
-
static void
mousepad_window_action_replace (GtkAction *action,
MousepadWindow *window)
@@ -3888,13 +3919,12 @@ mousepad_window_action_replace (GtkAction *action,
/* connect signals */
g_signal_connect_swapped (G_OBJECT (window->replace_dialog), "destroy", G_CALLBACK (mousepad_window_action_replace_destroy), window);
g_signal_connect_swapped (G_OBJECT (window->replace_dialog), "search", G_CALLBACK (mousepad_window_search), window);
-
- /* TODO tab switch update signal */
+ g_signal_connect_swapped (G_OBJECT (window->notebook), "switch-page", G_CALLBACK (mousepad_window_action_replace_switch_page), window);
}
else
{
/* focus the existing dialog */
- gtk_widget_grab_focus (window->replace_dialog);
+ gtk_window_present (GTK_WINDOW (window->replace_dialog));
}
}
More information about the Xfce4-commits
mailing list