[gtk/wip/otte/undo: 4/17] undo: Actually implement undo



commit 130625662887d23f480b398645bff064acaa675a
Author: Benjamin Otte <otte redhat com>
Date:   Thu Aug 6 02:10:47 2015 +0200

    undo: Actually implement undo

 gtk/Makefile.am                 |   2 +
 gtk/gtkundostack.c              |  60 ++++++++++++++--
 gtk/gtkundoundocommand.c        | 151 ++++++++++++++++++++++++++++++++++++++++
 gtk/gtkundoundocommandprivate.h |  56 +++++++++++++++
 4 files changed, 262 insertions(+), 7 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 6d404e4d58..d1b05a8cc3 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -532,6 +532,7 @@ gtk_private_h_sources =             \
        gtktreeprivate.h        \
        gtkundocommandprivate.h \
        gtkundostackprivate.h   \
+       gtkundoundocommandprivate.h     \
        gtkwidgetprivate.h      \
        gtkwin32themeprivate.h  \
        gtkwindowprivate.h      \
@@ -866,6 +867,7 @@ gtk_base_c_sources =                \
        gtktypebuiltins.c       \
        gtkundocommand.c        \
        gtkundostack.c          \
+       gtkundoundocommand.c    \
        gtkvolumebutton.c       \
        gtkviewport.c           \
        gtkwidget.c             \
diff --git a/gtk/gtkundostack.c b/gtk/gtkundostack.c
index 2cdc81a76b..3b6a358499 100644
--- a/gtk/gtkundostack.c
+++ b/gtk/gtkundostack.c
@@ -24,6 +24,8 @@
 #include <glib/gi18n-lib.h>
 #include <gio/gio.h>
 
+#include "gtkundoundocommandprivate.h"
+
 typedef struct _GtkUndoStackPrivate GtkUndoStackPrivate;
 struct _GtkUndoStackPrivate {
   GSequence *commands;          /* latest added command is at front of queue */
@@ -132,27 +134,71 @@ gtk_undo_stack_clear (GtkUndoStack *stack)
   g_list_model_items_changed (G_LIST_MODEL (stack), 0, len, 0);
 }
 
-void
-gtk_undo_stack_push (GtkUndoStack   *stack,
-                     GtkUndoCommand *command)
+static void
+gtk_undo_stack_push_internal (GtkUndoStack   *stack,
+                              GtkUndoCommand *command,
+                              gboolean        replace)
 {
   GtkUndoStackPrivate *priv = gtk_undo_stack_get_instance_private (stack);
 
-  g_return_if_fail (GTK_IS_UNDO_STACK (stack));
-  g_return_if_fail (GTK_IS_UNDO_COMMAND (command));
+  if (replace)
+    g_sequence_remove (g_sequence_get_begin_iter (priv->commands));
 
   g_object_ref (command);
   g_sequence_prepend (priv->commands, command);
 
-  g_list_model_items_changed (G_LIST_MODEL (stack), 0, 0, 1);
+  g_list_model_items_changed (G_LIST_MODEL (stack), 0, replace ? 1 : 0, 1);
+}
+
+void
+gtk_undo_stack_push (GtkUndoStack   *stack,
+                     GtkUndoCommand *command)
+{
+  g_return_if_fail (GTK_IS_UNDO_STACK (stack));
+  g_return_if_fail (GTK_IS_UNDO_COMMAND (command));
+
+  gtk_undo_stack_push_internal (stack, command, FALSE);
 }
 
 gboolean
 gtk_undo_stack_undo (GtkUndoStack *stack)
 {
+  GtkUndoStackPrivate *priv = gtk_undo_stack_get_instance_private (stack);
+  GtkUndoCommand *command, *undo;
+  GSequenceIter *begin_iter, *end_iter;
+  gboolean replace = FALSE;
+
   g_return_val_if_fail (GTK_IS_UNDO_STACK (stack), FALSE);
 
-  return FALSE;
+  begin_iter = g_sequence_get_begin_iter (priv->commands);
+  if (g_sequence_iter_is_end (begin_iter))
+    return FALSE;
+
+  undo = g_sequence_get (begin_iter);
+
+  if (GTK_IS_UNDO_UNDO_COMMAND (undo))
+    {
+      begin_iter = g_sequence_iter_next (begin_iter);
+      end_iter = g_sequence_iter_move (begin_iter, gtk_undo_undo_command_get_n_items (GTK_UNDO_UNDO_COMMAND 
(undo)));
+      if (g_sequence_iter_is_end (end_iter))
+        return FALSE;
+
+      undo = g_sequence_get (end_iter);
+      end_iter = g_sequence_iter_next (end_iter);
+      replace = TRUE;
+    }
+  else
+    {
+      end_iter = g_sequence_iter_next (begin_iter);
+      replace = FALSE;
+    }
+
+  gtk_undo_command_undo (undo);
+  command = gtk_undo_undo_command_new (begin_iter, end_iter);
+  gtk_undo_stack_push_internal (stack, command, replace);
+  g_object_unref (command);
+
+  return TRUE;
 }
 
 gboolean
diff --git a/gtk/gtkundoundocommand.c b/gtk/gtkundoundocommand.c
new file mode 100644
index 0000000000..0c119c9d0b
--- /dev/null
+++ b/gtk/gtkundoundocommand.c
@@ -0,0 +1,151 @@
+/*
+ * 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 "gtkundoundocommandprivate.h"
+
+#include <glib/gi18n-lib.h>
+
+typedef struct _GtkUndoUndoCommandPrivate GtkUndoUndoCommandPrivate;
+struct _GtkUndoUndoCommandPrivate {
+  GSequence *commands;          /* sequence of GtkUndoCommand, first to undo command first */
+};
+
+G_DEFINE_TYPE_WITH_CODE (GtkUndoUndoCommand, gtk_undo_undo_command, GTK_TYPE_UNDO_COMMAND,
+                         G_ADD_PRIVATE (GtkUndoUndoCommand))
+
+static gboolean
+gtk_undo_undo_command_undo (GtkUndoCommand *command)
+{
+  GtkUndoUndoCommandPrivate *priv = gtk_undo_undo_command_get_instance_private (GTK_UNDO_UNDO_COMMAND 
(command));
+  GSequenceIter *iter;
+  gboolean result;
+
+  result = FALSE;
+
+  for (iter = g_sequence_get_begin_iter (priv->commands);
+       !g_sequence_iter_is_end (iter);
+       iter = g_sequence_iter_next (iter))
+    {
+      result |= gtk_undo_command_redo (g_sequence_get (iter));
+    }
+
+  return result;
+}
+
+gboolean
+gtk_undo_undo_command_redo (GtkUndoCommand *command)
+{
+  GtkUndoUndoCommandPrivate *priv = gtk_undo_undo_command_get_instance_private (GTK_UNDO_UNDO_COMMAND 
(command));
+  GSequenceIter *iter;
+  gboolean result;
+
+  result = FALSE;
+
+  iter = g_sequence_get_end_iter (priv->commands);
+  while (!g_sequence_iter_is_begin (iter))
+    {
+      iter = g_sequence_iter_prev (iter);
+
+      result |= gtk_undo_command_undo (g_sequence_get (iter));
+    }
+
+  return result;
+}
+
+GtkUndoCommand *
+gtk_undo_undo_command_merge (GtkUndoCommand *command,
+                             GtkUndoCommand *followup)
+{
+  return NULL;
+}
+
+char *
+gtk_undo_undo_command_describe (GtkUndoCommand *command)
+{
+  GtkUndoUndoCommandPrivate *priv = gtk_undo_undo_command_get_instance_private (GTK_UNDO_UNDO_COMMAND 
(command));
+
+  return g_strdup_printf (_("Undo last %u commands"), g_sequence_get_length (priv->commands));
+}
+
+static void
+gtk_undo_undo_command_finalize (GObject *object)
+{
+  GtkUndoUndoCommandPrivate *priv = gtk_undo_undo_command_get_instance_private (GTK_UNDO_UNDO_COMMAND 
(object));
+
+  g_sequence_free (priv->commands);
+
+  G_OBJECT_CLASS (gtk_undo_undo_command_parent_class)->finalize (object);
+}
+
+static void
+gtk_undo_undo_command_class_init (GtkUndoUndoCommandClass *klass)
+{
+  GtkUndoCommandClass *undo_class = GTK_UNDO_COMMAND_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gtk_undo_undo_command_finalize;
+
+  undo_class->undo = gtk_undo_undo_command_undo;
+  undo_class->redo = gtk_undo_undo_command_redo;
+  undo_class->merge = gtk_undo_undo_command_merge;
+  undo_class->describe = gtk_undo_undo_command_describe;
+}
+
+static void
+gtk_undo_undo_command_init (GtkUndoUndoCommand *command)
+{
+  GtkUndoUndoCommandPrivate *priv = gtk_undo_undo_command_get_instance_private (GTK_UNDO_UNDO_COMMAND 
(command));
+
+  priv->commands = g_sequence_new (g_object_unref);
+}
+
+GtkUndoCommand *
+gtk_undo_undo_command_new (GSequenceIter *begin_iter,
+                           GSequenceIter *end_iter)
+{
+  GtkUndoUndoCommand *result;
+  GtkUndoUndoCommandPrivate *priv;
+  GSequenceIter *iter;
+
+  g_return_val_if_fail (begin_iter != NULL, NULL);
+  g_return_val_if_fail (end_iter != NULL, NULL);
+
+  result = g_object_new (GTK_TYPE_UNDO_UNDO_COMMAND, NULL);
+
+  priv = gtk_undo_undo_command_get_instance_private (result);
+  for (iter = begin_iter; iter != end_iter; iter = g_sequence_iter_next (iter))
+    {
+      g_sequence_prepend (priv->commands, g_object_ref (g_sequence_get (iter)));
+    }
+
+  return GTK_UNDO_COMMAND (result);
+}
+
+guint
+gtk_undo_undo_command_get_n_items (GtkUndoUndoCommand *command)
+{
+  GtkUndoUndoCommandPrivate *priv = gtk_undo_undo_command_get_instance_private (GTK_UNDO_UNDO_COMMAND 
(command));
+
+  g_return_val_if_fail (GTK_IS_UNDO_UNDO_COMMAND (command), 0);
+
+  return g_sequence_get_length (priv->commands);
+}
+
diff --git a/gtk/gtkundoundocommandprivate.h b/gtk/gtkundoundocommandprivate.h
new file mode 100644
index 0000000000..530720f9fc
--- /dev/null
+++ b/gtk/gtkundoundocommandprivate.h
@@ -0,0 +1,56 @@
+/*
+ * 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_UNDO_COMMAND_PRIVATE_H__
+#define __GTK_UNDO_UNDO_COMMAND_PRIVATE_H__
+
+#include <gtk/gtkundocommandprivate.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_UNDO_UNDO_COMMAND           (gtk_undo_undo_command_get_type ())
+#define GTK_UNDO_UNDO_COMMAND(obj)           (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_UNDO_UNDO_COMMAND, 
GtkUndoUndoCommand))
+#define GTK_UNDO_UNDO_COMMAND_CLASS(cls)     (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_UNDO_UNDO_COMMAND, 
GtkUndoUndoCommandClass))
+#define GTK_IS_UNDO_UNDO_COMMAND(obj)        (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_UNDO_UNDO_COMMAND))
+#define GTK_IS_UNDO_UNDO_COMMAND_CLASS(obj)  (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_UNDO_UNDO_COMMAND))
+#define GTK_UNDO_UNDO_COMMAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_UNDO_UNDO_COMMAND, 
GtkUndoUndoCommandClass))
+
+typedef struct _GtkUndoUndoCommand           GtkUndoUndoCommand;
+typedef struct _GtkUndoUndoCommandClass      GtkUndoUndoCommandClass;
+
+struct _GtkUndoUndoCommand
+{
+  GtkUndoCommand parent;
+};
+
+struct _GtkUndoUndoCommandClass
+{
+  GtkUndoCommandClass parent_class;
+};
+
+GType                   gtk_undo_undo_command_get_type          (void) G_GNUC_CONST;
+
+GtkUndoCommand *        gtk_undo_undo_command_new               (GSequenceIter          *begin_iter,
+                                                                 GSequenceIter          *end_iter);
+
+guint                   gtk_undo_undo_command_get_n_items       (GtkUndoUndoCommand     *command);
+
+G_END_DECLS
+
+#endif /* __GTK_UNDO_UNDO_COMMAND_PRIVATE_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]