[dia] Object alias definition via sheet file



commit 5c810e89c6c6ed509f029107ecbe074d6f2cb7d6
Author: Hans Breuer <hans breuer org>
Date:   Mon Jun 13 23:23:23 2011 +0200

    Object alias definition via sheet file
    
    To keep compatibility when renaming old shapes/objects the
    new alias facility could be used, see following commits for
    bug 598969 and bug 567886

 doc/sheet.dtd      |    6 ++-
 lib/Makefile.am    |    2 +
 lib/makefile.msc   |    1 +
 lib/object-alias.c |  185 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/object-alias.h |    8 ++
 lib/sheet.c        |   19 ++++--
 6 files changed, 214 insertions(+), 7 deletions(-)
---
diff --git a/doc/sheet.dtd b/doc/sheet.dtd
index 916d386..8d35881 100644
--- a/doc/sheet.dtd
+++ b/doc/sheet.dtd
@@ -8,9 +8,13 @@
 <!ATTLIST description
   xml:lang NMTOKEN #IMPLIED 'C' >
 
+<!ELEMENT alias (#PCDATA)* >
+<!ATTLIST alias
+  name CDATA #REQUIRED >
+
 <!ELEMENT contents (object | shape | br)* >
 
-<!ELEMENT object (description)* >
+<!ELEMENT object (description | alias)* >
 <!ATTLIST object
   name CDATA #REQUIRED
   intdata CDATA #IMPLIED >
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 7f6dd4e..1fca5ca 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -90,6 +90,8 @@ libdia_la_SOURCES =  \
 		handle.h \
 		object.h \
 		object.c \
+		object-alias.h \
+		object-alias.c \
 		object_defaults.c \
 		connection.c \
 		connection.h \
diff --git a/lib/makefile.msc b/lib/makefile.msc
index 8f79dcc..a6a8be3 100644
--- a/lib/makefile.msc
+++ b/lib/makefile.msc
@@ -83,6 +83,7 @@ OBJECTS = \
 	neworth_conn.obj \
 	objchange.obj \
 	object.obj \
+	object-alias.obj \
 	object_defaults.obj \
 	orth_conn.obj \
 	paper.obj \
diff --git a/lib/object-alias.c b/lib/object-alias.c
new file mode 100644
index 0000000..df49ffb
--- /dev/null
+++ b/lib/object-alias.c
@@ -0,0 +1,185 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * object-alias.c : a way to correct typos in object names
+ *
+ * Copyright (C) 2011 Hans Breuer
+ *
+ * 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.
+ */
+#include <config.h>
+
+/* To map an old name to a new object type the alias indirection is used.
+ * Starting with the old object from file the old name will persist. So there
+ * even should be no issue with forward compatibility (except if the object
+ * itself has issues, like an updated version).
+ *
+ * An extra feature would be the availability of construction only properties.
+ * These would be applied to the real object after creation and should not be
+ * accessible to any user of the alias name, i.e. neither be listed by 
+ * _alias_describe_props and _alias_get_props. But they additionally need to be 
+ * filtered in _alias_set_props, because e.g. for groups some properties might
+ * get tried to be applied which do not come from the original set(?). 
+ *
+ * The sheet code already relies on the correct order of type registration and
+ * access, so we can assume the target type is registered before the alias is
+ * created.
+ */
+
+#include <stdlib.h> /* atoi() */
+#include <string.h>
+
+#include <glib.h>
+
+#include "intl.h"
+
+#include <libxml/tree.h>
+#include "dia_xml_libxml.h"
+#include "dia_xml.h"
+#include "object.h"
+#include "message.h"
+#include "dia_dirs.h"
+#include "propinternals.h"
+
+/* DiaObjectType _alias_type must be dynamically 
+ *
+ * The hash table is mapping the alias name to the real type.
+ */
+GHashTable *_alias_types_ht = NULL;
+
+/* It should be possible to modify the original object after creation to point
+ * back to the alias type, at least as long as there are no dedicated object_ops
+ */
+#undef MODIFY_OBJECTS_TYPE
+
+static void *
+_alias_lookup (const char *name)
+{
+  if (!_alias_types_ht)
+    return NULL;
+
+  return g_hash_table_lookup (_alias_types_ht, name);
+}
+
+/* type_ops */
+static DiaObject *
+_alias_create (Point *startpoint,
+	       void *user_data,
+	       Handle **handle1,
+	       Handle **handle2);
+static DiaObject *
+_alias_load (ObjectNode obj_node, int version, const char *filename);
+static void
+_alias_save (DiaObject *obj, ObjectNode obj_node, const char *filename);
+
+static ObjectTypeOps _alias_type_ops =
+{
+  (CreateFunc) _alias_create,
+  (LoadFunc)   _alias_load, /* can't use object_load_using_properties, signature mismatch */
+  (SaveFunc)   _alias_save, /* overwrite for filename normalization */
+  (GetDefaultsFunc)   NULL,
+  (ApplyDefaultsFunc) NULL
+};
+
+/*! factory function */
+static DiaObject *
+_alias_create (Point *startpoint,
+	       void *user_data,
+	       Handle **handle1,
+	       Handle **handle2)
+{
+  DiaObject *obj;
+  DiaObjectType *alias_type = (DiaObjectType *)user_data;
+  DiaObjectType *real_type;
+  
+  g_return_val_if_fail (alias_type != NULL || alias_type->name != NULL, NULL);
+
+  real_type = _alias_lookup (alias_type->name);
+  if (!real_type)
+    return NULL;
+  g_return_val_if_fail (real_type->ops != &_alias_type_ops, NULL);
+
+  obj = real_type->ops->create (startpoint, real_type->default_user_data, handle1, handle2);
+  if (!obj)
+    return NULL;
+#ifdef MODIFY_OBJECTS_TYPE
+  /* now modify the object for some behavior change */
+  obj->type = alias_type; /* also changes the name */
+#endif
+
+  return obj;
+}
+
+static DiaObject *
+_alias_load (ObjectNode obj_node, int version, const char *filename)
+{
+  DiaObject *obj;
+  xmlChar *str;
+
+  str = xmlGetProp(obj_node, (const xmlChar *)"type");
+  if (str) {
+    DiaObjectType *alias_type = object_get_type ((char *)str);
+    DiaObjectType *real_type = _alias_lookup ((char *)str);
+    Point apoint = {0, 0};
+    Handle *h1, *h2;
+    /* can not use real_type->ops->load (obj_node, ...) because the
+     * typename used from obj_node is wrong for the real object ...
+     * just another reason to pass in the exlplicit this-pointer in every method.
+     */
+    obj = real_type->ops->create (&apoint, real_type->default_user_data, &h1, &h2);
+    object_load_props (obj, obj_node);
+#ifdef MODIFY_OBJECTS_TYPE
+    /* now modify the object for some behavior change */
+    obj->type = alias_type; /* also changes the name */
+#endif
+    xmlFree(str);
+  }
+  return obj;
+}
+
+static void
+_alias_save (DiaObject *obj, ObjectNode obj_node, const char *filename)
+{
+  object_save_using_properties (obj, obj_node, filename);
+}
+
+void
+object_register_alias_type (DiaObjectType *type, ObjectNode alias_node)
+{
+  xmlChar *name;
+
+  /* real type must be available before the alias can be created */
+  g_return_if_fail (type != NULL && object_get_type (type->name) != NULL);
+
+  name = xmlGetProp(alias_node, (const xmlChar *)"name");
+  if (name) {
+    DiaObjectType *alias_type = g_new0 (DiaObjectType, 1);
+
+    alias_type->name = g_strdup ((char *)name);
+    alias_type->ops = &_alias_type_ops;
+    alias_type->version = type->version; /* really? */
+    alias_type->pixmap = alias_type->pixmap;
+    alias_type->pixmap_file = type->pixmap_file ;
+    alias_type->default_user_data = alias_type; /* _create has no self pointer */
+
+    object_register_type (alias_type);
+    
+    if (!_alias_types_ht)
+      _alias_types_ht = g_hash_table_new (g_str_hash, g_str_equal);
+    g_hash_table_insert (_alias_types_ht, g_strdup (name), type);
+
+    xmlFree (name);
+  }
+}
diff --git a/lib/object-alias.h b/lib/object-alias.h
new file mode 100644
index 0000000..cd5b649
--- /dev/null
+++ b/lib/object-alias.h
@@ -0,0 +1,8 @@
+#ifndef OBJECT_ALIAS_H
+#define OBJECT_ALIAS_H
+
+#include "dia_xml.h"
+
+void object_register_alias_type (DiaObjectType *type, ObjectNode alias_node);
+
+#endif
diff --git a/lib/sheet.c b/lib/sheet.c
index d85caf1..06c3f19 100644
--- a/lib/sheet.c
+++ b/lib/sheet.c
@@ -38,6 +38,7 @@
 #include "sheet.h"
 #include "message.h"
 #include "object.h"
+#include "object-alias.h"
 #include "dia_dirs.h"
 
 static GSList *sheets = NULL;
@@ -360,6 +361,8 @@ load_register_sheet(const gchar *dirname, const gchar *filename,
 
     gboolean has_intdata = FALSE;
     gboolean has_icon_on_sheet = FALSE;
+    
+    xmlChar *ot_name = NULL;
 
     if (xmlIsBlankNode(node)) continue;
 
@@ -389,6 +392,8 @@ load_register_sheet(const gchar *dirname, const gchar *filename,
     chardata = (gchar *) xmlGetProp(node, (const xmlChar *)"chardata");
     /* TODO.... */
     if (chardata) xmlFree(chardata);
+   
+    ot_name = xmlGetProp(node, (xmlChar *)"name");
     
     for (subnode = node->xmlChildrenNode; 
          subnode != NULL ; 
@@ -425,13 +430,14 @@ load_register_sheet(const gchar *dirname, const gchar *filename,
           }
           has_icon_on_sheet = TRUE;
           if (tmp) xmlFree(tmp);
+      } else if (subnode->ns == ns && !xmlStrcmp(subnode->name, (const xmlChar *)"alias")) {
+        if (ot_name)
+          object_register_alias_type (object_get_type ((char *)ot_name), subnode); 
       }
     }
 
-    tmp = xmlGetProp(node, (xmlChar *)"name");
-
     sheet_obj = g_new(SheetObject,1);
-    sheet_obj->object_type = g_strdup((char *) tmp);
+    sheet_obj->object_type = g_strdup((char *) ot_name);
     sheet_obj->description = g_strdup(objdesc);
     xmlFree(objdesc); objdesc = NULL;
 
@@ -444,14 +450,14 @@ load_register_sheet(const gchar *dirname, const gchar *filename,
     sheet_obj->line_break = set_line_break;
     set_line_break = FALSE;
 
-    if ((otype = object_get_type((char *) tmp)) == NULL) {
+    if ((otype = object_get_type((char *) ot_name)) == NULL) {
       /* Don't complain. This does happen when disabling plug-ins too.
       g_warning("object_get_type(%s) returned NULL", tmp); */
       if (sheet_obj->description) g_free(sheet_obj->description);
       g_free(sheet_obj->pixmap_file);
       g_free(sheet_obj->object_type);
       g_free(sheet_obj);
-      if (tmp) xmlFree(tmp);
+      if (tmp) xmlFree(ot_name);
       continue; 
     }	  
     
@@ -468,7 +474,8 @@ load_register_sheet(const gchar *dirname, const gchar *filename,
     else
       sheet_obj->user_data_type = USER_DATA_IS_INTDATA;
 
-    if (tmp) xmlFree(tmp);
+    if (ot_name)
+      xmlFree(ot_name);
       
     /* we don't need to fix up the icon and descriptions for simple objects,
        since they don't have their own description, and their icon is 



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