1
#ifndef __SP_OBJECT_H__
2
#define __SP_OBJECT_H__
5
* Abstract base class for all nodes
8
* Lauris Kaplinski <lauris@kaplinski.com>
10
* Copyright (C) 1999-2002 authors
11
* Copyright (C) 2001-2002 Ximian, Inc.
13
* Released under GNU GPL, read the file 'COPYING' for more information
18
/* Async modification flags */
19
#define SP_OBJECT_MODIFIED_FLAG (1 << 0)
20
#define SP_OBJECT_CHILD_MODIFIED_FLAG (1 << 1)
21
#define SP_OBJECT_PARENT_MODIFIED_FLAG (1 << 2)
22
#define SP_OBJECT_STYLE_MODIFIED_FLAG (1 << 3)
23
#define SP_OBJECT_VIEWPORT_MODIFIED_FLAG (1 << 4)
24
#define SP_OBJECT_USER_MODIFIED_FLAG_A (1 << 5)
25
#define SP_OBJECT_USER_MODIFIED_FLAG_B (1 << 6)
26
#define SP_OBJECT_USER_MODIFIED_FLAG_C (1 << 7)
29
#define SP_OBJECT_FLAGS_ALL 0xff
31
/* Flags that mark object as modified */
32
/* Object, Child, Style, Viewport, User */
33
#define SP_OBJECT_MODIFIED_STATE (SP_OBJECT_FLAGS_ALL & ~(SP_OBJECT_PARENT_MODIFIED_FLAG))
35
/* Flags that will propagate downstreams */
36
/* Parent, Style, Viewport, User */
37
#define SP_OBJECT_MODIFIED_CASCADE (SP_OBJECT_FLAGS_ALL & ~(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))
40
#define SP_OBJECT_IS_CLONED(o) (((SPObject *) (o))->cloned)
43
#define SP_OBJECT_WRITE_BUILD (1 << 0)
44
#define SP_OBJECT_WRITE_EXT (1 << 1)
45
#define SP_OBJECT_WRITE_ALL (1 << 2)
47
/* Convenience stuff */
48
#define SP_OBJECT_ID(o) (((SPObject *) (o))->id)
49
#define SP_OBJECT_REPR(o) (((SPObject *) (o))->repr)
50
#define SP_OBJECT_DOCUMENT(o) (((SPObject *) (o))->document)
51
#define SP_OBJECT_PARENT(o) (((SPObject *) (o))->parent)
52
#define SP_OBJECT_NEXT(o) (((SPObject *) (o))->next)
53
#define SP_OBJECT_PREV(o) (sp_object_prev((SPObject *) (o)))
54
#define SP_OBJECT_HREFCOUNT(o) (((SPObject *) (o))->hrefcount)
55
#define SP_OBJECT_STYLE(o) (((SPObject *) (o))->style)
56
#define SP_OBJECT_TITLE(o) sp_object_title_get((SPObject *) (o))
57
#define SP_OBJECT_DESCRIPTION(o) sp_object_description_get((SPObject *) (o))
60
#include <glib-object.h>
61
#include <sigc++/connection.h>
62
#include <sigc++/functors/slot.h>
63
#include <sigc++/signal.h>
67
#include "util/forward-pointer-iterator.h"
79
SP_DOMSTRING_SIZE_ERR,
80
SP_HIERARCHY_REQUEST_ERR,
81
SP_WRONG_DOCUMENT_ERR,
82
SP_INVALID_CHARACTER_ERR,
83
SP_NO_DATA_ALLOWED_ERR,
84
SP_NO_MODIFICATION_ALLOWED_ERR,
87
SP_INUSE_ATTRIBUTE_ERR,
90
SP_INVALID_MODIFICATION_ERR,
97
/// An attempt to implement exceptions, unused?
102
#define SP_EXCEPTION_INIT(ex) {(ex)->code = SP_NO_EXCEPTION;}
103
#define SP_EXCEPTION_IS_OK(ex) (!(ex) || ((ex)->code == SP_NO_EXCEPTION))
113
SP_XML_SPACE_DEFAULT,
114
SP_XML_SPACE_PRESERVE
119
/// Internal class consisting of two bits.
130
* Owner is here for debug reasons, you can set it to NULL safely
131
* Ref should return object, NULL is error, unref return always NULL
134
SPObject *sp_object_ref(SPObject *object, SPObject *owner=NULL);
135
SPObject *sp_object_unref(SPObject *object, SPObject *owner=NULL);
137
SPObject *sp_object_href(SPObject *object, gpointer owner);
138
SPObject *sp_object_hunref(SPObject *object, gpointer owner);
140
/// A refcounting tree node object.
141
struct SPObject : public GObject {
142
enum CollectionPolicy {
147
unsigned int cloned : 1;
148
unsigned int uflags : 8;
149
unsigned int mflags : 8;
150
SPIXmlSpace xml_space;
151
unsigned int hrefcount; /* number of xlink:href references */
152
unsigned int _total_hrefcount; /* our hrefcount + total descendants */
153
SPDocument *document; /* Document we are part of */
154
SPObject *parent; /* Our parent (only one allowed) */
155
SPObject *children; /* Our children */
156
SPObject *_last_child; /* Remembered last child */
157
SPObject *next; /* Next object in linked list */
158
Inkscape::XML::Node *repr; /* Our xml representation */
159
gchar *id; /* Our very own unique id */
162
* Represents the style properties, whether from presentation attributes, the <tt>style</tt>
163
* attribute, or inherited.
165
* sp_object_private_set doesn't handle SP_ATTR_STYLE or any presentation attributes at the
166
* time of writing, so this is probably NULL for all SPObject's that aren't an SPItem.
168
* However, this gives rise to the bugs mentioned in sp_object_get_style_property.
169
* Note that some non-SPItem SPObject's, such as SPStop, do need styling information,
170
* and need to inherit properties even through other non-SPItem parents like \<defs\>.
174
/// Switch containing next() method.
175
struct ParentIteratorStrategy {
176
static SPObject const *next(SPObject const *object) {
177
return object->parent;
180
/// Switch containing next() method.
181
struct SiblingIteratorStrategy {
182
static SPObject const *next(SPObject const *object) {
187
typedef Inkscape::Util::ForwardPointerIterator<SPObject, ParentIteratorStrategy> ParentIterator;
188
typedef Inkscape::Util::ForwardPointerIterator<SPObject const, ParentIteratorStrategy> ConstParentIterator;
189
typedef Inkscape::Util::ForwardPointerIterator<SPObject, SiblingIteratorStrategy> SiblingIterator;
190
typedef Inkscape::Util::ForwardPointerIterator<SPObject const, SiblingIteratorStrategy> ConstSiblingIterator;
192
bool isSiblingOf(SPObject const *object) const {
193
g_return_val_if_fail(object != NULL, false);
194
return this->parent && this->parent == object->parent;
196
bool isAncestorOf(SPObject const *object) const;
198
SPObject const *nearestCommonAncestor(SPObject const *object) const;
199
/* A non-const version can be similarly constructed if you want one.
200
* (Don't just cast away the constness, which would be ill-formed.) */
202
bool hasChildren() const { return ( children != NULL ); }
204
SPObject *firstChild() { return children; }
205
SPObject const *firstChild() const { return children; }
206
SPObject *lastChild() { return _last_child; }
207
SPObject const *lastChild() const { return _last_child; }
209
SPObject *appendChildRepr(Inkscape::XML::Node *repr);
211
/** @brief Gets the author-visible label for this object. */
212
gchar const *label() const;
213
/** @brief Returns a default label for this object. */
214
gchar const *defaultLabel() const;
215
/** @brief Sets the author-visible label for this object.
217
* Sets the author-visible label for the object.
219
* @param label the new label
221
void setLabel(gchar const *label);
223
/** Retrieves the title of this object */
224
gchar const *title() const { return NULL; /* TODO */ }
225
/** Sets the title of this object */
226
void setTitle(gchar const *title) { /* TODO */ }
228
/** Retrieves the description of this object */
229
gchar const *desc() const { return NULL; /* TODO */ }
230
/** Sets the description of this object */
231
void setDesc(gchar const *desc) { /* TODO */ }
233
/** @brief Set the policy under which this object will be
236
* Orphan-collection is the process of deleting all objects which no longer have
237
* hyper-references pointing to them. The policy determines when this happens. Many objects
238
* should not be deleted simply because they are no longer referred to; other objects (like
239
* "intermediate" gradients) are more or less throw-away and should always be collected when no
242
* Along these lines, there are currently two orphan-collection policies:
244
* COLLECT_WITH_PARENT - don't worry about the object's hrefcount;
245
* if its parent is collected, this object
248
* COLLECT_ALWAYS - always collect the object as soon as its
249
* hrefcount reaches zero
251
* @returns the current collection policy in effect for this object
253
CollectionPolicy collectionPolicy() const { return _collection_policy; }
255
/** @brief Sets the orphan-collection policy in effect for this object.
257
* @see SPObject::collectionPolicy
259
* @param policy the new policy to adopt
261
void setCollectionPolicy(CollectionPolicy policy) {
262
_collection_policy = policy;
265
/** @brief Requests a later automatic call to collectOrphan().
267
* This method requests that collectOrphan() be called during the document update cycle,
268
* deleting the object if it is no longer used.
270
* If the current collection policy is COLLECT_WITH_PARENT, this function has no effect.
272
* @see SPObject::collectOrphan
274
void requestOrphanCollection();
276
/** @brief Unconditionally delete the object if it is not referenced.
278
* Unconditionally delete the object if there are no outstanding hyper-references to it.
279
* Observers are not notified of the object's deletion (at the SPObject level; XML tree
280
* notifications still fire).
282
* @see SPObject::deleteObject
284
void collectOrphan() {
285
if ( _total_hrefcount == 0 ) {
290
/** @brief Deletes an object.
292
* Detaches the object's repr, and optionally sends notification that the object has been
295
* @param propagate notify observers that the object has been deleted?
297
* @param propagate_descendants notify observers of children that they have been deleted?
299
void deleteObject(bool propagate, bool propagate_descendants);
301
/** @brief Deletes on object.
303
* @param propagate Notify observers of this object and its children that they have been
306
void deleteObject(bool propagate=true) {
307
deleteObject(propagate, propagate);
310
/** @brief Connects a slot to be called when an object is deleted.
312
* This connects a slot to an object's internal delete signal, which is invoked when the object
315
* The signal is mainly useful for e.g. knowing when to break hrefs or dissociate clones.
317
* @param slot the slot to connect
319
* @see SPObject::deleteObject
321
sigc::connection connectDelete(sigc::slot<void, SPObject *> slot) {
322
return _delete_signal.connect(slot);
325
/** @brief Returns the object which supercedes this one (if any).
327
* This is mainly useful for ensuring we can correctly perform a series of moves or deletes,
328
* even if the objects in question have been replaced in the middle of the sequence.
330
SPObject *successor() { return _successor; }
332
/** @brief Indicates that another object supercedes this one. */
333
void setSuccessor(SPObject *successor) {
334
g_assert(successor != NULL);
335
g_assert(_successor == NULL);
336
g_assert(successor->_successor == NULL);
337
sp_object_ref(successor, NULL);
338
_successor = successor;
341
/* modifications; all three sets of methods should probably ultimately be protected, as they
342
* are not really part of its public interface. However, other parts of the code to
343
* occasionally use them at present. */
345
/* the no-argument version of updateRepr() is intended to be a bit more public, however -- it
346
* essentially just flushes any changes back to the backing store (the repr layer); maybe it
347
* should be called something else and made public at that point. */
349
/** @brief Updates the object's repr based on the object's state.
351
* This method updates the the repr attached to the object to reflect the object's current
352
* state; see the two-argument version for details.
354
* @param flags object write flags that apply to this update
356
* @return the updated repr
358
Inkscape::XML::Node *updateRepr(unsigned int flags=SP_OBJECT_WRITE_EXT);
360
/** @brief Updates the given repr based on the object's state.
362
* This method updates the given repr to reflect the object's current state. There are
363
* several flags that affect this:
365
* SP_OBJECT_WRITE_BUILD - create new reprs
367
* SP_OBJECT_WRITE_EXT - write elements and attributes
368
* which are not part of pure SVG
369
* (i.e. the Inkscape and Sodipodi
372
* SP_OBJECT_WRITE_ALL - create all nodes and attributes,
373
* even those which might be redundant
375
* @param repr the repr to update
376
* @param flags object write flags that apply to this update
378
* @return the updated repr
380
Inkscape::XML::Node *updateRepr(Inkscape::XML::Node *repr, unsigned int flags);
382
/** @brief Queues an deferred update of this object's display.
384
* This method sets flags to indicate updates to be performed later, during the idle loop.
386
* There are several flags permitted here:
388
* SP_OBJECT_MODIFIED_FLAG - the object has been modified
390
* SP_OBJECT_CHILD_MODIFIED_FLAG - a child of the object has been
393
* SP_OBJECT_STYLE_MODIFIED_FLAG - the object's style has been
396
* There are also some subclass-specific modified flags which are hardly ever used.
398
* One of either MODIFIED or CHILD_MODIFIED is required.
400
* @param flags flags indicating what to update
402
void requestDisplayUpdate(unsigned int flags);
404
/** @brief Updates the object's display immediately
406
* This method is called during the idle loop by SPDocument in order to update the object's
409
* One additional flag is legal here:
411
* SP_OBJECT_PARENT_MODIFIED_FLAG - the parent has been
414
* @param ctx an SPCtx which accumulates various state
415
* during the recursive update -- beware! some
416
* subclasses try to cast this to an SPItemCtx *
418
* @param flags flags indicating what to update (in addition
419
* to any already set flags)
421
void updateDisplay(SPCtx *ctx, unsigned int flags);
423
/** @brief Requests that a modification notification signal
424
* be emitted later (e.g. during the idle loop)
426
* @param flags flags indicating what has been modified
428
void requestModified(unsigned int flags);
430
/** @brief Emits a modification notification signal
432
* @param flags indicating what has been modified
434
void emitModified(unsigned int flags);
436
void _sendDeleteSignalRecursive();
437
void _updateTotalHRefCount(int increment);
439
void _requireSVGVersion(unsigned major, unsigned minor) {
440
_requireSVGVersion(Inkscape::Version(major, minor));
442
void _requireSVGVersion(Inkscape::Version version);
444
sigc::signal<void, SPObject *> _delete_signal;
445
SPObject *_successor;
446
CollectionPolicy _collection_policy;
448
mutable gchar *_default_label;
451
/// The SPObject vtable.
452
struct SPObjectClass {
453
GObjectClass parent_class;
455
void (* build) (SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr);
456
void (* release) (SPObject *object);
458
/* Virtual handlers of repr signals */
459
void (* child_added) (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref);
460
void (* remove_child) (SPObject *object, Inkscape::XML::Node *child);
462
void (* order_changed) (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *old, Inkscape::XML::Node *new_repr);
464
void (* set) (SPObject *object, unsigned int key, gchar const *value);
466
void (* read_content) (SPObject *object);
469
void (* update) (SPObject *object, SPCtx *ctx, unsigned int flags);
470
/* Modification handler */
471
void (* modified) (SPObject *object, unsigned int flags);
473
Inkscape::XML::Node * (* write) (SPObject *object, Inkscape::XML::Node *repr, unsigned int flags);
478
* Attaching/detaching
481
void sp_object_attach(SPObject *parent, SPObject *object, SPObject *prev);
482
void sp_object_reorder(SPObject *object, SPObject *prev);
483
void sp_object_detach(SPObject *parent, SPObject *object);
485
inline SPObject *sp_object_first_child(SPObject *parent) {
486
return parent->firstChild();
488
SPObject *sp_object_get_child_by_repr(SPObject *object, Inkscape::XML::Node *repr);
490
void sp_object_invoke_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr, unsigned int cloned);
491
void sp_object_invoke_release(SPObject *object);
493
void sp_object_set(SPObject *object, unsigned int key, gchar const *value);
495
void sp_object_read_attr(SPObject *object, gchar const *key);
498
* Get and set descriptive parameters.
500
* These are inefficent, so they are not intended to be used interactively.
503
gchar const *sp_object_title_get(SPObject *object);
504
gchar const *sp_object_description_get(SPObject *object);
505
unsigned int sp_object_title_set(SPObject *object, gchar const *title);
506
unsigned int sp_object_description_set(SPObject *object, gchar const *desc);
510
gchar const *sp_object_tagName_get(SPObject const *object, SPException *ex);
511
gchar const *sp_object_getAttribute(SPObject const *object, gchar const *key, SPException *ex);
512
void sp_object_setAttribute(SPObject *object, gchar const *key, gchar const *value, SPException *ex);
513
void sp_object_removeAttribute(SPObject *object, gchar const *key, SPException *ex);
517
gchar const *sp_object_get_style_property(SPObject const *object,
518
gchar const *key, gchar const *def);
520
Inkscape::Version sp_object_get_sodipodi_version(SPObject *object);
522
int sp_object_compare_position(SPObject const *first, SPObject const *second);
524
SPObject *sp_object_prev(SPObject *child);
533
c-file-style:"stroustrup"
534
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
539
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :