[gtk/wip/otte/undo: 16/17] undo: Change semantics of gtk_undo_command_merge()
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/undo: 16/17] undo: Change semantics of gtk_undo_command_merge()
- Date: Mon, 18 Feb 2019 17:13:45 +0000 (UTC)
commit afb661e99265a9ac3885ef5ed7dade70f4ab7fef
Author: Benjamin Otte <otte redhat com>
Date: Sun Aug 23 18:01:26 2015 +0200
undo: Change semantics of gtk_undo_command_merge()
Merges always succeed. The fallback implementation will create a (newly
added) GtkUndoCommandChain with the 2 commands to be merged.
The merge function may still return NULL. NULL should be returned if
merging commands would create a no-op.
This is implemented in the entry command undo. You can test it by
entering a character and then typing backspace.
gtk/Makefile.am | 2 +
gtk/gtkentryundocommand.c | 5 +-
gtk/gtkundocommand.c | 4 +-
gtk/gtkundocommandchain.c | 209 +++++++++++++++++++++++++++++++++++++++
gtk/gtkundocommandchainprivate.h | 57 +++++++++++
gtk/gtkundostack.c | 19 ++--
6 files changed, 286 insertions(+), 10 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index d1b05a8cc3..17927696f0 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -530,6 +530,7 @@ gtk_private_h_sources = \
gtktooltipprivate.h \
gtktreedatalist.h \
gtktreeprivate.h \
+ gtkundocommandchainprivate.h \
gtkundocommandprivate.h \
gtkundostackprivate.h \
gtkundoundocommandprivate.h \
@@ -866,6 +867,7 @@ gtk_base_c_sources = \
gtktreeviewcolumn.c \
gtktypebuiltins.c \
gtkundocommand.c \
+ gtkundocommandchain.c \
gtkundostack.c \
gtkundoundocommand.c \
gtkvolumebutton.c \
diff --git a/gtk/gtkentryundocommand.c b/gtk/gtkentryundocommand.c
index c88570caa9..1797a10e53 100644
--- a/gtk/gtkentryundocommand.c
+++ b/gtk/gtkentryundocommand.c
@@ -195,9 +195,12 @@ gtk_entry_undo_command_merge (GtkUndoCommand *command,
GtkEntryUndoCommandPrivate *followup_priv = gtk_entry_undo_command_get_instance_private
(GTK_ENTRY_UNDO_COMMAND (followup));
if (!GTK_IS_ENTRY_UNDO_COMMAND (followup))
- return NULL;
+ return GTK_UNDO_COMMAND_CLASS (gtk_entry_undo_command_parent_class)->merge (command, followup);
if (command_priv->entry != followup_priv->entry)
+ return GTK_UNDO_COMMAND_CLASS (gtk_entry_undo_command_parent_class)->merge (command, followup);
+
+ if (g_str_equal (command_priv->before.text, followup_priv->after.text))
return NULL;
return gtk_entry_undo_command_new_from_snapshots (command_priv->entry,
diff --git a/gtk/gtkundocommand.c b/gtk/gtkundocommand.c
index b7fc36683d..01241454e2 100644
--- a/gtk/gtkundocommand.c
+++ b/gtk/gtkundocommand.c
@@ -23,6 +23,8 @@
#include <glib/gi18n-lib.h>
+#include "gtkundocommandchainprivate.h"
+
typedef struct _GtkUndoCommandPrivate GtkUndoCommandPrivate;
struct _GtkUndoCommandPrivate {
gint64 timestamp;
@@ -121,7 +123,7 @@ GtkUndoCommand *
gtk_undo_command_real_merge (GtkUndoCommand *command,
GtkUndoCommand *followup)
{
- return NULL;
+ return gtk_undo_command_chain_new_merge (command, followup);
}
gboolean
diff --git a/gtk/gtkundocommandchain.c b/gtk/gtkundocommandchain.c
new file mode 100644
index 0000000000..54f9820a3e
--- /dev/null
+++ b/gtk/gtkundocommandchain.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright © 2015 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gtkundocommandchainprivate.h"
+
+#include <glib/gi18n-lib.h>
+#include <string.h>
+
+typedef struct _GtkUndoCommandChainPrivate GtkUndoCommandChainPrivate;
+
+struct _GtkUndoCommandChainPrivate {
+ GtkUndoCommand **commands;
+ gsize n_commands;
+};
+
+G_DEFINE_TYPE_WITH_CODE (GtkUndoCommandChain, gtk_undo_command_chain, GTK_TYPE_UNDO_COMMAND,
+ G_ADD_PRIVATE (GtkUndoCommandChain))
+
+static gboolean
+gtk_undo_command_chain_undo (GtkUndoCommand *command)
+{
+ GtkUndoCommandChainPrivate *priv = gtk_undo_command_chain_get_instance_private (GTK_UNDO_COMMAND_CHAIN
(command));
+ gboolean result;
+ gsize i;
+
+ result = FALSE;
+
+ for (i = priv->n_commands; i --> 0; )
+ {
+ result |= gtk_undo_command_undo (priv->commands[i]);
+ }
+
+ return result;
+}
+
+gboolean
+gtk_undo_command_chain_redo (GtkUndoCommand *command)
+{
+ GtkUndoCommandChainPrivate *priv = gtk_undo_command_chain_get_instance_private (GTK_UNDO_COMMAND_CHAIN
(command));
+ gboolean result;
+ gsize i;
+
+ result = FALSE;
+
+ for (i = 0; i < priv->n_commands; i++)
+ {
+ result |= gtk_undo_command_redo (priv->commands[i]);
+ }
+
+ return result;
+}
+
+GtkUndoCommand *
+gtk_undo_command_chain_merge (GtkUndoCommand *command,
+ GtkUndoCommand *followup)
+{
+ return gtk_undo_command_chain_new_merge (command, followup);
+}
+
+static void
+gtk_undo_command_chain_dispose (GObject *object)
+{
+ GtkUndoCommandChainPrivate *priv = gtk_undo_command_chain_get_instance_private (GTK_UNDO_COMMAND_CHAIN
(object));
+ gsize i;
+
+ for (i = 0; i < priv->n_commands; i++)
+ {
+ g_object_unref (priv->commands[i]);
+ }
+ g_free (priv->commands);
+ priv->n_commands = 0;
+
+ G_OBJECT_CLASS (gtk_undo_command_chain_parent_class)->dispose (object);
+}
+
+static void
+gtk_undo_command_chain_class_init (GtkUndoCommandChainClass *klass)
+{
+ GtkUndoCommandClass *undo_class = GTK_UNDO_COMMAND_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gtk_undo_command_chain_dispose;
+
+ undo_class->undo = gtk_undo_command_chain_undo;
+ undo_class->redo = gtk_undo_command_chain_redo;
+ undo_class->merge = gtk_undo_command_chain_merge;
+}
+
+static void
+gtk_undo_command_chain_init (GtkUndoCommandChain *command)
+{
+}
+
+/**
+ * gtk_undo_command_chain_new:
+ * @commands: (array length=n_commands): commands to chain
+ * @n_commands: number of commands
+ *
+ * Creates a new command that undoes or redoes all given @commands
+ * in order. The first command in the @commands array is the oldest
+ * command. So it is the first command to be executed during redo
+ * and the last command executed during undo.
+ *
+ * Returns: a new #GtkUndoCommand
+ */
+GtkUndoCommand *
+gtk_undo_command_chain_new (GtkUndoCommand **commands,
+ gsize n_commands)
+{
+ GtkUndoCommandChainPrivate *priv;
+ GtkUndoCommand *result;
+ char *title;
+ gsize i;
+
+ g_return_val_if_fail (commands != NULL, NULL);
+ g_return_val_if_fail (n_commands > 0, NULL);
+
+ title = g_strdup_printf (_("Execute %zu commands"), n_commands);
+ result = g_object_new (GTK_TYPE_UNDO_COMMAND_CHAIN,
+ "timestamp", gtk_undo_command_get_timestamp (commands[n_commands - 1]),
+ "title", title,
+ NULL);
+ g_free (title);
+ priv = gtk_undo_command_chain_get_instance_private (GTK_UNDO_COMMAND_CHAIN (result));
+
+ priv->commands = g_new (GtkUndoCommand *, n_commands);
+ priv->n_commands = n_commands;
+ for (i = 0; i < n_commands; i++)
+ {
+ priv->commands[i] = g_object_ref (commands[i]);
+ }
+
+ return result;
+}
+
+/**
+ * gtk_undo_command_chain_new_merge:
+ * @command: first command to merge
+ * @followup: followup command to merge
+ *
+ * Merges the two given command. This is a convenience function for use
+ * in GtkUndCommandClass::merge implementations as a fallback.
+ *
+ * Returns: A new command
+ */
+GtkUndoCommand *
+gtk_undo_command_chain_new_merge (GtkUndoCommand *command,
+ GtkUndoCommand *followup)
+{
+ GtkUndoCommand **commands, **first;
+ GtkUndoCommand *result;
+ gsize n_commands, n_first;
+
+ g_return_val_if_fail (GTK_IS_UNDO_COMMAND (command), NULL);
+ g_return_val_if_fail (GTK_IS_UNDO_COMMAND (followup), NULL);
+
+ if (GTK_IS_UNDO_COMMAND_CHAIN (command))
+ {
+ GtkUndoCommandChainPrivate *priv = gtk_undo_command_chain_get_instance_private (GTK_UNDO_COMMAND_CHAIN
(command));
+
+ n_commands = n_first = priv->n_commands;
+ first = priv->commands;
+ }
+ else
+ {
+ n_commands = n_first = 1;
+ first = &command;
+ }
+
+ if (GTK_IS_UNDO_COMMAND_CHAIN (followup))
+ {
+ GtkUndoCommandChainPrivate *priv = gtk_undo_command_chain_get_instance_private (GTK_UNDO_COMMAND_CHAIN
(followup));
+
+ n_commands += priv->n_commands;
+ commands = g_new (GtkUndoCommand *, n_commands);
+ memcpy (commands + n_first, priv->commands, sizeof (GtkUndoCommand *) * priv->n_commands);
+ }
+ else
+ {
+ n_commands++;
+ commands = g_new (GtkUndoCommand *, n_commands);
+ commands[n_first] = followup;
+ }
+ memcpy (commands, first, sizeof (GtkUndoCommand *) * n_first);
+
+ result = gtk_undo_command_chain_new (commands, n_commands);
+
+ g_free (commands);
+
+ return result;
+}
diff --git a/gtk/gtkundocommandchainprivate.h b/gtk/gtkundocommandchainprivate.h
new file mode 100644
index 0000000000..520ee9e423
--- /dev/null
+++ b/gtk/gtkundocommandchainprivate.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2015 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_UNDO_COMMAND_CHAIN_PRIVATE_H__
+#define __GTK_UNDO_COMMAND_CHAIN_PRIVATE_H__
+
+#include <gtk/gtkentry.h>
+#include <gtk/gtkundocommandprivate.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_UNDO_COMMAND_CHAIN (gtk_undo_command_chain_get_type ())
+#define GTK_UNDO_COMMAND_CHAIN(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_UNDO_COMMAND_CHAIN,
GtkUndoCommandChain))
+#define GTK_UNDO_COMMAND_CHAIN_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_UNDO_COMMAND_CHAIN,
GtkUndoCommandChainClass))
+#define GTK_IS_UNDO_COMMAND_CHAIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_UNDO_COMMAND_CHAIN))
+#define GTK_IS_UNDO_COMMAND_CHAIN_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_UNDO_COMMAND_CHAIN))
+#define GTK_UNDO_COMMAND_CHAIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
GTK_TYPE_UNDO_COMMAND_CHAIN, GtkUndoCommandChainClass))
+
+typedef struct _GtkUndoCommandChain GtkUndoCommandChain;
+typedef struct _GtkUndoCommandChainClass GtkUndoCommandChainClass;
+
+struct _GtkUndoCommandChain
+{
+ GtkUndoCommand parent;
+};
+
+struct _GtkUndoCommandChainClass
+{
+ GtkUndoCommandClass parent_class;
+};
+
+GType gtk_undo_command_chain_get_type (void) G_GNUC_CONST;
+
+GtkUndoCommand * gtk_undo_command_chain_new (GtkUndoCommand **commnds,
+ gsize n_commands);
+GtkUndoCommand * gtk_undo_command_chain_new_merge (GtkUndoCommand *command,
+ GtkUndoCommand *followup);
+
+G_END_DECLS
+
+#endif /* __GTK_UNDO_COMMAND_CHAIN_PRIVATE_H__ */
diff --git a/gtk/gtkundostack.c b/gtk/gtkundostack.c
index 5dea553ab9..4eed652e58 100644
--- a/gtk/gtkundostack.c
+++ b/gtk/gtkundostack.c
@@ -162,10 +162,15 @@ gtk_undo_stack_push_internal (GtkUndoStack *stack,
if (replace)
g_sequence_remove (g_sequence_get_begin_iter (priv->commands));
- g_object_ref (command);
- g_sequence_prepend (priv->commands, command);
+ if (command)
+ {
+ g_object_ref (command);
+ g_sequence_prepend (priv->commands, command);
+ }
- g_list_model_items_changed (G_LIST_MODEL (stack), 0, replace ? 1 : 0, 1);
+ g_list_model_items_changed (G_LIST_MODEL (stack), 0,
+ replace ? 1 : 0,
+ command ? 1 : 0);
gtk_undo_stack_dump (stack);
}
@@ -188,12 +193,10 @@ gtk_undo_stack_push (GtkUndoStack *stack,
if (gtk_undo_command_should_merge (previous, command))
{
merge = gtk_undo_command_merge (previous, command);
+ gtk_undo_stack_push_internal (stack, merge, TRUE);
if (merge)
- {
- gtk_undo_stack_push_internal (stack, merge, TRUE);
- g_object_unref (merge);
- return;
- }
+ g_object_unref (merge);
+ return;
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]