1 /* Dia -- a diagram creation/manipulation program -*- c -*-
2 * Copyright (C) 1998 Alexander Larsson
3 *
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
8 *
9 * Property types for static and dynamic arrays.
10 * These arrays are simply arrays of records whose structures are themselves
11 * described by property descriptors.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 */
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30
31 #include <gtk/gtk.h>
32 #define WIDGET GtkWidget
33 #include "widgets.h"
34 #include "properties.h"
35 #include "propinternals.h"
36
37 /******************************************/
38 /* The SARRAY and DARRAY property types. */
39 /******************************************/
40
41 static ArrayProperty *
arrayprop_new(const PropDescription * pdesc,PropDescToPropPredicate reason)42 arrayprop_new(const PropDescription *pdesc, PropDescToPropPredicate reason)
43 {
44 ArrayProperty *prop = g_new0(ArrayProperty,1);
45 const PropDescCommonArrayExtra *extra = pdesc->extra_data;
46
47 initialize_property(&prop->common, pdesc, reason);
48 prop->ex_props = prop_list_from_descs(extra->record,reason);
49 prop->records = g_ptr_array_new();
50 return prop;
51 }
52
53 static void
arrayprop_freerecords(ArrayProperty * prop)54 arrayprop_freerecords(ArrayProperty *prop) /* but not the array itself. */
55 {
56 guint i;
57
58 for (i=0; i < prop->records->len; i++)
59 prop_list_free(g_ptr_array_index(prop->records,i));
60 }
61
62 static void
arrayprop_free(ArrayProperty * prop)63 arrayprop_free(ArrayProperty *prop)
64 {
65 arrayprop_freerecords(prop);
66 g_ptr_array_free(prop->records,TRUE);
67 g_free(prop);
68 }
69
70 static ArrayProperty *
arrayprop_copy(ArrayProperty * src)71 arrayprop_copy(ArrayProperty *src)
72 {
73 ArrayProperty *prop =
74 (ArrayProperty *)src->common.ops->new_prop(src->common.descr,
75 src->common.reason);
76 guint i;
77 copy_init_property(&prop->common,&src->common);
78 prop->ex_props = prop_list_copy(src->ex_props);
79 prop->records = g_ptr_array_new();
80 for (i = 0; i < src->records->len; i++) {
81 g_ptr_array_add(prop->records,
82 prop_list_copy(g_ptr_array_index(src->records,i)));
83 }
84 return prop;
85 }
86
87 static void
arrayprop_load(ArrayProperty * prop,AttributeNode attr,DataNode data)88 arrayprop_load(ArrayProperty *prop, AttributeNode attr, DataNode data)
89 {
90 const PropDescCommonArrayExtra *extra = prop->common.descr->extra_data;
91 DataNode composite;
92 GError *err = NULL;
93
94 arrayprop_freerecords(prop);
95 g_ptr_array_set_size(prop->records,0);
96
97 for (composite = data;
98 composite != NULL;
99 composite = data_next(composite)) {
100 GPtrArray *record = prop_list_from_descs(extra->record,
101 prop->common.reason);
102 if (!prop_list_load(record,composite, &err)) {
103 g_warning ("%s:%s", prop->common.name, err->message);
104 g_error_free (err);
105 err = NULL;
106 }
107 g_ptr_array_add(prop->records,record);
108 }
109 }
110
111 static void
arrayprop_save(ArrayProperty * prop,AttributeNode attr)112 arrayprop_save(ArrayProperty *prop, AttributeNode attr)
113 {
114 int i;
115 const PropDescCommonArrayExtra *extra = prop->common.descr->extra_data;
116
117 for (i = 0; i < prop->records->len; i++) {
118 prop_list_save(g_ptr_array_index(prop->records,i),
119 data_add_composite(attr,extra->composite_type));
120 }
121 }
122
123 static void
sarrayprop_get_from_offset(ArrayProperty * prop,void * base,guint offset,guint offset2)124 sarrayprop_get_from_offset(ArrayProperty *prop,
125 void *base, guint offset, guint offset2)
126 {
127 const PropDescSArrayExtra *extra = prop->common.descr->extra_data;
128 PropOffset *suboffsets = extra->common.offsets;
129 guint i;
130
131 prop_offset_list_calculate_quarks(suboffsets);
132
133 arrayprop_freerecords(prop);
134 g_ptr_array_set_size(prop->records,extra->array_len);
135
136 for (i=0; i < prop->records->len; i++) {
137 void *rec_in_obj = &struct_member(base,
138 offset + (i * extra->element_size),
139 char);
140 GPtrArray *subprops = prop_list_copy(prop->ex_props);
141
142 do_get_props_from_offsets(rec_in_obj,subprops,suboffsets);
143
144 g_ptr_array_index(prop->records,i) = subprops;
145 }
146 }
147
148 static void
sarrayprop_set_from_offset(ArrayProperty * prop,void * base,guint offset,guint offset2)149 sarrayprop_set_from_offset(ArrayProperty *prop,
150 void *base, guint offset, guint offset2)
151 {
152 const PropDescSArrayExtra *extra = prop->common.descr->extra_data;
153 PropOffset *suboffsets = extra->common.offsets;
154 guint i;
155
156 g_assert(prop->records->len == extra->array_len);
157
158 prop_offset_list_calculate_quarks(suboffsets);
159
160 for (i=0; i < prop->records->len; i++) {
161 void *rec_in_obj = &struct_member(base,
162 offset + (i * extra->element_size),
163 char);
164 GPtrArray *subprops = g_ptr_array_index(prop->records,i);
165
166 do_set_props_from_offsets(rec_in_obj,subprops,suboffsets);
167 }
168 }
169
170 static void
darrayprop_get_from_offset(ArrayProperty * prop,void * base,guint offset,guint offset2)171 darrayprop_get_from_offset(ArrayProperty *prop,
172 void *base, guint offset, guint offset2)
173 {
174 /* This sucks. We do almost exactly like in sarrayprop_get_from_offset(). */
175 const PropDescSArrayExtra *extra = prop->common.descr->extra_data;
176 PropOffset *suboffsets = extra->common.offsets;
177 guint i;
178 GList *obj_rec = struct_member(base,offset,GList *);
179
180 prop_offset_list_calculate_quarks(suboffsets);
181
182 arrayprop_freerecords(prop);
183 g_ptr_array_set_size(prop->records,0);
184
185 for (obj_rec = g_list_first(obj_rec), i = 0;
186 obj_rec != NULL;
187 obj_rec = g_list_next(obj_rec), i++) {
188 void *rec_in_obj = obj_rec->data;
189 GPtrArray *subprops = prop_list_copy(prop->ex_props);
190
191 do_get_props_from_offsets(rec_in_obj,subprops,suboffsets);
192
193 g_ptr_array_add(prop->records,subprops);
194 }
195 }
196
197 static GList *
darrayprop_adjust_object_records(ArrayProperty * prop,const PropDescDArrayExtra * extra,GList * obj_rec)198 darrayprop_adjust_object_records(ArrayProperty *prop,
199 const PropDescDArrayExtra *extra,
200 GList *obj_rec) {
201 guint list_len = g_list_length(obj_rec);
202
203 while (list_len > prop->records->len) {
204 gpointer rec = obj_rec->data;
205 obj_rec = g_list_remove(obj_rec,rec);
206 extra->freerec(rec);
207 list_len--;
208 }
209 while (list_len < prop->records->len) {
210 obj_rec = g_list_append(obj_rec,extra->newrec());
211 list_len++;
212 }
213 return obj_rec;
214 }
215
216 static void
darrayprop_set_from_offset(ArrayProperty * prop,void * base,guint offset,guint offset2)217 darrayprop_set_from_offset(ArrayProperty *prop,
218 void *base, guint offset, guint offset2)
219 {
220 /* This sucks. We do almost exactly like in darrayprop_set_from_offset(). */
221 const PropDescDArrayExtra *extra = prop->common.descr->extra_data;
222 PropOffset *suboffsets = extra->common.offsets;
223 guint i;
224 GList *obj_rec = struct_member(base,offset,GList *);
225
226 prop_offset_list_calculate_quarks(suboffsets);
227
228 obj_rec = darrayprop_adjust_object_records(prop,extra,obj_rec);
229 struct_member(base,offset,GList *) = obj_rec;
230
231 for (obj_rec = g_list_first(obj_rec), i = 0;
232 obj_rec != NULL;
233 obj_rec = g_list_next(obj_rec), i++) {
234 void *rec_in_obj = obj_rec->data;
235 GPtrArray *subprops = g_ptr_array_index(prop->records,i);
236
237 do_set_props_from_offsets(rec_in_obj,subprops,suboffsets);
238 }
239 }
240
241 /*!
242 * Create a dialog containing the list of array properties
243 */
244 static void
darray_prop_edit(GtkWidget * widget,gpointer data)245 darray_prop_edit (GtkWidget *widget, gpointer data)
246 {
247 ArrayProperty *prop = data;
248
249 }
250
251 static WIDGET *
arrayprop_get_widget(ArrayProperty * prop,PropDialog * dialog)252 arrayprop_get_widget(ArrayProperty *prop, PropDialog *dialog)
253 {
254 GtkWidget *ret = gtk_button_new_with_label (prop->common.descr->tooltip);
255 g_signal_connect (G_OBJECT (ret), "clicked",
256 G_CALLBACK (darray_prop_edit), prop);
257
258 return ret;
259 }
260
261 static void
arrayprop_reset_widget(NoopProperty * prop,WIDGET * widget)262 arrayprop_reset_widget(NoopProperty *prop, WIDGET *widget)
263 {
264 }
265
266 static void
arrayprop_set_from_widget(NoopProperty * prop,WIDGET * widget)267 arrayprop_set_from_widget(NoopProperty *prop, WIDGET *widget)
268 {
269 }
270
271 static gboolean
arrayprop_can_merge(const PropDescription * pd1,const PropDescription * pd2)272 arrayprop_can_merge(const PropDescription *pd1, const PropDescription *pd2)
273 {
274 if (pd1->extra_data != pd2->extra_data) return FALSE;
275 return TRUE;
276 }
277
278 static const PropertyOps sarrayprop_ops = {
279 (PropertyType_New) arrayprop_new,
280 (PropertyType_Free) arrayprop_free,
281 (PropertyType_Copy) arrayprop_copy,
282 (PropertyType_Load) arrayprop_load,
283 (PropertyType_Save) arrayprop_save,
284
285 (PropertyType_GetWidget) arrayprop_get_widget,
286 (PropertyType_ResetWidget) arrayprop_reset_widget,
287 (PropertyType_SetFromWidget) arrayprop_set_from_widget,
288
289 (PropertyType_CanMerge) arrayprop_can_merge,
290 (PropertyType_GetFromOffset) sarrayprop_get_from_offset,
291 (PropertyType_SetFromOffset) sarrayprop_set_from_offset
292 };
293
294 static const PropertyOps darrayprop_ops = {
295 (PropertyType_New) arrayprop_new,
296 (PropertyType_Free) arrayprop_free,
297 (PropertyType_Copy) arrayprop_copy,
298 (PropertyType_Load) arrayprop_load,
299 (PropertyType_Save) arrayprop_save,
300
301 (PropertyType_GetWidget) arrayprop_get_widget,
302 (PropertyType_ResetWidget) arrayprop_reset_widget,
303 (PropertyType_SetFromWidget) arrayprop_set_from_widget,
304
305 (PropertyType_CanMerge) noopprop_can_merge,
306 (PropertyType_GetFromOffset) darrayprop_get_from_offset,
307 (PropertyType_SetFromOffset) darrayprop_set_from_offset
308 };
309
310 /* ************************************************************** */
311
312 void
prop_sdarray_register(void)313 prop_sdarray_register(void)
314 {
315 prop_type_register(PROP_TYPE_SARRAY,&sarrayprop_ops);
316 prop_type_register(PROP_TYPE_DARRAY,&darrayprop_ops);
317 }
318