File: object-alias.c

package info (click to toggle)
dia 0.98%2Bgit20250126-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 52,072 kB
  • sloc: ansic: 155,381; xml: 14,056; python: 6,250; cpp: 3,598; sh: 439; perl: 137; makefile: 25
file content (188 lines) | stat: -rw-r--r-- 5,983 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/* 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"

#include <glib/gi18n-lib.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 <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"

#include "object-alias.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, DiaContext *ctx);
static void
_alias_save (DiaObject *obj, ObjectNode obj_node, DiaContext *ctx);

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, DiaContext *ctx)
{
  DiaObject *obj = NULL;
  xmlChar *str;

  str = xmlGetProp(obj_node, (const xmlChar *)"type");
  if (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, ctx);
#ifdef MODIFY_OBJECTS_TYPE
    /* now modify the object for some behavior change */
    obj->type = object_get_type ((char *)str); /* also changes the name */
#endif
    xmlFree(str);
  }
  return obj;
}

static void
_alias_save (DiaObject *obj, ObjectNode obj_node, DiaContext *ctx)
{
  object_save_using_properties (obj, obj_node, ctx);
}

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 = 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 ((char *)name), type);

    xmlFree (name);
  }
}