1 /*
2 * The reference corresponding to href of <use> element.
3 *
4 * Copyright (C) 2004 Bulia Byak
5 * Copyright (C) 2004 Monash University
6 *
7 * Released under GNU GPL, read the file 'COPYING' for more information.
8 */
10 #include <string.h>
12 #include "enums.h"
13 #include "sp-use-reference.h"
15 #include "display/curve.h"
16 #include "livarot/Path.h"
17 #include "prefs-utils.h"
18 #include "sp-shape.h"
19 #include "sp-text.h"
20 #include "uri.h"
24 bool SPUseReference::_acceptObject(SPObject * const obj) const
25 {
26 if (SP_IS_ITEM(obj)) {
27 SPObject * const owner = getOwner();
28 /* Refuse references to us or to an ancestor. */
29 for ( SPObject *iter = owner ; iter ; iter = SP_OBJECT_PARENT(iter) ) {
30 if ( iter == obj ) {
31 return false;
32 }
33 }
34 return true;
35 } else {
36 return false;
37 }
38 }
41 static void sp_usepath_href_changed(SPObject *old_ref, SPObject *ref, SPUsePath *offset);
42 static void sp_usepath_move_compensate(NR::Matrix const *mp, SPItem *original, SPUsePath *self);
43 static void sp_usepath_delete_self(SPObject *deleted, SPUsePath *offset);
44 static void sp_usepath_source_modified(SPObject *iSource, guint flags, SPUsePath *offset);
46 SPUsePath::SPUsePath(SPObject* i_owner):SPUseReference(i_owner)
47 {
48 owner=i_owner;
49 originalPath = NULL;
50 sourceDirty=false;
51 sourceHref = NULL;
52 sourceRepr = NULL;
53 sourceObject = NULL;
54 _changed_connection = changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_usepath_href_changed), this)); // listening to myself, this should be virtual instead
56 user_unlink = NULL;
57 }
59 SPUsePath::~SPUsePath(void)
60 {
61 delete originalPath;
62 originalPath = NULL;
64 _changed_connection.disconnect(); // to do before unlinking
66 quit_listening();
67 unlink();
68 }
70 void
71 SPUsePath::link(char *to)
72 {
73 if ( to == NULL ) {
74 quit_listening();
75 unlink();
76 } else {
77 if ( !sourceHref || ( strcmp(to, sourceHref) != 0 ) ) {
78 g_free(sourceHref);
79 sourceHref = g_strdup(to);
80 try {
81 attach(Inkscape::URI(to));
82 } catch (Inkscape::BadURIException &e) {
83 /* TODO: Proper error handling as per
84 * http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing.
85 */
86 g_warning("%s", e.what());
87 detach();
88 }
89 }
90 }
91 }
93 void
94 SPUsePath::unlink(void)
95 {
96 g_free(sourceHref);
97 sourceHref = NULL;
98 detach();
99 }
101 void
102 SPUsePath::start_listening(SPObject* to)
103 {
104 if ( to == NULL ) {
105 return;
106 }
107 sourceObject = to;
108 sourceRepr = SP_OBJECT_REPR(to);
109 _delete_connection = to->connectDelete(sigc::bind(sigc::ptr_fun(&sp_usepath_delete_self), this));
110 _transformed_connection = SP_ITEM(to)->connectTransformed(sigc::bind(sigc::ptr_fun(&sp_usepath_move_compensate), this));
111 _modified_connection = to->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_usepath_source_modified), this));
112 }
114 void
115 SPUsePath::quit_listening(void)
116 {
117 if ( sourceObject == NULL ) {
118 return;
119 }
120 _modified_connection.disconnect();
121 _delete_connection.disconnect();
122 _transformed_connection.disconnect();
123 sourceRepr = NULL;
124 sourceObject = NULL;
125 }
127 static void
128 sp_usepath_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPUsePath *offset)
129 {
130 offset->quit_listening();
131 SPItem *refobj = offset->getObject();
132 if ( refobj ) {
133 offset->start_listening(refobj);
134 }
135 offset->sourceDirty=true;
136 SP_OBJECT(offset->owner)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
137 }
139 static void
140 sp_usepath_move_compensate(NR::Matrix const *mp, SPItem *original, SPUsePath *self)
141 {
142 guint mode = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_PARALLEL);
143 if (mode == SP_CLONE_COMPENSATION_NONE) {
144 return;
145 }
146 SPItem *item = SP_ITEM(self->owner);
148 // TODO kill naughty naughty #if 0
149 #if 0
150 NR::Matrix m(*mp);
151 if (!(m.is_translation())) {
152 return;
153 }
154 NR::Matrix const t(item->transform);
155 NR::Matrix clone_move = t.inverse() * m * t;
157 // Calculate the compensation matrix and the advertized movement matrix.
158 NR::Matrix advertized_move;
159 if (mode == SP_CLONE_COMPENSATION_PARALLEL) {
160 //clone_move = clone_move.inverse();
161 advertized_move.set_identity();
162 } else if (mode == SP_CLONE_COMPENSATION_UNMOVED) {
163 clone_move = clone_move.inverse() * m;
164 advertized_move = m;
165 } else {
166 g_assert_not_reached();
167 }
169 // Commit the compensation.
170 item->transform *= clone_move;
171 sp_item_write_transform(item, SP_OBJECT_REPR(item), item->transform, &advertized_move);
172 #else
173 (void)mp;
174 (void)original;
175 #endif
177 self->sourceDirty = true;
178 SP_OBJECT(item)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
179 }
181 static void
182 sp_usepath_delete_self(SPObject */*deleted*/, SPUsePath *offset)
183 {
184 guint const mode = prefs_get_int_attribute("options.cloneorphans", "value", SP_CLONE_ORPHANS_UNLINK);
186 if (mode == SP_CLONE_ORPHANS_UNLINK) {
187 // leave it be. just forget about the source
188 offset->quit_listening();
189 offset->unlink();
190 if (offset->user_unlink)
191 offset->user_unlink(offset->owner);
192 } else if (mode == SP_CLONE_ORPHANS_DELETE) {
193 offset->owner->deleteObject();
194 }
195 }
197 static void
198 sp_usepath_source_modified(SPObject */*iSource*/, guint /*flags*/, SPUsePath *offset)
199 {
200 offset->sourceDirty = true;
201 offset->owner->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
202 }
204 void SPUsePath::refresh_source()
205 {
206 sourceDirty = false;
207 delete originalPath;
208 originalPath = NULL;
210 // le mauvais cas: pas d'attribut d => il faut verifier que c'est une SPShape puis prendre le contour
211 // [tr: The bad case: no d attribute. Must check that it's a SPShape and then take the outline.]
212 SPObject *refobj = sourceObject;
213 if ( refobj == NULL ) return;
214 SPItem *item = SP_ITEM(refobj);
216 SPCurve *curve = NULL;
217 if (!SP_IS_SHAPE(item) && !SP_IS_TEXT(item)) {
218 return;
219 }
220 if (SP_IS_SHAPE(item)) {
221 curve = sp_shape_get_curve(SP_SHAPE(item));
222 if (curve == NULL)
223 return;
224 }
225 if (SP_IS_TEXT(item)) {
226 curve = SP_TEXT(item)->getNormalizedBpath();
227 if (curve == NULL) {
228 return;
229 }
230 }
231 originalPath = new Path;
232 originalPath->LoadArtBPath(SP_CURVE_BPATH(curve), NR::Matrix(item->transform), true);
233 sp_curve_unref(curve);
234 }
237 /*
238 Local Variables:
239 mode:c++
240 c-file-style:"stroustrup"
241 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
242 indent-tabs-mode:nil
243 fill-column:99
244 End:
245 */
246 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :