[dia/zbrown/object-change: 2/16] change: DiaObjectChange type to replace ObjectChange




commit 4b87cfe5599b71aa705fa74f91e1de01a56f1f77
Author: Zander Brown <zbrown gnome org>
Date:   Thu Oct 1 13:45:42 2020 +0100

    change: DiaObjectChange type to replace ObjectChange
    
    As ObjectChange works on objects vs diagrams we can't outright merge
    them but we can adopt a very similar architecture

 docs/dia/dia-docs.xml   |   1 +
 lib/dia-change.c        |  60 ++++++++-
 lib/dia-object-change.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/dia-object-change.h | 141 ++++++++++++++++++++
 lib/meson.build         |   2 +
 5 files changed, 546 insertions(+), 2 deletions(-)
---
diff --git a/docs/dia/dia-docs.xml b/docs/dia/dia-docs.xml
index 7c89ac316..fafb731ee 100644
--- a/docs/dia/dia-docs.xml
+++ b/docs/dia/dia-docs.xml
@@ -71,6 +71,7 @@
     <xi:include href="xml/dia_svg.xml"/>
     <xi:include href="xml/objchange.xml"/>
     <xi:include href="xml/dia-change.xml" />
+    <xi:include href="xml/dia-object-change.xml" />
     <xi:include href="xml/object-alias.xml"/>
     <xi:include href="xml/create.xml"/>
     <xi:include href="xml/diatransform.xml"/>
diff --git a/lib/dia-change.c b/lib/dia-change.c
index b216a7074..006f26d62 100644
--- a/lib/dia-change.c
+++ b/lib/dia-change.c
@@ -26,6 +26,7 @@
 #include "dia-change.h"
 #include "diagramdata.h"
 
+
 static void
 dia_change_real_apply (DiaChange   *self,
                        DiagramData *diagram)
@@ -113,7 +114,7 @@ g_value_change_peek_pointer (const GValue *value)
 }
 
 
-static gchar*
+static char *
 g_value_change_collect_value (GValue      *value,
                               guint        n_collect_values,
                               GTypeCValue *collect_values,
@@ -145,7 +146,7 @@ g_value_change_collect_value (GValue      *value,
 }
 
 
-static gchar*
+static char *
 g_value_change_lcopy_value (const GValue *value,
                             guint         n_collect_values,
                             GTypeCValue  *collect_values,
@@ -233,6 +234,16 @@ dia_change_get_type (void)
 }
 
 
+/**
+ * dia_change_ref:
+ * @self: the #DiaChange
+ *
+ * Returns: (transfer full): a new reference
+ *
+ * Since: 0.98
+ *
+ * Stability: Stable
+ */
 gpointer
 dia_change_ref (gpointer self)
 {
@@ -244,6 +255,16 @@ dia_change_ref (gpointer self)
 }
 
 
+/**
+ * dia_change_unref:
+ * @self: (transfer full): the #DiaChange
+ *
+ * Decrease the ref count of @self potentially freeing it
+ *
+ * Since: 0.98
+ *
+ * Stability: Stable
+ */
 void
 dia_change_unref (gpointer self)
 {
@@ -257,6 +278,19 @@ dia_change_unref (gpointer self)
 }
 
 
+/**
+ * dia_change_new:
+ * @type: the #DiaChange derrived #GType to instantiate
+ *
+ * Create an instance of @type, it's epected this will be used inside a
+ * constructor for @type rather than in general code
+ *
+ * Returns: (transfer full): A new #DiaChange instance
+ *
+ * Since: 0.98
+ *
+ * Stability: Stable
+ */
 gpointer
 dia_change_new (GType type)
 {
@@ -266,6 +300,17 @@ dia_change_new (GType type)
 }
 
 
+/**
+ * dia_change_apply:
+ * @self: a #DiaChange
+ * @diagram: the #DiagramData to apply @self to
+ *
+ * Do a change
+ *
+ * Since: 0.98
+ *
+ * Stability: Stable
+ */
 void
 dia_change_apply (DiaChange   *self,
                   DiagramData *diagram)
@@ -277,6 +322,17 @@ dia_change_apply (DiaChange   *self,
 }
 
 
+/**
+ * dia_change_revert:
+ * @self: a #DiaChange
+ * @diagram: the #DiagramData to revert @self from
+ *
+ * Undo a change
+ *
+ * Since: 0.98
+ *
+ * Stability: Stable
+ */
 void
 dia_change_revert (DiaChange   *self,
                    DiagramData *diagram)
diff --git a/lib/dia-object-change.c b/lib/dia-object-change.c
new file mode 100644
index 000000000..f14ce6714
--- /dev/null
+++ b/lib/dia-object-change.c
@@ -0,0 +1,344 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1999 Alexander Larsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright © 2020 Zander Brown <zbrown gnome org>
+ */
+
+#include <glib-object.h>
+#include <gobject/gvaluecollector.h>
+
+#include "dia-object-change.h"
+#include "object.h"
+
+
+static void
+dia_object_change_real_apply (DiaObjectChange *self,
+                              DiaObject       *object)
+{
+  g_critical ("%s doesn't implement apply", DIA_OBJECT_CHANGE_TYPE_NAME (self));
+}
+
+
+static void
+dia_object_change_real_revert (DiaObjectChange *self,
+                               DiaObject       *object)
+{
+  g_critical ("%s doesn't implement revert", DIA_OBJECT_CHANGE_TYPE_NAME (self));
+}
+
+
+static void
+dia_object_change_real_free (DiaObjectChange *self)
+{
+}
+
+
+static void
+dia_object_change_base_class_init (DiaObjectChangeClass *klass)
+{
+  klass->apply = dia_object_change_real_apply;
+  klass->revert = dia_object_change_real_revert;
+  klass->free = dia_object_change_real_free;
+}
+
+
+static void
+dia_object_change_class_finalize (DiaObjectChangeClass *klass)
+{
+
+}
+
+
+static void
+dia_object_change_do_class_init (DiaObjectChangeClass *klass)
+{
+}
+
+
+static void
+dia_object_change_init (DiaObjectChange      *self,
+                 DiaObjectChangeClass *klass)
+{
+  g_ref_count_init (&self->refs);
+}
+
+
+static void
+g_value_change_init (GValue *value)
+{
+  value->data[0].v_pointer = NULL;
+}
+
+
+static void
+g_value_change_free_value (GValue *value)
+{
+  if (value->data[0].v_pointer) {
+    dia_object_change_unref (value->data[0].v_pointer);
+  }
+}
+
+
+static void
+g_value_change_copy_value (const GValue *src_value,
+                           GValue       *dest_value)
+{
+  if (src_value->data[0].v_pointer) {
+    dest_value->data[0].v_pointer = dia_object_change_ref (src_value->data[0].v_pointer);
+  } else {
+    dest_value->data[0].v_pointer = NULL;
+  }
+}
+
+
+static gpointer
+g_value_change_peek_pointer (const GValue *value)
+{
+  return value->data[0].v_pointer;
+}
+
+
+static char *
+g_value_change_collect_value (GValue      *value,
+                              guint        n_collect_values,
+                              GTypeCValue *collect_values,
+                              guint        collect_flags)
+{
+  if (collect_values[0].v_pointer) {
+    DiaObjectChange *change = collect_values[0].v_pointer;
+
+    if (change->g_type_instance.g_class == NULL) {
+      return g_strconcat ("invalid unclassed change pointer for value type '",
+                          G_VALUE_TYPE_NAME (value),
+                          "'",
+                          NULL);
+    } else if (!g_value_type_compatible (DIA_OBJECT_CHANGE_TYPE (change), G_VALUE_TYPE (value))) {
+      return g_strconcat ("invalid change type '",
+                          DIA_OBJECT_CHANGE_TYPE_NAME (change),
+                          "' for value type '",
+                          G_VALUE_TYPE_NAME (value),
+                          "'",
+                          NULL);
+      /* never honour G_VALUE_NOCOPY_CONTENTS for ref-counted types */
+      value->data[0].v_pointer = dia_object_change_ref (change);
+    }
+  } else {
+    value->data[0].v_pointer = NULL;
+  }
+
+  return NULL;
+}
+
+
+static char *
+g_value_change_lcopy_value (const GValue *value,
+                            guint         n_collect_values,
+                            GTypeCValue  *collect_values,
+                            guint         collect_flags)
+{
+  DiaObjectChange **change_p = collect_values[0].v_pointer;
+
+  if (!change_p) {
+    return g_strdup_printf ("value location for '%s' passed as NULL",
+                            G_VALUE_TYPE_NAME (value));
+  }
+
+  if (!value->data[0].v_pointer) {
+    *change_p = NULL;
+  } else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
+    *change_p = value->data[0].v_pointer;
+  } else {
+    *change_p = dia_object_change_ref (value->data[0].v_pointer);
+  }
+
+  return NULL;
+}
+
+
+static void
+g_value_change_transform_value (const GValue *src_value,
+                                GValue       *dest_value)
+{
+  if (src_value->data[0].v_pointer &&
+      g_type_is_a (DIA_OBJECT_CHANGE_TYPE (src_value->data[0].v_pointer), G_VALUE_TYPE (dest_value))) {
+    dest_value->data[0].v_pointer = dia_object_change_ref (src_value->data[0].v_pointer);
+  } else {
+    dest_value->data[0].v_pointer = NULL;
+  }
+}
+
+
+GType
+dia_object_change_get_type (void)
+{
+  static volatile GType type_id = 0;
+
+  if (g_once_init_enter (&type_id)) {
+    static const GTypeFundamentalInfo finfo = {
+      G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE,
+    };
+    GTypeInfo info = {
+      sizeof (DiaObjectChangeClass),
+      (GBaseInitFunc) dia_object_change_base_class_init,
+      (GBaseFinalizeFunc) dia_object_change_class_finalize,
+      (GClassInitFunc) dia_object_change_do_class_init,
+      NULL,                         /* class_destroy */
+      NULL,                         /* class_data */
+      sizeof (DiaObjectChange),
+      0,                            /* n_preallocs */
+      (GInstanceInitFunc) dia_object_change_init,
+      NULL,                         /* value_table */
+    };
+    static const GTypeValueTable value_table = {
+      g_value_change_init,          /* value_init */
+      g_value_change_free_value,    /* value_free */
+      g_value_change_copy_value,    /* value_copy */
+      g_value_change_peek_pointer,  /* value_peek_pointer */
+      "p",                          /* collect_format */
+      g_value_change_collect_value, /* collect_value */
+      "p",                          /* lcopy_format */
+      g_value_change_lcopy_value,   /* lcopy_value */
+    };
+    GType type;
+
+    info.value_table = &value_table;
+    type = g_type_register_fundamental (g_type_fundamental_next (),
+                                        g_intern_static_string ("DiaObjectChange"),
+                                        &info,
+                                        &finfo,
+                                        0);
+    g_value_register_transform_func (type,
+                                     type,
+                                     g_value_change_transform_value);
+
+    g_once_init_leave (&type_id, type);
+  }
+
+  return type_id;
+}
+
+
+/**
+ * dia_object_change_ref:
+ * @self: the #DiaObjectChange
+ *
+ * Returns: (transfer full): a new reference
+ *
+ * Since: 0.98
+ *
+ * Stability: Stable
+ */
+gpointer
+dia_object_change_ref (gpointer self)
+{
+  g_return_val_if_fail (self != NULL, NULL);
+
+  g_ref_count_inc (&((DiaObjectChange *) self)->refs);
+
+  return self;
+}
+
+
+/**
+ * dia_object_change_unref:
+ * @self: (transfer full): the #DiaObjectChange
+ *
+ * Decrease the ref count of @self potentially freeing it
+ *
+ * Since: 0.98
+ *
+ * Stability: Stable
+ */
+void
+dia_object_change_unref (gpointer self)
+{
+  g_return_if_fail (self != NULL);
+
+  if (g_ref_count_dec (&((DiaObjectChange *) self)->refs)) {
+    DIA_OBJECT_CHANGE_GET_CLASS (self)->free (self);
+
+    g_type_free_instance (self);
+  }
+}
+
+
+/**
+ * dia_object_change_new:
+ * @type: the #DiaObjectChange derrived #GType to instantiate
+ *
+ * Create an instance of @type, it's epected this will be used inside a
+ * constructor for @type rather than in general code
+ *
+ * Returns: (transfer full): A new #DiaObjectChange instance
+ *
+ * Since: 0.98
+ *
+ * Stability: Stable
+ */
+gpointer
+dia_object_change_new (GType type)
+{
+  g_return_val_if_fail (DIA_TYPE_IS_OBJECT_CHANGE (type), NULL);
+
+  return g_type_create_instance (type);
+}
+
+
+/**
+ * dia_object_change_apply:
+ * @self: a #DiaObjectChange
+ * @object: the #DiaObject to apply @self to
+ *
+ * Do a change
+ *
+ * Since: 0.98
+ *
+ * Stability: Stable
+ */
+void
+dia_object_change_apply (DiaObjectChange *self,
+                         DiaObject       *object)
+{
+  g_return_if_fail (self && DIA_IS_OBJECT_CHANGE (self));
+  g_return_if_fail (object && DIA_IS_DIAGRAM_DATA (object));
+
+  DIA_OBJECT_CHANGE_GET_CLASS (self)->apply (self, object);
+}
+
+
+/**
+ * dia_object_change_revert:
+ * @self: a #DiaObjectChange
+ * @object: the #DiaObject to revert @self from
+ *
+ * Undo a change
+ *
+ * Since: 0.98
+ *
+ * Stability: Stable
+ */
+void
+dia_object_change_revert (DiaObjectChange *self,
+                          DiaObject       *object)
+{
+  g_return_if_fail (self && DIA_IS_OBJECT_CHANGE (self));
+  g_return_if_fail (object && DIA_IS_DIAGRAM_DATA (object));
+
+  DIA_OBJECT_CHANGE_GET_CLASS (self)->revert (self, object);
+}
diff --git a/lib/dia-object-change.h b/lib/dia-object-change.h
new file mode 100644
index 000000000..c500f4271
--- /dev/null
+++ b/lib/dia-object-change.h
@@ -0,0 +1,141 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1999 Alexander Larsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright © 2020 Zander Brown <zbrown gnome org>
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+#ifndef __GTK_DOC_IGNORE__
+// TODO: Fix the cycle
+typedef struct _DiaObject DiaObject;
+#endif
+
+G_BEGIN_DECLS
+
+GType dia_object_change_get_type (void);
+#define DIA_TYPE_OBJECT_CHANGE dia_object_change_get_type ()
+
+typedef struct _DiaObjectChange DiaObjectChange;
+typedef struct _DiaObjectChangeClass DiaObjectChangeClass;
+
+#define DIA_TYPE_IS_OBJECT_CHANGE(type)     (G_TYPE_FUNDAMENTAL (type) == DIA_TYPE_OBJECT_CHANGE)
+#define DIA_OBJECT_CHANGE(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), DIA_TYPE_OBJECT_CHANGE, 
DiaObjectChange))
+#define DIA_OBJECT_CHANGE_CLASS(class)      (G_TYPE_CHECK_CLASS_CAST ((class), DIA_TYPE_OBJECT_CHANGE, 
DiaObjectChangeClass))
+#define DIA_IS_OBJECT_CHANGE(object)        (G_TYPE_CHECK_INSTANCE_FUNDAMENTAL_TYPE ((object), 
DIA_TYPE_OBJECT_CHANGE))
+#define DIA_IS_OBJECT_CHANGE_CLASS(class)   (G_TYPE_CHECK_CLASS_TYPE ((class), DIA_TYPE_OBJECT_CHANGE))
+#define DIA_OBJECT_CHANGE_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), DIA_TYPE_OBJECT_CHANGE, 
DiaObjectChangeClass))
+#define DIA_OBJECT_CHANGE_TYPE(object)      (G_TYPE_FROM_INSTANCE (object))
+#define DIA_OBJECT_CHANGE_TYPE_NAME(object) (g_type_name (DIA_OBJECT_CHANGE_TYPE (object)))
+#define DIA_OBJECT_CHANGE_CLASS_TYPE(class) (G_TYPE_FROM_CLASS (class))
+#define DIA_OBJECT_CHANGE_CLASS_NAME(class) (g_type_name (DIA_OBJECT_CHANGE_CLASS_TYPE (class)))
+#define G_VALUE_HOLDS_OBJECT_CHANGE(value)  (G_TYPE_CHECK_VALUE_TYPE ((value), DIA_TYPE_OBJECT_CHANGE))
+
+
+/**
+ * DIA_DEFINE_CHANGE:
+ * @TypeName: CamelCase name of the type
+ * @type_name: python_case name of the type
+ *
+ * G_DEFINE_TYPE() wrapper for implementing #DiaObjectChange types, however
+ * unlike G_DEFINE_TYPE() the _init and _class_init are implemented for you.
+ * Instead you provide apply, revert & free functions
+ *
+ * |[<!-- language="C" -->
+ * DIA_DEFINE_OBJECT_CHANGE (SomeChange, some_change)
+ *
+ * static void
+ * some_change_apply (DiaObjectChange *change,
+ *                    DiaObject       *object)
+ * {
+ * }
+ *
+ * static void
+ * some_change_revert (DiaObjectChange *change,
+ *                     DiaObject       *object)
+ * {
+ * }
+ *
+ * static void
+ * some_change_free (DiaObjectChange *change)
+ * {
+ * }
+ * ]|
+ *
+ * Since: 0.98
+ */
+#define DIA_DEFINE_OBJECT_CHANGE(TypeName, type_name)                        \
+  G_DEFINE_TYPE (TypeName, type_name, DIA_TYPE_OBJECT_CHANGE)                \
+                                                                             \
+  static void type_name##_apply             (DiaObjectChange *change,        \
+                                             DiaObject       *object);       \
+  static void type_name##_revert            (DiaObjectChange *change,        \
+                                             DiaObject       *object);       \
+  static void type_name##_free              (DiaObjectChange *change);       \
+                                                                             \
+  static void                                                                \
+  type_name##_class_init (TypeName##Class *klass)                            \
+  {                                                                          \
+    DiaObjectChangeClass *change_class = DIA_OBJECT_CHANGE_CLASS (klass);    \
+                                                                             \
+    change_class->apply = type_name##_apply;                                 \
+    change_class->revert = type_name##_revert;                               \
+    change_class->free = type_name##_free;                                   \
+  }                                                                          \
+                                                                             \
+  static void                                                                \
+  type_name##_init (TypeName *klass)                                         \
+  {                                                                          \
+  }
+
+
+struct _DiaObjectChange {
+  GTypeInstance g_type_instance;
+
+  grefcount refs;
+
+  DiaObjectChange *next;
+  DiaObjectChange *prev;
+};
+
+
+struct _DiaObjectChangeClass {
+  GTypeClass parent;
+
+  void (*apply)  (DiaObjectChange *change,
+                  DiaObject       *dia);
+  void (*revert) (DiaObjectChange *change,
+                  DiaObject       *dia);
+  void (*free)   (DiaObjectChange *change);
+};
+
+
+void     dia_object_change_unref  (gpointer         self);
+gpointer dia_object_change_ref    (gpointer         self);
+gpointer dia_object_change_new    (GType            type);
+void     dia_object_change_apply  (DiaObjectChange *self,
+                                   DiaObject       *object);
+void     dia_object_change_revert (DiaObjectChange *self,
+                                   DiaObject       *object);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (DiaObjectChange, dia_object_change_unref)
+
+G_END_DECLS
diff --git a/lib/meson.build b/lib/meson.build
index 1aa23e788..9938fea1a 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -91,6 +91,8 @@ libdia_sources = stdprop_sources + [
     'objchange.h',
     'dia-change.c',
     'dia-change.h',
+    'dia-object-change.c',
+    'dia-object-change.h',
     'dialogs.c',
     'dialogs.h',
     'widgets.c',


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