1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * The reference corresponding to the inkscape:live-effect attribute
4  *
5  * Copyright (C) 2007 Johan Engelen
6  *
7  * Released under GNU GPL v2+, read the file 'COPYING' for more information.
8  */
9 
10 #include "live_effects/lpeobject-reference.h"
11 
12 #include <cstring>
13 
14 #include "bad-uri-exception.h"
15 #include "live_effects/lpeobject.h"
16 #include "object/uri.h"
17 
18 namespace Inkscape {
19 
20 namespace LivePathEffect {
21 
22 static void lpeobjectreference_href_changed(SPObject *old_ref, SPObject *ref, LPEObjectReference *lpeobjref);
23 static void lpeobjectreference_delete_self(SPObject *deleted, LPEObjectReference *lpeobjref);
24 static void lpeobjectreference_source_modified(SPObject *iSource, guint flags, LPEObjectReference *lpeobjref);
25 
LPEObjectReference(SPObject * i_owner)26 LPEObjectReference::LPEObjectReference(SPObject* i_owner) : URIReference(i_owner)
27 {
28     owner=i_owner;
29     lpeobject_href = nullptr;
30     lpeobject_repr = nullptr;
31     lpeobject = nullptr;
32     _changed_connection = changedSignal().connect(sigc::bind(sigc::ptr_fun(lpeobjectreference_href_changed), this)); // listening to myself, this should be virtual instead
33 
34     user_unlink = nullptr;
35 }
36 
~LPEObjectReference()37 LPEObjectReference::~LPEObjectReference()
38 {
39     _changed_connection.disconnect(); // to do before unlinking
40 
41     quit_listening();
42     unlink();
43 }
44 
_acceptObject(SPObject * const obj) const45 bool LPEObjectReference::_acceptObject(SPObject * const obj) const
46 {
47     LivePathEffectObject *lpobj = dynamic_cast<LivePathEffectObject *>(obj);
48     if (lpobj) {
49         return URIReference::_acceptObject(obj);
50     } else {
51         return false;
52     }
53 }
54 
55 void
link(const char * to)56 LPEObjectReference::link(const char *to)
57 {
58     if (!to || !to[0]) {
59         quit_listening();
60         unlink();
61     } else {
62         if ( !lpeobject_href || ( strcmp(to, lpeobject_href) != 0 ) ) {
63             if (lpeobject_href) {
64                 g_free(lpeobject_href);
65             }
66             lpeobject_href = g_strdup(to);
67             try {
68                 attach(Inkscape::URI(to));
69             } catch (Inkscape::BadURIException &e) {
70                 /* TODO: Proper error handling as per
71                  * http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing.
72                  */
73                 g_warning("%s", e.what());
74                 detach();
75             }
76         }
77     }
78 }
79 
80 void
unlink()81 LPEObjectReference::unlink()
82 {
83     if (lpeobject_href) {
84         g_free(lpeobject_href);
85         lpeobject_href = nullptr;
86     }
87     detach();
88 }
89 
90 void
start_listening(LivePathEffectObject * to)91 LPEObjectReference::start_listening(LivePathEffectObject* to)
92 {
93     if ( to == nullptr ) {
94         return;
95     }
96     lpeobject = to;
97     lpeobject_repr = to->getRepr();
98     _delete_connection = to->connectDelete(sigc::bind(sigc::ptr_fun(&lpeobjectreference_delete_self), this));
99     _modified_connection = to->connectModified(sigc::bind<2>(sigc::ptr_fun(&lpeobjectreference_source_modified), this));
100 }
101 
102 void
quit_listening()103 LPEObjectReference::quit_listening()
104 {
105     _modified_connection.disconnect();
106     _delete_connection.disconnect();
107     lpeobject_repr = nullptr;
108     lpeobject = nullptr;
109 }
110 
111 static void
lpeobjectreference_href_changed(SPObject *,SPObject *,LPEObjectReference * lpeobjref)112 lpeobjectreference_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, LPEObjectReference *lpeobjref)
113 {
114     lpeobjref->quit_listening();
115     LivePathEffectObject *refobj = dynamic_cast<LivePathEffectObject *>( lpeobjref->getObject() );
116     if ( refobj ) {
117         lpeobjref->start_listening(refobj);
118     }
119     if (lpeobjref->owner) {
120         lpeobjref->owner->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
121     }
122 }
123 
124 static void
lpeobjectreference_delete_self(SPObject *,LPEObjectReference * lpeobjref)125 lpeobjectreference_delete_self(SPObject */*deleted*/, LPEObjectReference *lpeobjref)
126 {
127     lpeobjref->quit_listening();
128     lpeobjref->unlink();
129     if (lpeobjref->user_unlink) {
130         lpeobjref->user_unlink(lpeobjref, lpeobjref->owner);
131     }
132 }
133 
134 static void
lpeobjectreference_source_modified(SPObject *,guint,LPEObjectReference * lpeobjref)135 lpeobjectreference_source_modified(SPObject */*iSource*/, guint /*flags*/, LPEObjectReference *lpeobjref)
136 {
137 //    We dont need to request update when LPE XML is updated
138 //    Retain it temporary, drop if no regression
139 //    SPObject *owner_obj = lpeobjref->owner;
140 //    if (owner_obj) {
141 //        lpeobjref->owner->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
142 //    }
143 }
144 
145 } //namespace LivePathEffect
146 
147 } // namespace inkscape
148 
149 /*
150   Local Variables:
151   mode:c++
152   c-file-style:"stroustrup"
153   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
154   indent-tabs-mode:nil
155   fill-column:99
156   End:
157 */
158 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
159