index 17339271fc0549135bbf3e97d70bc32332a4e108..3cca393d228366d7b013d9109d7c207ebaddd85f 100644 (file)
--- a/src/xml/simple-node.cpp
+++ b/src/xml/simple-node.cpp
-/*
- * SimpleNode - simple XML node implementation
- *
- * Copyright 2003-2005 MenTaLguY <mental@rydia.net>
+/** @file
+ * @brief Garbage collected XML node implementation
+ */
+/* Copyright 2003-2005 MenTaLguY <mental@rydia.net>
* Copyright 2003 Nathan Hurst
* Copyright 1999-2003 Lauris Kaplinski
* Copyright 2000-2002 Ximian Inc.
* of the License, or (at your option) any later version.
*
* See the file COPYING for details.
- *
*/
+#include <cstring>
+#include <string>
#include <glib/gstrfuncs.h>
+
#include "xml/simple-node.h"
#include "xml/node-event-vector.h"
#include "xml/node-fns.h"
#include "xml/repr.h"
#include "debug/event-tracker.h"
+#include "debug/simple-event.h"
+#include "util/share.h"
+#include "util/format.h"
namespace Inkscape {
return result;
}
-Util::ptr_shared<char> stringify_unsigned(unsigned n) {
- gchar *string = g_strdup_printf("%u", n);
- Util::ptr_shared<char> result=Util::share_string(string);
- g_free(string);
- return result;
-}
+typedef Debug::SimpleEvent<Debug::Event::XML> DebugXML;
-}
+class DebugXMLNode : public DebugXML {
+public:
+ DebugXMLNode(Node const &node, Util::ptr_shared<char> name)
+ : DebugXML(name)
+ {
+ _addProperty("node", stringify_node(node));
+ }
+};
-class DebugAddChild : public Debug::Event {
+class DebugAddChild : public DebugXMLNode {
public:
DebugAddChild(Node const &node, Node const &child, Node const *prev)
- : _parent(stringify_node(node)),
- _child(stringify_node(child)),
- _position(prev ? prev->position() + 1 : 0)
- {}
-
- static Category category() { return XML; }
-
- Util::ptr_shared<char> name() const {
- return Util::share_static_string("add-child");
- }
- unsigned propertyCount() const { return 3; }
- PropertyPair property(unsigned i) const {
- switch (i) {
- case 0:
- return PropertyPair("parent", _parent);
- case 1:
- return PropertyPair("child", _child);
- case 2:
- return PropertyPair("position", stringify_unsigned(_position));
- default:
- return PropertyPair();
- }
+ : DebugXMLNode(node, Util::share_static_string("add-child"))
+ {
+ _addProperty("child", stringify_node(child));
+ _addProperty("position", Util::format("%d", ( prev ? prev->position() + 1 : 0 )));
}
-private:
- Util::ptr_shared<char> _parent;
- Util::ptr_shared<char> _child;
- unsigned _position;
};
-class DebugRemoveChild : public Debug::Event {
+class DebugRemoveChild : public DebugXMLNode {
public:
- DebugRemoveChild(Node const &node, Node const &child, Node const *prev)
- : _parent(stringify_node(node)),
- _child(stringify_node(child))
- {}
-
- static Category category() { return XML; }
-
- Util::ptr_shared<char> name() const {
- return Util::share_static_string("remove-child");
- }
- unsigned propertyCount() const { return 2; }
- PropertyPair property(unsigned i) const {
- switch (i) {
- case 0:
- return PropertyPair("parent", _parent);
- case 1:
- return PropertyPair("child", _child);
- default:
- return PropertyPair();
- }
+ DebugRemoveChild(Node const &node, Node const &child)
+ : DebugXMLNode(node, Util::share_static_string("remove-child"))
+ {
+ _addProperty("child", stringify_node(child));
}
-private:
- Util::ptr_shared<char> _parent;
- Util::ptr_shared<char> _child;
};
-class DebugSetChildPosition : public Debug::Event {
+class DebugSetChildPosition : public DebugXMLNode {
public:
- DebugSetChildPosition(Node const &node, Node const &child, Node const *old_prev, Node const *new_prev)
- : _parent(stringify_node(node)),
- _child(stringify_node(child))
+ DebugSetChildPosition(Node const &node, Node const &child,
+ Node const *old_prev, Node const *new_prev)
+ : DebugXMLNode(node, Util::share_static_string("set-child-position"))
{
+ _addProperty("child", stringify_node(child));
+
unsigned old_position = ( old_prev ? old_prev->position() : 0 );
- _position = ( new_prev ? new_prev->position() : 0 );
- if ( _position > old_position ) {
- --_position;
+ unsigned position = ( new_prev ? new_prev->position() : 0 );
+ if ( position > old_position ) {
+ --position;
}
- }
-
- static Category category() { return XML; }
- Util::ptr_shared<char> name() const {
- return Util::share_static_string("set-child-position");
+ _addProperty("position", Util::format("%d", position));
}
- unsigned propertyCount() const { return 3; }
- PropertyPair property(unsigned i) const {
- switch (i) {
- case 0:
- return PropertyPair("parent", _parent);
- case 1:
- return PropertyPair("child", _child);
- case 2:
- return PropertyPair("position", stringify_unsigned(_position));
- default:
- return PropertyPair();
- }
- }
-private:
- Util::ptr_shared<char> _parent;
- Util::ptr_shared<char> _child;
- unsigned _position;
};
-class DebugSetContent : public Debug::Event {
+class DebugSetContent : public DebugXMLNode {
public:
DebugSetContent(Node const &node,
- Util::ptr_shared<char> old_content,
- Util::ptr_shared<char> new_content)
- : _node(stringify_node(node)), _content(new_content) {}
+ Util::ptr_shared<char> content)
+ : DebugXMLNode(node, Util::share_static_string("set-content"))
+ {
+ _addProperty("content", content);
+ }
+};
- static Category category() { return XML; }
+class DebugClearContent : public DebugXMLNode {
+public:
+ DebugClearContent(Node const &node)
+ : DebugXMLNode(node, Util::share_static_string("clear-content"))
+ {}
+};
- Util::ptr_shared<char> name() const {
- if (_content) {
- return Util::share_static_string("set-content");
- } else {
- return Util::share_static_string("clear-content");
- }
- }
- unsigned propertyCount() const {
- if (_content) {
- return 2;
- } else {
- return 1;
- }
- }
- PropertyPair property(unsigned i) const {
- switch (i) {
- case 0:
- return PropertyPair("node", _node);
- case 1:
- return PropertyPair("content", _content);
- default:
- return PropertyPair();
- }
+class DebugSetAttribute : public DebugXMLNode {
+public:
+ DebugSetAttribute(Node const &node,
+ GQuark name,
+ Util::ptr_shared<char> value)
+ : DebugXMLNode(node, Util::share_static_string("set-attribute"))
+ {
+ _addProperty("name", Util::share_static_string(g_quark_to_string(name)));
+ _addProperty("value", value);
}
-private:
- Util::ptr_shared<char> _node;
- Util::ptr_shared<char> _content;
};
-class DebugSetAttribute : public Debug::Event {
+class DebugClearAttribute : public DebugXMLNode {
public:
- DebugSetAttribute(Node const &node, GQuark name,
- Util::ptr_shared<char> old_value,
- Util::ptr_shared<char> new_value)
- : _node(stringify_node(node)),
- _name(Util::share_unsafe(g_quark_to_string(name))),
- _value(new_value) {}
-
- static Category category() { return XML; }
-
- Util::ptr_shared<char> name() const {
- if (_value) {
- return Util::share_static_string("set-attribute");
- } else {
- return Util::share_static_string("clear-attribute");
- }
- }
- unsigned propertyCount() const {
- if (_value) {
- return 3;
- } else {
- return 2;
- }
- }
- PropertyPair property(unsigned i) const {
- switch (i) {
- case 0:
- return PropertyPair("node", _node);
- case 1:
- return PropertyPair("name", _name);
- case 2:
- return PropertyPair("value", _value);
- default:
- return PropertyPair();
- }
+ DebugClearAttribute(Node const &node, GQuark name)
+ : DebugXMLNode(node, Util::share_static_string("clear-attribute"))
+ {
+ _addProperty("name", Util::share_static_string(g_quark_to_string(name)));
}
-
-private:
- Util::ptr_shared<char> _node;
- Util::ptr_shared<char> _name;
- Util::ptr_shared<char> _value;
};
-using Inkscape::Util::ptr_shared;
-using Inkscape::Util::share_string;
-using Inkscape::Util::share_unsafe;
-using Inkscape::Util::share_static_string;
-using Inkscape::Util::List;
-using Inkscape::Util::MutableList;
-using Inkscape::Util::cons;
-using Inkscape::Util::rest;
-using Inkscape::Util::set_rest;
-
-SimpleNode::SimpleNode(int code)
+}
+
+using Util::ptr_shared;
+using Util::share_string;
+using Util::share_unsafe;
+using Util::share_static_string;
+using Util::List;
+using Util::MutableList;
+using Util::cons;
+using Util::rest;
+using Util::set_rest;
+
+SimpleNode::SimpleNode(int code, Document *document)
: Node(), _name(code), _attributes(), _child_count(0),
_cached_positions_valid(false)
{
- this->_logger = NULL;
- this->_document = NULL;
+ g_assert(document != NULL);
+
+ this->_document = document;
this->_parent = this->_next = NULL;
this->_first_child = this->_last_child = NULL;
+
+ _observers.add(_subtree_observers);
}
-SimpleNode::SimpleNode(SimpleNode const &node)
+SimpleNode::SimpleNode(SimpleNode const &node, Document *document)
: Node(),
_cached_position(node._cached_position),
_name(node._name), _attributes(), _content(node._content),
_child_count(node._child_count),
_cached_positions_valid(node._cached_positions_valid)
{
- _logger = NULL;
- _document = NULL;
+ g_assert(document != NULL);
+
+ _document = document;
_parent = _next = NULL;
_first_child = _last_child = NULL;
- for ( Node *child = node._first_child ;
- child != NULL ; child = child->next() )
+ for ( SimpleNode *child = node._first_child ;
+ child != NULL ; child = child->_next )
{
- Node *child_copy=child->duplicate();
+ SimpleNode *child_copy=dynamic_cast<SimpleNode *>(child->duplicate(document));
child_copy->_setParent(this);
if (_last_child) {
- _last_child->_setNext(child_copy);
+ _last_child->_next = child_copy;
} else {
_first_child = child_copy;
}
{
_attributes = cons(*iter, _attributes);
}
+
+ _observers.add(_subtree_observers);
}
gchar const *SimpleNode::name() const {
return _parent->_childPosition(*this);
}
-unsigned SimpleNode::_childPosition(Node const &child) const {
+unsigned SimpleNode::_childPosition(SimpleNode const &child) const {
if (!_cached_positions_valid) {
unsigned position=0;
- for ( Node *sibling = _first_child ;
- sibling ; sibling = sibling->next() )
+ for ( SimpleNode *sibling = _first_child ;
+ sibling ; sibling = sibling->_next )
{
- sibling->_setCachedPosition(position);
+ sibling->_cached_position = position;
position++;
}
_cached_positions_valid = true;
}
- return child._cachedPosition();
+ return child._cached_position;
}
Node *SimpleNode::nthChild(unsigned index) {
- Node *child = _first_child;
- for ( ; index > 0 && child ; child = child->next() ) {
+ SimpleNode *child = _first_child;
+ for ( ; index > 0 && child ; child = child->_next ) {
index--;
}
return child;
return false;
}
+void SimpleNode::_setParent(SimpleNode *parent) {
+ if (_parent) {
+ _subtree_observers.remove(_parent->_subtree_observers);
+ }
+ _parent = parent;
+ if (parent) {
+ _subtree_observers.add(parent->_subtree_observers);
+ }
+}
+
void SimpleNode::setContent(gchar const *content) {
ptr_shared<char> old_content=_content;
ptr_shared<char> new_content = ( content ? share_string(content) : ptr_shared<char>() );
- Debug::EventTracker<DebugSetContent> tracker(
- *this, old_content, new_content
- );
+ Debug::EventTracker<> tracker;
+ if (new_content) {
+ tracker.set<DebugSetContent>(*this, new_content);
+ } else {
+ tracker.set<DebugClearContent>(*this);
+ }
_content = new_content;
if ( _content != old_content ) {
- if (_logger) {
- _logger->notifyContentChanged(*this, old_content, _content);
- }
-
+ _document->logger()->notifyContentChanged(*this, old_content, _content);
_observers.notifyContentChanged(*this, old_content, _content);
}
}
void
-SimpleNode::setAttribute(gchar const *name, gchar const *value, bool const is_interactive)
+SimpleNode::setAttribute(gchar const *name, gchar const *value, bool const /*is_interactive*/)
{
g_return_if_fail(name && *name);
@@ -407,7 +328,7 @@ SimpleNode::setAttribute(gchar const *name, gchar const *value, bool const is_in
ptr_shared<char> new_value=ptr_shared<char>();
if (value) {
new_value = share_string(value);
- tracker.set<DebugSetAttribute>(*this, key, old_value, new_value);
+ tracker.set<DebugSetAttribute>(*this, key, new_value);
if (!existing) {
if (ref) {
set_rest(ref, MutableList<AttributeRecord>(AttributeRecord(key, new_value)));
@@ -418,7 +339,7 @@ SimpleNode::setAttribute(gchar const *name, gchar const *value, bool const is_in
existing->value = new_value;
}
} else {
- tracker.set<DebugSetAttribute>(*this, key, old_value, new_value);
+ tracker.set<DebugClearAttribute>(*this, key);
if (existing) {
if (ref) {
set_rest(ref, rest(existing));
@@ -430,25 +351,28 @@ SimpleNode::setAttribute(gchar const *name, gchar const *value, bool const is_in
}
if ( new_value != old_value && (!old_value || !new_value || strcmp(old_value, new_value))) {
- if (_logger) {
- _logger->notifyAttributeChanged(*this, key, old_value, new_value);
- }
-
+ _document->logger()->notifyAttributeChanged(*this, key, old_value, new_value);
_observers.notifyAttributeChanged(*this, key, old_value, new_value);
}
}
-void SimpleNode::addChild(Node *child, Node *ref) {
- g_assert(child);
- g_assert(!ref || ref->parent() == this);
- g_assert(!child->parent());
+void SimpleNode::addChild(Node *generic_child, Node *generic_ref) {
+ g_assert(generic_child);
+ g_assert(generic_child->document() == _document);
+ g_assert(!generic_ref || generic_ref->document() == _document);
+
+ SimpleNode *child=dynamic_cast<SimpleNode *>(generic_child);
+ SimpleNode *ref=dynamic_cast<SimpleNode *>(generic_ref);
+
+ g_assert(!ref || ref->_parent == this);
+ g_assert(!child->_parent);
Debug::EventTracker<DebugAddChild> tracker(*this, *child, ref);
- Node *next;
+ SimpleNode *next;
if (ref) {
- next = ref->next();
- ref->_setNext(child);
+ next = ref->_next;
+ ref->_next = child;
} else {
next = _first_child;
_first_child = child;
// set cached position if possible when appending
if (!ref) {
// if !next && !ref, child is sole child
- child->_setCachedPosition(0);
+ child->_cached_position = 0;
_cached_positions_valid = true;
} else if (_cached_positions_valid) {
- child->_setCachedPosition(ref->_cachedPosition() + 1);
+ child->_cached_position = ref->_cached_position + 1;
}
} else {
// invalidate cached positions otherwise
}
child->_setParent(this);
- child->_setNext(next);
+ child->_next = next;
_child_count++;
- if (_document) {
- child->_bindDocument(*_document);
- }
- if (_logger) {
- child->_bindLogger(*_logger);
- _logger->notifyChildAdded(*this, *child, ref);
- }
-
+ _document->logger()->notifyChildAdded(*this, *child, ref);
_observers.notifyChildAdded(*this, *child, ref);
}
-void SimpleNode::_bindDocument(Document &document) {
- g_assert(!_document || _document == &document);
-
- if (!_document) {
- _document = &document;
+void SimpleNode::removeChild(Node *generic_child) {
+ g_assert(generic_child);
+ g_assert(generic_child->document() == _document);
- for ( Node *child = _first_child ; child != NULL ; child = child->next() ) {
- child->_bindDocument(document);
- }
- }
-}
+ SimpleNode *child=dynamic_cast<SimpleNode *>(generic_child);
+ SimpleNode *ref=dynamic_cast<SimpleNode *>(previous_node(child));
-void SimpleNode::_bindLogger(TransactionLogger &logger) {
- g_assert(!_logger || _logger == &logger);
+ g_assert(child->_parent == this);
- if (!_logger) {
- _logger = &logger;
+ Debug::EventTracker<DebugRemoveChild> tracker(*this, *child);
- for ( Node *child = _first_child ; child != NULL ; child = child->next() ) {
- child->_bindLogger(logger);
- }
- }
-}
-
-void SimpleNode::removeChild(Node *child) {
- g_assert(child);
- g_assert(child->parent() == this);
-
- Node *ref = ( child != _first_child ? previous_node(child) : NULL );
-
- Debug::EventTracker<DebugRemoveChild> tracker(*this, *child, ref);
-
- Node *next = child->next();
+ SimpleNode *next = child->_next;
if (ref) {
- ref->_setNext(next);
+ ref->_next = next;
} else {
_first_child = next;
}
_cached_positions_valid = false;
}
- child->_setNext(NULL);
+ child->_next = NULL;
child->_setParent(NULL);
_child_count--;
- if (_logger) {
- _logger->notifyChildRemoved(*this, *child, ref);
- }
-
+ _document->logger()->notifyChildRemoved(*this, *child, ref);
_observers.notifyChildRemoved(*this, *child, ref);
}
-void SimpleNode::changeOrder(Node *child, Node *ref) {
- g_return_if_fail(child);
+void SimpleNode::changeOrder(Node *generic_child, Node *generic_ref) {
+ g_assert(generic_child);
+ g_assert(generic_child->document() == this->_document);
+ g_assert(!generic_ref || generic_ref->document() == this->_document);
+
+ SimpleNode *const child=dynamic_cast<SimpleNode *>(generic_child);
+ SimpleNode *const ref=dynamic_cast<SimpleNode *>(generic_ref);
+
g_return_if_fail(child->parent() == this);
g_return_if_fail(child != ref);
g_return_if_fail(!ref || ref->parent() == this);
- Node *const prev = previous_node(child);
+ SimpleNode *const prev=dynamic_cast<SimpleNode *>(previous_node(child));
Debug::EventTracker<DebugSetChildPosition> tracker(*this, *child, prev, ref);
if (prev == ref) { return; }
- Node *next;
+ SimpleNode *next;
/* Remove from old position. */
- next=child->next();
+ next = child->_next;
if (prev) {
- prev->_setNext(next);
+ prev->_next = next;
} else {
_first_child = next;
}
/* Insert at new position. */
if (ref) {
- next = ref->next();
- ref->_setNext(child);
+ next = ref->_next;
+ ref->_next = child;
} else {
next = _first_child;
_first_child = child;
}
- child->_setNext(next);
+ child->_next = next;
if (!next) {
_last_child = child;
}
_cached_positions_valid = false;
- if (_logger) {
- _logger->notifyChildOrderChanged(*this, *child, prev, ref);
- }
-
+ _document->logger()->notifyChildOrderChanged(*this, *child, prev, ref);
_observers.notifyChildOrderChanged(*this, *child, prev, ref);
}
// a position beyond the end of the list means the end of the list;
// a negative position is the same as an infinitely large position
- Node *ref=NULL;
- for ( Node *sibling = _parent->firstChild() ;
- sibling && pos ; sibling = sibling->next() )
+ SimpleNode *ref=NULL;
+ for ( SimpleNode *sibling = _parent->_first_child ;
+ sibling && pos ; sibling = sibling->_next )
{
if ( sibling != this ) {
ref = sibling;
@@ -619,7 +515,7 @@ void content_changed(Node *node, gchar const *old_content, gchar const *new_cont
reinterpret_cast<NodeObserver *>(data)->notifyContentChanged(*node, Util::share_unsafe((const char *)old_content), Util::share_unsafe((const char *)new_content));
}
-void attr_changed(Node *node, gchar const *name, gchar const *old_value, gchar const *new_value, bool is_interactive, void *data) {
+void attr_changed(Node *node, gchar const *name, gchar const *old_value, gchar const *new_value, bool /*is_interactive*/, void *data) {
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));
}
}
}
if (vector->child_added) {
- Node *ref = NULL;
- for ( Node *child = this->_first_child ;
- child ; child = child->next() )
+ SimpleNode *ref = NULL;
+ for ( SimpleNode *child = this->_first_child ;
+ child ; child = child->_next )
{
vector->child_added(this, child, ref, data);
ref = child;
if (rch) {
rch->mergeFrom(child, key);
} else {
- rch = child->duplicate();
+ rch = child->duplicate(_document);
appendChild(rch);
rch->release();
}
} else {
- Node *rch=child->duplicate();
+ Node *rch=child->duplicate(_document);
appendChild(rch);
rch->release();
}
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :