1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009 Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
23 * @short_description: The base class of the ADG model infrastructure
25 * A model is a conceptual representation of something. From an ADG
26 * user point of view, it is a collection of data and rules that
27 * defines how an object should be represented on a drawing.
29 * Because #AdgModel instances are only a conceptual idea, they are
30 * not renderable (that is, #AdgModel is not derived from #AdgEntity).
31 * Instead, it must be passed as subject to entities such as #AdgStroke
38 * All fields are private and should not be used directly.
39 * Use its public methods instead.
43 #include "adg-model.h"
44 #include "adg-model-private.h"
45 #include "adg-marshal.h"
48 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_model_parent_class)
64 static void dispose (GObject
*object
);
65 static void set_property (GObject
*object
,
70 static GSList
* get_dependencies (AdgModel
*model
);
71 static void add_dependency (AdgModel
*model
,
73 static void remove_dependency (AdgModel
*model
,
75 static void changed (AdgModel
*model
);
77 static guint signals
[LAST_SIGNAL
] = { 0 };
80 G_DEFINE_ABSTRACT_TYPE(AdgModel
, adg_model
, G_TYPE_OBJECT
);
84 adg_model_class_init(AdgModelClass
*klass
)
86 GObjectClass
*gobject_class
;
89 gobject_class
= (GObjectClass
*) klass
;
91 g_type_class_add_private(klass
, sizeof(AdgModelPrivate
));
93 gobject_class
->dispose
= dispose
;
94 gobject_class
->set_property
= set_property
;
96 klass
->get_dependencies
= get_dependencies
;
97 klass
->add_dependency
= add_dependency
;
98 klass
->remove_dependency
= remove_dependency
;
99 klass
->changed
= changed
;
101 param
= g_param_spec_object("dependency",
103 P_("Can be used to add a new dependency from this model (this entity will be invalidated on model changed)"),
104 ADG_TYPE_ENTITY
, G_PARAM_WRITABLE
);
105 g_object_class_install_property(gobject_class
, PROP_DEPENDENCY
, param
);
108 * AdgModel::add-dependency:
109 * @model: an #AdgModel
110 * @entity: an #AdgEntity that depends on @model
112 * Adds @entity to @model. After that @entity will depend on @model,
113 * that is #AdgModel::changed on @model will invalidate @entity.
115 signals
[ADD_DEPENDENCY
] = g_signal_new("add-dependency",
116 G_OBJECT_CLASS_TYPE(gobject_class
),
118 G_STRUCT_OFFSET(AdgModelClass
, add_dependency
),
120 adg_marshal_VOID__OBJECT
,
121 G_TYPE_NONE
, 1, ADG_TYPE_ENTITY
);
124 * AdgModel::remove-dependency:
125 * @model: an #AdgModel
126 * @entity: the #AdgEntity that does not depend on @model anymore
128 * Removes the @entity from @model, that is @entity will not depend
131 signals
[REMOVE_DEPENDENCY
] = g_signal_new("remove-dependency",
132 G_OBJECT_CLASS_TYPE(gobject_class
),
134 G_STRUCT_OFFSET(AdgModelClass
, remove_dependency
),
136 adg_marshal_VOID__OBJECT
,
137 G_TYPE_NONE
, 1, ADG_TYPE_ENTITY
);
141 * @model: an #AdgModel
143 * Notificates that the model has changed. By default, the model
144 * cache is invalidated.
146 signals
[CHANGED
] = g_signal_new("changed", ADG_TYPE_MODEL
,
147 G_SIGNAL_RUN_LAST
|G_SIGNAL_NO_RECURSE
,
148 G_STRUCT_OFFSET(AdgModelClass
, changed
),
150 adg_marshal_VOID__VOID
,
155 adg_model_init(AdgModel
*model
)
157 AdgModelPrivate
*data
= G_TYPE_INSTANCE_GET_PRIVATE(model
, ADG_TYPE_MODEL
,
160 data
->dependencies
= NULL
;
166 dispose(GObject
*object
)
169 AdgModelPrivate
*data
;
171 model
= (AdgModel
*) object
;
174 /* Remove all the dependencies from the model: this will emit
175 * a "remove" signal for every dependency and will drop all the
176 * references from those entities to this model */
177 while (data
->dependencies
!= NULL
)
178 adg_model_remove_dependency(model
,
179 (AdgEntity
*) data
->dependencies
->data
);
181 if (PARENT_OBJECT_CLASS
->dispose
!= NULL
)
182 PARENT_OBJECT_CLASS
->dispose(object
);
186 set_property(GObject
*object
,
187 guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
189 AdgModel
*model
= (AdgModel
*) object
;
192 case PROP_DEPENDENCY
:
193 adg_model_add_dependency(model
, g_value_get_object(value
));
196 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
202 * adg_model_add_dependency:
203 * @model: an #AdgModel
204 * @entity: an #AdgEntity
207 * This function is only useful in entity implementations.
210 * Emits a #AdgModel::add-dependency signal on @model passing @entity
211 * as argument. This will add a reference to @entity owned by @model.
214 adg_model_add_dependency(AdgModel
*model
, AdgEntity
*entity
)
216 g_return_if_fail(ADG_IS_MODEL(model
));
217 g_return_if_fail(ADG_IS_ENTITY(entity
));
219 g_signal_emit(model
, signals
[ADD_DEPENDENCY
], 0, entity
);
223 * adg_model_remove_dependency:
224 * @model: an #AdgModel
225 * @entity: an #AdgEntity
228 * This function is only useful in entity implementations.
231 * Emits a #AdgModel::remove-dependency signal on @model passing
232 * @entity as argument. @entity must be inside @model.
234 * Note that @model will own a reference to @entity and it
235 * may be the last reference held: this means removing an entity
236 * from the model can destroy it.
239 adg_model_remove_dependency(AdgModel
*model
, AdgEntity
*entity
)
241 g_return_if_fail(ADG_IS_MODEL(model
));
242 g_return_if_fail(ADG_IS_ENTITY(entity
));
244 g_signal_emit(model
, signals
[REMOVE_DEPENDENCY
], 0, entity
);
248 * adg_model_get_dependencies:
249 * @model: an #AdgModel
251 * Gets a list of entities dependent on @model.
252 * This list must be freed with g_slist_free() when no longer user.
254 * Returns: a newly allocated #GSList or %NULL on error
257 adg_model_get_dependencies(AdgModel
*model
)
259 g_return_val_if_fail(ADG_IS_MODEL(model
), NULL
);
261 return ADG_MODEL_GET_CLASS(model
)->get_dependencies(model
);
265 * adg_model_foreach_dependency:
266 * @model: an #AdgModel
267 * @callback: a callback
268 * @user_data: callback user data
270 * Invokes @callback on each entity linked to @model.
271 * The callback should be declared as:
274 * void callback(AdgEntity *entity, gpointer user_data);
278 adg_model_foreach_dependency(AdgModel
*model
, GCallback callback
,
281 GSList
*dependencies
;
283 g_return_if_fail(ADG_IS_MODEL(model
));
284 g_return_if_fail(callback
!= NULL
);
286 dependencies
= adg_model_get_dependencies(model
);
288 while (dependencies
) {
289 if (dependencies
->data
)
290 ((void (*) (gpointer
, gpointer
)) callback
) (dependencies
->data
,
293 dependencies
= g_slist_delete_link(dependencies
, dependencies
);
299 * @model: an #AdgModel
302 * This function is only useful in entity implementations.
305 * Emits the #AdgModel::changed signal on @model.
308 adg_model_changed(AdgModel
*model
)
310 g_return_if_fail(ADG_IS_MODEL(model
));
312 g_signal_emit(model
, signals
[CHANGED
], 0);
317 add_dependency(AdgModel
*model
, AdgEntity
*entity
)
319 AdgModelPrivate
*data
= model
->data
;
321 /* The prepend operation is more efficient */
322 data
->dependencies
= g_slist_prepend(data
->dependencies
, entity
);
324 g_object_ref(entity
);
328 remove_dependency(AdgModel
*model
, AdgEntity
*entity
)
330 AdgModelPrivate
*data
;
334 node
= g_slist_find(data
->dependencies
, entity
);
337 g_warning("Attempting to remove an entity with type %s from a "
338 "model of type %s, but the entity is not present.",
339 g_type_name(G_OBJECT_TYPE(entity
)),
340 g_type_name(G_OBJECT_TYPE(model
)));
344 data
->dependencies
= g_slist_delete_link(data
->dependencies
, node
);
345 g_object_unref(entity
);
349 get_dependencies(AdgModel
*model
)
351 AdgModelPrivate
*data
= model
->data
;
353 /* The NULL case is yet managed by GLib */
354 return g_slist_copy(data
->dependencies
);
358 changed(AdgModel
*model
)
360 /* Invalidate all the entities dependent on this model */
361 adg_model_foreach_dependency(model
,
362 G_CALLBACK(adg_entity_invalidate
), NULL
);