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.
33 #include "properties.h"
34 #include "propinternals.h"
37 prop_desc_list_calculate_quarks(PropDescription
*plist
)
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
);
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
)
55 GQuark name_quark
= g_quark_from_string(name
);
57 while (plist
[i
].name
!= NULL
) {
58 if (plist
[i
].quark
== name_quark
)
65 /* finds the real handler in case there are several levels of indirection */
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
;
73 if (chain
->handler
) ret
= chain
->handler
;
79 /* free a handler indirection list */
81 prop_desc_free_handler_chain(PropDescription
*pdesc
)
84 PropEventHandlerChain
*chain
= pdesc
->chain_handler
.chain
;
86 PropEventHandlerChain
*next
= chain
->chain
;
90 pdesc
->chain_handler
.chain
= NULL
;
91 pdesc
->chain_handler
.handler
= NULL
;
95 /* free a handler indirection list in a list of descriptors */
97 prop_desc_list_free_handler_chain(PropDescription
*pdesc
)
100 while (pdesc
->name
) {
101 prop_desc_free_handler_chain(pdesc
);
106 /* insert an event handler */
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
};
124 prop_desc_lists_union(GList
*plists
)
126 GArray
*arr
= g_array_new(TRUE
, TRUE
, sizeof(PropDescription
));
127 PropDescription
*ret
;
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
;
138 for (i
= 0; plist
[i
].name
!= NULL
; i
++) {
140 for (j
= 0; j
< arr
->len
; j
++)
141 if (g_array_index(arr
, PropDescription
, j
).quark
== plist
[i
].quark
)
144 g_array_append_val(arr
, plist
[i
]);
147 ret
= (PropDescription
*)arr
->data
;
148 g_array_free(arr
, FALSE
);
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
;
168 prop_desc_lists_intersection(GList
*plists
)
170 GArray
*arr
= g_array_new(TRUE
, TRUE
, sizeof(PropDescription
));
171 PropDescription
*ret
;
175 /* make sure the array is allocated */
176 g_array_append_val(arr
, null_prop_desc
);
177 g_array_remove_index(arr
, 0);
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
) {
188 /* go through array in reverse so that removals don't stuff things up */
189 for (i
= arr
->len
- 1; i
>= 0; i
--) {
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
));
199 if (remove
) g_array_remove_index(arr
, i
);
203 ret
= (PropDescription
*)arr
->data
;
204 g_array_free(arr
, FALSE
);