Code

replace Util::SharedCStringPtr with the more general Util::shared_ptr<>
[inkscape.git] / src / xml / simple-node.cpp
1 /*
2  * SimpleNode - simple XML node implementation
3  *
4  * Copyright 2003-2005 MenTaLguY <mental@rydia.net>
5  * Copyright 2003 Nathan Hurst
6  * Copyright 1999-2003 Lauris Kaplinski
7  * Copyright 2000-2002 Ximian Inc.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * See the file COPYING for details.
15  *
16  */
18 #include <glib/gstrfuncs.h>
19 #include "xml/simple-node.h"
20 #include "xml/node-event-vector.h"
21 #include "xml/node-fns.h"
22 #include "xml/repr.h"
23 #include "debug/event-tracker.h"
25 namespace Inkscape {
27 namespace XML {
29 namespace {
31 Util::shared_ptr<char> stringify_node(Node const &node) {
32     gchar *string;
33     switch (node.type()) {
34     case ELEMENT_NODE: {
35         char const *id=node.attribute("id");
36         if (id) {
37             string = g_strdup_printf("element(%p)=%s(#%s)", &node, node.name(), id);
38         } else {
39             string = g_strdup_printf("element(%p)=%s", &node, node.name());
40         }
41     } break;
42     case TEXT_NODE:
43         string = g_strdup_printf("text(%p)=%s", &node, node.content());
44         break;
45     case COMMENT_NODE:
46         string = g_strdup_printf("comment(%p)=<!--%s-->", &node, node.content());
47         break;
48     case DOCUMENT_NODE:
49         string = g_strdup_printf("document(%p)", &node);
50         break;
51     default:
52         string = g_strdup_printf("unknown(%p)", &node);
53     }
54     Util::shared_ptr<char> result=Util::share_string(string);
55     g_free(string);
56     return result;
57 }
59 Util::shared_ptr<char> stringify_unsigned(unsigned n) {
60     gchar *string = g_strdup_printf("%u", n);
61     Util::shared_ptr<char> result=Util::share_string(string);
62     g_free(string);
63     return result;
64 }
66 }
68 class DebugAddChild : public Debug::Event {
69 public:
70     DebugAddChild(Node const &node, Node const &child, Node const *prev)
71     : _parent(stringify_node(node)),
72       _child(stringify_node(child)),
73       _position(prev ? prev->position() + 1 : 0)
74     {}
76     static Category category() { return XML; }
78     Util::shared_ptr<char> name() const {
79         return Util::share_static("add-child");
80     }
81     unsigned propertyCount() const { return 3; }
82     PropertyPair property(unsigned i) const {
83         switch (i) {
84         case 0:
85             return PropertyPair("parent", _parent);
86         case 1:
87             return PropertyPair("child", _child);
88         case 2:
89             return PropertyPair("position", stringify_unsigned(_position));
90         default:
91             return PropertyPair();
92         }
93     }
94 private:
95     Util::shared_ptr<char> _parent;
96     Util::shared_ptr<char> _child;
97     unsigned _position;
98 };
100 class DebugRemoveChild : public Debug::Event {
101 public:
102     DebugRemoveChild(Node const &node, Node const &child, Node const *prev)
103     : _parent(stringify_node(node)),
104       _child(stringify_node(child))
105     {}
107     static Category category() { return XML; }
109     Util::shared_ptr<char> name() const {
110         return Util::share_static("remove-child");
111     }
112     unsigned propertyCount() const { return 2; }
113     PropertyPair property(unsigned i) const {
114         switch (i) {
115         case 0:
116             return PropertyPair("parent", _parent);
117         case 1:
118             return PropertyPair("child", _child);
119         default:
120             return PropertyPair();
121         }
122     }
123 private:
124     Util::shared_ptr<char> _parent;
125     Util::shared_ptr<char> _child;
126 };
128 class DebugSetChildPosition : public Debug::Event {
129 public:
130     DebugSetChildPosition(Node const &node, Node const &child, Node const *old_prev, Node const *new_prev)
131     : _parent(stringify_node(node)),
132       _child(stringify_node(child))
133     {
134         unsigned old_position = ( old_prev ? old_prev->position() : 0 );
135         _position = ( new_prev ? new_prev->position() : 0 );
136         if ( _position > old_position ) {
137             --_position;
138         }
139     }
141     static Category category() { return XML; }
143     Util::shared_ptr<char> name() const {
144         return Util::share_static("set-child-position");
145     }
146     unsigned propertyCount() const { return 3; }
147     PropertyPair property(unsigned i) const {
148         switch (i) {
149         case 0:
150             return PropertyPair("parent", _parent);
151         case 1:
152             return PropertyPair("child", _child);
153         case 2:
154             return PropertyPair("position", stringify_unsigned(_position));
155         default:
156             return PropertyPair();
157         }
158     }
159 private:
160     Util::shared_ptr<char> _parent;
161     Util::shared_ptr<char> _child;
162     unsigned _position;
163 };
165 class DebugSetContent : public Debug::Event {
166 public:
167     DebugSetContent(Node const &node,
168                     Util::shared_ptr<char> old_content,
169                     Util::shared_ptr<char> new_content)
170     : _node(stringify_node(node)), _content(new_content) {}
172     static Category category() { return XML; }
174     Util::shared_ptr<char> name() const {
175         if (_content) {
176             return Util::share_static("set-content");
177         } else {
178             return Util::share_static("clear-content");
179         }
180     }
181     unsigned propertyCount() const {
182         if (_content) {
183             return 2;
184         } else {
185             return 1;
186         }
187     }
188     PropertyPair property(unsigned i) const {
189         switch (i) {
190         case 0:
191             return PropertyPair("node", _node);
192         case 1:
193             return PropertyPair("content", _content);
194         default:
195             return PropertyPair();
196         }
197     }
198 private:
199     Util::shared_ptr<char> _node;
200     Util::shared_ptr<char> _content;
201 };
203 class DebugSetAttribute : public Debug::Event {
204 public:
205     DebugSetAttribute(Node const &node, GQuark name,
206                       Util::shared_ptr<char> old_value,
207                       Util::shared_ptr<char> new_value)
208     : _node(stringify_node(node)),
209       _name(Util::share_unsafe(g_quark_to_string(name))),
210       _value(new_value) {}
212     static Category category() { return XML; }
214     Util::shared_ptr<char> name() const {
215         if (_value) {
216             return Util::share_static("set-attribute");
217         } else {
218             return Util::share_static("clear-attribute");
219         }
220     }
221     unsigned propertyCount() const {
222         if (_value) {
223             return 3;
224         } else {
225             return 2;
226         }
227     }
228     PropertyPair property(unsigned i) const {
229         switch (i) {
230         case 0:
231             return PropertyPair("node", _node);
232         case 1:
233             return PropertyPair("name", _name);
234         case 2:
235             return PropertyPair("value", _value);
236         default:
237             return PropertyPair();
238         }
239     }
241 private:
242     Util::shared_ptr<char> _node;
243     Util::shared_ptr<char> _name;
244     Util::shared_ptr<char> _value;
245 };
247 using Inkscape::Util::shared_ptr;
248 using Inkscape::Util::share_string;
249 using Inkscape::Util::share_unsafe;
250 using Inkscape::Util::share_static;
251 using Inkscape::Util::List;
252 using Inkscape::Util::MutableList;
253 using Inkscape::Util::cons;
254 using Inkscape::Util::rest;
255 using Inkscape::Util::set_rest;
257 SimpleNode::SimpleNode(int code)
258 : Node(), _name(code), _attributes(), _child_count(0),
259   _cached_positions_valid(false)
261     this->_logger = NULL;
262     this->_document = NULL;
263     this->_parent = this->_next = NULL;
264     this->_first_child = this->_last_child = NULL;
267 SimpleNode::SimpleNode(SimpleNode const &node)
268 : Node(),
269   _cached_position(node._cached_position),
270   _name(node._name), _attributes(), _content(node._content),
271   _child_count(node._child_count),
272   _cached_positions_valid(node._cached_positions_valid)
274     _logger = NULL;
275     _document = NULL;
276     _parent = _next = NULL;
277     _first_child = _last_child = NULL;
279     for ( Node *child = node._first_child ;
280           child != NULL ; child = child->next() )
281     {
282         Node *child_copy=child->duplicate();
284         child_copy->_setParent(this);
285         if (_last_child) {
286             _last_child->_setNext(child_copy);
287         } else {
288             _first_child = child_copy;
289         }
290         _last_child = child_copy;
292         child_copy->release(); // release to avoid a leak
293     }
295     for ( List<AttributeRecord const> iter = node._attributes ;
296           iter ; ++iter )
297     {
298         _attributes = cons(*iter, _attributes);
299     }
302 gchar const *SimpleNode::name() const {
303     return g_quark_to_string(_name);
306 gchar const *SimpleNode::content() const {
307     return this->_content;
310 gchar const *SimpleNode::attribute(gchar const *name) const {
311     g_return_val_if_fail(name != NULL, NULL);
313     GQuark const key = g_quark_from_string(name);
315     for ( List<AttributeRecord const> iter = _attributes ;
316           iter ; ++iter )
317     {
318         if ( iter->key == key ) {
319             return iter->value;
320         }
321     }
323     return NULL;
326 unsigned SimpleNode::position() const {
327     g_return_val_if_fail(_parent != NULL, 0);
328     return _parent->_childPosition(*this);
331 unsigned SimpleNode::_childPosition(Node const &child) const {
332     if (!_cached_positions_valid) {
333         unsigned position=0;
334         for ( Node *sibling = _first_child ;
335               sibling ; sibling = sibling->next() )
336         {
337             sibling->_setCachedPosition(position);
338             position++;
339         }
340         _cached_positions_valid = true;
341     }
342     return child._cachedPosition();
345 Node *SimpleNode::nthChild(unsigned index) {
346     Node *child = _first_child;
347     for ( ; index > 0 && child ; child = child->next() ) {
348         index--;
349     }
350     return child;
353 bool SimpleNode::matchAttributeName(gchar const *partial_name) const {
354     g_return_val_if_fail(partial_name != NULL, false);
356     for ( List<AttributeRecord const> iter = _attributes ;
357           iter ; ++iter )
358     {
359         gchar const *name = g_quark_to_string(iter->key);
360         if (std::strstr(name, partial_name)) {
361             return true;
362         }
363     }
365     return false;
368 void SimpleNode::setContent(gchar const *content) {
369     shared_ptr<char> old_content=_content;
370     shared_ptr<char> new_content = ( content ? share_string(content) : shared_ptr<char>() );
372     Debug::EventTracker<DebugSetContent> tracker(
373         *this, old_content, new_content
374     );
376     _content = new_content;
378     if ( _content != old_content ) {
379         if (_logger) {
380             _logger->notifyContentChanged(*this, old_content, _content);
381         }
383         _observers.notifyContentChanged(*this, old_content, _content);
384     }
387 void
388 SimpleNode::setAttribute(gchar const *name, gchar const *value, bool const is_interactive)
390     g_return_if_fail(name && *name);
392     GQuark const key = g_quark_from_string(name);
394     MutableList<AttributeRecord> ref;
395     MutableList<AttributeRecord> existing;
396     for ( existing = _attributes ; existing ; ++existing ) {
397         if ( existing->key == key ) {
398             break;
399         }
400         ref = existing;
401     }
403     Debug::EventTracker<> tracker;
405     shared_ptr<char> old_value=( existing ? existing->value : shared_ptr<char>() );
407     shared_ptr<char> new_value=shared_ptr<char>();
408     if (value) {
409         new_value = share_string(value);
410         tracker.set<DebugSetAttribute>(*this, key, old_value, new_value);
411         if (!existing) {
412             if (ref) {
413                 set_rest(ref, MutableList<AttributeRecord>(AttributeRecord(key, new_value)));
414             } else {
415                 _attributes = MutableList<AttributeRecord>(AttributeRecord(key, new_value));
416             }
417         } else {
418             existing->value = new_value;
419         }
420     } else {
421         tracker.set<DebugSetAttribute>(*this, key, old_value, new_value);
422         if (existing) {
423             if (ref) {
424                 set_rest(ref, rest(existing));
425             } else {
426                 _attributes = rest(existing);
427             }
428             set_rest(existing, MutableList<AttributeRecord>());
429         }
430     }
432     if ( new_value != old_value ) {
433         if (_logger) {
434             _logger->notifyAttributeChanged(*this, key, old_value, new_value);
435         }
437         _observers.notifyAttributeChanged(*this, key, old_value, new_value);
438     }
441 void SimpleNode::addChild(Node *child, Node *ref) {
442     g_assert(child);
443     g_assert(!ref || ref->parent() == this);
444     g_assert(!child->parent());
446     Debug::EventTracker<DebugAddChild> tracker(*this, *child, ref);
448     Node *next;
449     if (ref) {
450         next = ref->next();
451         ref->_setNext(child);
452     } else {
453         next = _first_child;
454         _first_child = child;
455     }
456     if (!next) { // appending?
457         _last_child = child;
458         // set cached position if possible when appending
459         if (!ref) {
460             // if !next && !ref, child is sole child
461             child->_setCachedPosition(0);
462             _cached_positions_valid = true;
463         } else if (_cached_positions_valid) {
464             child->_setCachedPosition(ref->_cachedPosition() + 1);
465         }
466     } else {
467         // invalidate cached positions otherwise
468         _cached_positions_valid = false;
469     }
471     child->_setParent(this);
472     child->_setNext(next);
473     _child_count++;
475     if (_document) {
476         child->_bindDocument(*_document);
477     }
478     if (_logger) {
479         child->_bindLogger(*_logger);
480         _logger->notifyChildAdded(*this, *child, ref);
481     }
483     _observers.notifyChildAdded(*this, *child, ref);
486 void SimpleNode::_bindDocument(Document &document) {
487     g_assert(!_document || _document == &document);
489     if (!_document) {
490         _document = &document;
492         for ( Node *child = _first_child ; child != NULL ; child = child->next() ) {
493             child->_bindDocument(document);
494         }
495     }
498 void SimpleNode::_bindLogger(TransactionLogger &logger) {
499     g_assert(!_logger || _logger == &logger);
501     if (!_logger) {
502         _logger = &logger;
504         for ( Node *child = _first_child ; child != NULL ; child = child->next() ) {
505             child->_bindLogger(logger);
506         }
507     }
510 void SimpleNode::removeChild(Node *child) {
511     g_assert(child);
512     g_assert(child->parent() == this);
514     Node *ref = ( child != _first_child ? previous_node(child) : NULL );
516     Debug::EventTracker<DebugRemoveChild> tracker(*this, *child, ref);
518     Node *next = child->next();
519     if (ref) {
520         ref->_setNext(next);
521     } else {
522         _first_child = next;
523     }
524     if (!next) { // removing the last child?
525         _last_child = ref;
526     } else {
527         // removing any other child invalidates the cached positions
528         _cached_positions_valid = false;
529     }
531     child->_setNext(NULL);
532     child->_setParent(NULL);
533     _child_count--;
535     if (_logger) {
536         _logger->notifyChildRemoved(*this, *child, ref);
537     }
539     _observers.notifyChildRemoved(*this, *child, ref);
542 void SimpleNode::changeOrder(Node *child, Node *ref) {
543     g_return_if_fail(child);
544     g_return_if_fail(child->parent() == this);
545     g_return_if_fail(child != ref);
546     g_return_if_fail(!ref || ref->parent() == this);
548     Node *const prev = previous_node(child);
550     Debug::EventTracker<DebugSetChildPosition> tracker(*this, *child, prev, ref);
552     if (prev == ref) { return; }
554     Node *next;
556     /* Remove from old position. */
557     next=child->next();
558     if (prev) {
559         prev->_setNext(next);
560     } else {
561         _first_child = next;
562     }
563     if (!next) {
564         _last_child = prev;
565     }
567     /* Insert at new position. */
568     if (ref) {
569         next = ref->next();
570         ref->_setNext(child);
571     } else {
572         next = _first_child;
573         _first_child = child;
574     }
575     child->_setNext(next);
576     if (!next) {
577         _last_child = child;
578     }
580     _cached_positions_valid = false;
582     if (_logger) {
583         _logger->notifyChildOrderChanged(*this, *child, prev, ref);
584     }
586     _observers.notifyChildOrderChanged(*this, *child, prev, ref);
589 void SimpleNode::setPosition(int pos) {
590     g_return_if_fail(_parent != NULL);
592     // a position beyond the end of the list means the end of the list;
593     // a negative position is the same as an infinitely large position
595     Node *ref=NULL;
596     for ( Node *sibling = _parent->firstChild() ;
597           sibling && pos ; sibling = sibling->next() )
598     {
599         if ( sibling != this ) {
600             ref = sibling;
601             pos--;
602         }
603     }
605     _parent->changeOrder(this, ref);
608 namespace {
610 void child_added(Node *node, Node *child, Node *ref, void *data) {
611     reinterpret_cast<NodeObserver *>(data)->notifyChildAdded(*node, *child, ref);
614 void child_removed(Node *node, Node *child, Node *ref, void *data) {
615     reinterpret_cast<NodeObserver *>(data)->notifyChildRemoved(*node, *child, ref);
618 void content_changed(Node *node, gchar const *old_content, gchar const *new_content, void *data) {
619     reinterpret_cast<NodeObserver *>(data)->notifyContentChanged(*node, Util::share_unsafe((const char *)old_content), Util::share_unsafe((const char *)new_content));
622 void attr_changed(Node *node, gchar const *name, gchar const *old_value, gchar const *new_value, bool is_interactive, void *data) {
623     reinterpret_cast<NodeObserver *>(data)->notifyAttributeChanged(*node, g_quark_from_string(name), Util::share_unsafe((const char *)old_value), Util::share_unsafe((const char *)new_value));
626 void order_changed(Node *node, Node *child, Node *old_ref, Node *new_ref, void *data) {
627     reinterpret_cast<NodeObserver *>(data)->notifyChildOrderChanged(*node, *child, old_ref, new_ref);
630 const NodeEventVector OBSERVER_EVENT_VECTOR = {
631     &child_added,
632     &child_removed,
633     &attr_changed,
634     &content_changed,
635     &order_changed
636 };
638 };
640 void SimpleNode::synthesizeEvents(NodeEventVector const *vector, void *data) {
641     if (vector->attr_changed) {
642         for ( List<AttributeRecord const> iter = _attributes ;
643               iter ; ++iter )
644         {
645             vector->attr_changed(this, g_quark_to_string(iter->key), NULL, iter->value, false, data);
646         }
647     }
648     if (vector->child_added) {
649         Node *ref = NULL;
650         for ( Node *child = this->_first_child ;
651               child ; child = child->next() )
652         {
653             vector->child_added(this, child, ref, data);
654             ref = child;
655         }
656     }
657     if (vector->content_changed) {
658         vector->content_changed(this, NULL, this->_content, data);
659     }
662 void SimpleNode::synthesizeEvents(NodeObserver &observer) {
663     synthesizeEvents(&OBSERVER_EVENT_VECTOR, &observer);
666 Node *SimpleNode::root() {
667     Node *parent=this;
668     while (parent->parent()) {
669         parent = parent->parent();
670     }
672     if ( parent->type() == DOCUMENT_NODE ) {
673         for ( Node *child = _document->firstChild() ;
674               child ; child = child->next() )
675         {
676             if ( child->type() == ELEMENT_NODE ) {
677                 return child;
678             }
679         }
680         return NULL;
681     } else if ( parent->type() == ELEMENT_NODE ) {
682         return parent;
683     } else {
684         return NULL;
685     }
688 void SimpleNode::mergeFrom(Node const *src, gchar const *key) {
689     g_return_if_fail(src != NULL);
690     g_return_if_fail(key != NULL);
691     g_assert(src != this);
693     setContent(src->content());
695     for ( Node const *child = src->firstChild() ; child != NULL ; child = child->next() )
696     {
697         gchar const *id = child->attribute(key);
698         if (id) {
699             Node *rch=sp_repr_lookup_child(this, key, id);
700             if (rch) {
701                 rch->mergeFrom(child, key);
702             } else {
703                 rch = child->duplicate();
704                 appendChild(rch);
705                 rch->release();
706             }
707         } else {
708             Node *rch=child->duplicate();
709             appendChild(rch);
710             rch->release();
711         }
712     }
714     for ( List<AttributeRecord const> iter = src->attributeList() ;
715           iter ; ++iter )
716     {
717         setAttribute(g_quark_to_string(iter->key), iter->value);
718     }
725 /*
726   Local Variables:
727   mode:c++
728   c-file-style:"stroustrup"
729   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
730   indent-tabs-mode:nil
731   fill-column:99
732   End:
733 */
734 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :