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