/* Dia -- a diagram creation/manipulation program -*- c -*- * Copyright (C) 1998 Alexander Larsson * * Property system for dia objects/shapes. * Copyright (C) 2000 James Henstridge * Copyright (C) 2001 Cyrille Chepelov * Major restructuration done in August 2001 by C. Chepelov * * Property types for static and dynamic arrays. * These arrays are simply arrays of records whose structures are themselves * described by property descriptors. * * 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. */ #ifdef HAVE_CONFIG_H #include #endif #include #define WIDGET GtkWidget #include "widgets.h" #include "properties.h" #include "propinternals.h" /******************************************/ /* The SARRAY and DARRAY property types. */ /******************************************/ static ArrayProperty * arrayprop_new(const PropDescription *pdesc, PropDescToPropPredicate reason) { ArrayProperty *prop = g_new0(ArrayProperty,1); const PropDescCommonArrayExtra *extra = pdesc->extra_data; initialize_property(&prop->common, pdesc, reason); prop->ex_props = prop_list_from_descs(extra->record,reason); prop->records = g_ptr_array_new(); return prop; } static void arrayprop_freerecords(ArrayProperty *prop) /* but not the array itself. */ { guint i; for (i=0; i < prop->records->len; i++) prop_list_free(g_ptr_array_index(prop->records,i)); } static void arrayprop_free(ArrayProperty *prop) { arrayprop_freerecords(prop); g_ptr_array_free(prop->records,TRUE); g_free(prop); } static ArrayProperty * arrayprop_copy(ArrayProperty *src) { ArrayProperty *prop = (ArrayProperty *)src->common.ops->new_prop(src->common.descr, src->common.reason); guint i; copy_init_property(&prop->common,&src->common); prop->ex_props = prop_list_copy(src->ex_props); prop->records = g_ptr_array_new(); for (i = 0; i < src->records->len; i++) { g_ptr_array_add(prop->records, prop_list_copy(g_ptr_array_index(src->records,i))); } return prop; } static void arrayprop_load(ArrayProperty *prop, AttributeNode attr, DataNode data) { const PropDescCommonArrayExtra *extra = prop->common.descr->extra_data; DataNode composite; GError *err = NULL; arrayprop_freerecords(prop); g_ptr_array_set_size(prop->records,0); for (composite = data; composite != NULL; composite = data_next(composite)) { GPtrArray *record = prop_list_from_descs(extra->record, prop->common.reason); if (!prop_list_load(record,composite, &err)) { g_warning ("%s:%s", prop->common.name, err->message); g_error_free (err); err = NULL; } g_ptr_array_add(prop->records,record); } } static void arrayprop_save(ArrayProperty *prop, AttributeNode attr) { int i; const PropDescCommonArrayExtra *extra = prop->common.descr->extra_data; for (i = 0; i < prop->records->len; i++) { prop_list_save(g_ptr_array_index(prop->records,i), data_add_composite(attr,extra->composite_type)); } } static void sarrayprop_get_from_offset(ArrayProperty *prop, void *base, guint offset, guint offset2) { const PropDescSArrayExtra *extra = prop->common.descr->extra_data; PropOffset *suboffsets = extra->common.offsets; guint i; prop_offset_list_calculate_quarks(suboffsets); arrayprop_freerecords(prop); g_ptr_array_set_size(prop->records,extra->array_len); for (i=0; i < prop->records->len; i++) { void *rec_in_obj = &struct_member(base, offset + (i * extra->element_size), char); GPtrArray *subprops = prop_list_copy(prop->ex_props); do_get_props_from_offsets(rec_in_obj,subprops,suboffsets); g_ptr_array_index(prop->records,i) = subprops; } } static void sarrayprop_set_from_offset(ArrayProperty *prop, void *base, guint offset, guint offset2) { const PropDescSArrayExtra *extra = prop->common.descr->extra_data; PropOffset *suboffsets = extra->common.offsets; guint i; g_assert(prop->records->len == extra->array_len); prop_offset_list_calculate_quarks(suboffsets); for (i=0; i < prop->records->len; i++) { void *rec_in_obj = &struct_member(base, offset + (i * extra->element_size), char); GPtrArray *subprops = g_ptr_array_index(prop->records,i); do_set_props_from_offsets(rec_in_obj,subprops,suboffsets); } } static void darrayprop_get_from_offset(ArrayProperty *prop, void *base, guint offset, guint offset2) { /* This sucks. We do almost exactly like in sarrayprop_get_from_offset(). */ const PropDescSArrayExtra *extra = prop->common.descr->extra_data; PropOffset *suboffsets = extra->common.offsets; guint i; GList *obj_rec = struct_member(base,offset,GList *); prop_offset_list_calculate_quarks(suboffsets); arrayprop_freerecords(prop); g_ptr_array_set_size(prop->records,0); for (obj_rec = g_list_first(obj_rec), i = 0; obj_rec != NULL; obj_rec = g_list_next(obj_rec), i++) { void *rec_in_obj = obj_rec->data; GPtrArray *subprops = prop_list_copy(prop->ex_props); do_get_props_from_offsets(rec_in_obj,subprops,suboffsets); g_ptr_array_add(prop->records,subprops); } } static GList * darrayprop_adjust_object_records(ArrayProperty *prop, const PropDescDArrayExtra *extra, GList *obj_rec) { guint list_len = g_list_length(obj_rec); while (list_len > prop->records->len) { gpointer rec = obj_rec->data; obj_rec = g_list_remove(obj_rec,rec); extra->freerec(rec); list_len--; } while (list_len < prop->records->len) { obj_rec = g_list_append(obj_rec,extra->newrec()); list_len++; } return obj_rec; } static void darrayprop_set_from_offset(ArrayProperty *prop, void *base, guint offset, guint offset2) { /* This sucks. We do almost exactly like in darrayprop_set_from_offset(). */ const PropDescDArrayExtra *extra = prop->common.descr->extra_data; PropOffset *suboffsets = extra->common.offsets; guint i; GList *obj_rec = struct_member(base,offset,GList *); prop_offset_list_calculate_quarks(suboffsets); obj_rec = darrayprop_adjust_object_records(prop,extra,obj_rec); struct_member(base,offset,GList *) = obj_rec; for (obj_rec = g_list_first(obj_rec), i = 0; obj_rec != NULL; obj_rec = g_list_next(obj_rec), i++) { void *rec_in_obj = obj_rec->data; GPtrArray *subprops = g_ptr_array_index(prop->records,i); do_set_props_from_offsets(rec_in_obj,subprops,suboffsets); } } static gboolean arrayprop_can_merge(const PropDescription *pd1, const PropDescription *pd2) { if (pd1->extra_data != pd2->extra_data) return FALSE; return TRUE; } static const PropertyOps sarrayprop_ops = { (PropertyType_New) arrayprop_new, (PropertyType_Free) arrayprop_free, (PropertyType_Copy) arrayprop_copy, (PropertyType_Load) arrayprop_load, (PropertyType_Save) arrayprop_save, (PropertyType_GetWidget) unimplementedprop_get_widget, (PropertyType_ResetWidget) unimplementedprop_reset_widget, (PropertyType_SetFromWidget) unimplementedprop_set_from_widget, (PropertyType_CanMerge) arrayprop_can_merge, (PropertyType_GetFromOffset) sarrayprop_get_from_offset, (PropertyType_SetFromOffset) sarrayprop_set_from_offset }; static const PropertyOps darrayprop_ops = { (PropertyType_New) arrayprop_new, (PropertyType_Free) arrayprop_free, (PropertyType_Copy) arrayprop_copy, (PropertyType_Load) arrayprop_load, (PropertyType_Save) arrayprop_save, (PropertyType_GetWidget) unimplementedprop_get_widget, (PropertyType_ResetWidget) unimplementedprop_reset_widget, (PropertyType_SetFromWidget) unimplementedprop_set_from_widget, (PropertyType_CanMerge) noopprop_can_merge, (PropertyType_GetFromOffset) darrayprop_get_from_offset, (PropertyType_SetFromOffset) darrayprop_set_from_offset }; /* ************************************************************** */ void prop_sdarray_register(void) { prop_type_register(PROP_TYPE_SARRAY,&sarrayprop_ops); prop_type_register(PROP_TYPE_DARRAY,&darrayprop_ops); }