2006-12-03 Dimitris Glezos <dimitris@glezos.com>
[dia.git] / lib / propdesc.c
blobd426a69100b2e59547a2a113ae0626862cfe9dbc
1 /* Dia -- a diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * Property system for dia objects/shapes.
5 * Copyright (C) 2000 James Henstridge
6 * Copyright (C) 2001 Cyrille Chepelov
7 * Major restructuration done in August 2001 by C. Chepelov
9 * propdesc.c: This module handles operations on property descriptors and
10 * property descriptor lists.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
31 #include <glib.h>
33 #include "properties.h"
34 #include "propinternals.h"
36 void
37 prop_desc_list_calculate_quarks(PropDescription *plist)
39 guint i;
41 for (i = 0; plist[i].name != NULL; i++) {
42 if (plist[i].quark == 0)
43 plist[i].quark = g_quark_from_static_string(plist[i].name);
44 if (plist[i].type_quark == 0)
45 plist[i].type_quark = g_quark_from_static_string(plist[i].type);
46 if (!plist[i].ops)
47 plist[i].ops = prop_type_get_ops(plist[i].type);
51 const PropDescription *
52 prop_desc_list_find_prop(const PropDescription *plist, const gchar *name)
54 gint i = 0;
55 GQuark name_quark = g_quark_from_string(name);
57 while (plist[i].name != NULL) {
58 if (plist[i].quark == name_quark)
59 return &plist[i];
60 i++;
62 return NULL;
65 /* finds the real handler in case there are several levels of indirection */
66 PropEventHandler
67 prop_desc_find_real_handler(const PropDescription *pdesc)
69 PropEventHandler ret = pdesc->event_handler;
70 const PropEventHandlerChain *chain = &pdesc->chain_handler;
71 if (!chain->handler) return ret;
72 while (chain) {
73 if (chain->handler) ret = chain->handler;
74 chain = chain->chain;
76 return ret;
79 /* free a handler indirection list */
80 void
81 prop_desc_free_handler_chain(PropDescription *pdesc)
83 if (pdesc) {
84 PropEventHandlerChain *chain = pdesc->chain_handler.chain;
85 while (chain) {
86 PropEventHandlerChain *next = chain->chain;
87 g_free(chain);
88 chain = next;
90 pdesc->chain_handler.chain = NULL;
91 pdesc->chain_handler.handler = NULL;
95 /* free a handler indirection list in a list of descriptors */
96 void
97 prop_desc_list_free_handler_chain(PropDescription *pdesc)
99 if (!pdesc) return;
100 while (pdesc->name) {
101 prop_desc_free_handler_chain(pdesc);
102 pdesc++;
106 /* insert an event handler */
107 void
108 prop_desc_insert_handler(PropDescription *pdesc,
109 PropEventHandler handler)
111 if ((pdesc->chain_handler.handler) || (pdesc->chain_handler.chain)) {
112 /* not the first level. Push things forward. */
113 PropEventHandlerChain *pushed = g_new0(PropEventHandlerChain,1);
114 *pushed = pdesc->chain_handler;
115 pdesc->chain_handler.chain = pushed;
117 pdesc->chain_handler.handler = pdesc->event_handler;
118 pdesc->event_handler = handler;
121 static const PropDescription null_prop_desc = { NULL };
123 PropDescription *
124 prop_desc_lists_union(GList *plists)
126 GArray *arr = g_array_new(TRUE, TRUE, sizeof(PropDescription));
127 PropDescription *ret;
128 GList *tmp;
130 /* make sure the array is allocated */
131 g_array_append_val(arr, null_prop_desc);
132 g_array_remove_index(arr, 0);
134 for (tmp = plists; tmp; tmp = tmp->next) {
135 PropDescription *plist = tmp->data;
136 int i;
138 for (i = 0; plist[i].name != NULL; i++) {
139 int j;
140 for (j = 0; j < arr->len; j++)
141 if (g_array_index(arr, PropDescription, j).quark == plist[i].quark)
142 break;
143 if (j == arr->len)
144 g_array_append_val(arr, plist[i]);
147 ret = (PropDescription *)arr->data;
148 g_array_free(arr, FALSE);
149 return ret;
152 gboolean
153 propdescs_can_be_merged(const PropDescription *p1,
154 const PropDescription *p2) {
155 PropEventHandler peh1 = prop_desc_find_real_handler(p1);
156 PropEventHandler peh2 = prop_desc_find_real_handler(p2);
158 if (p1->ops != p2->ops) return FALSE;
159 if ((p1->flags|p2->flags) & PROP_FLAG_DONT_MERGE) return FALSE;
160 if (peh1 != peh2) return FALSE;
161 if ((p1->ops->can_merge && !(p1->ops->can_merge(p1,p2))) ||
162 (p2->ops->can_merge && !(p2->ops->can_merge(p2,p1)))) return FALSE;
164 return TRUE;
167 PropDescription *
168 prop_desc_lists_intersection(GList *plists)
170 GArray *arr = g_array_new(TRUE, TRUE, sizeof(PropDescription));
171 PropDescription *ret;
172 GList *tmp;
173 gint i;
175 /* make sure the array is allocated */
176 g_array_append_val(arr, null_prop_desc);
177 g_array_remove_index(arr, 0);
179 if (plists) {
180 ret = plists->data;
181 for (i = 0; ret[i].name != NULL; i++)
182 g_array_append_val(arr, ret[i]);
184 /* check each PropDescription list for intersection */
185 for (tmp = plists->next; tmp; tmp = tmp->next) {
186 ret = tmp->data;
188 /* go through array in reverse so that removals don't stuff things up */
189 for (i = arr->len - 1; i >= 0; i--) {
190 gint j;
191 PropDescription cand = g_array_index(arr,PropDescription,i);
192 gboolean remove = TRUE;
193 for (j = 0; ret[j].name != NULL; j++) {
194 if (cand.quark == ret[j].quark) {
195 remove = !(propdescs_can_be_merged(&ret[j],&cand));
196 break;
199 if (remove) g_array_remove_index(arr, i);
203 ret = (PropDescription *)arr->data;
204 g_array_free(arr, FALSE);
205 return ret;