--- /dev/null
+
+#include <sstream>
+
+#include "globals.hh"
+#include "dom.hh"
+#include "TDocument.hh"
+
+TDocument::TDocument()
+{
+ DOM::DOMImplementation di;
+ DOM::DocumentType dt;
+ doc = di.createDocument(TML_NS_URI, "tml:tex", dt);
+ DOM::Element root = doc.get_documentElement();
+ root.setAttributeNS(XMLNS_NS_URI, "xmlns:tml", TML_NS_URI);
+ assert(root);
+
+ DOM::EventTarget et(doc);
+ assert(et);
+ et.addEventListener("DOMSubtreeModified", *this, false);
+}
+
+TDocument::~TDocument()
+{
+ //DOM::Element root = doc.get_documentElement();
+ DOM::EventTarget et(doc);
+ assert(doc);
+ et.removeEventListener("DOMSubtreeModified", *this, false);
+}
+
+void
+TDocument::serialize(const char* filename) const
+{
+ DOM::DOMImplementation di;
+ di.saveDocumentToFile(doc, filename, GDOME_SAVE_LIBXML_INDENT);
+}
+
+TNode
+TDocument::create(const std::string& name, unsigned id) const
+{
+ DOM::Element elem = doc.createElementNS(TML_NS_URI, "tml:" + name);
+ if (id > 0)
+ {
+ ostringstream os;
+ os << "I" << id;
+ elem.setAttribute("id", os.str());
+ }
+ return elem;
+}
+
+TNode
+TDocument::createC(const std::string& name, unsigned id) const
+{
+ TNode m = create("c", id);
+ m["name"] = name;
+ return m;
+}
+
+TNode
+TDocument::createT(const std::string& name, const std::string& text, unsigned id) const
+{
+ TNode t = create(name, id);
+ t["val"] = text;
+ return t;
+}
+
+unsigned
+TDocument::nodeDepth(const DOM::Node& node)
+{
+ DOM::Node n = node;
+
+ unsigned depth = 0;
+ while (n)
+ {
+ depth++;
+ n = n.get_parentNode();
+ }
+ return depth;
+}
+
+DOM::Node
+TDocument::findCommonAncestor(const DOM::Node& node1, const DOM::Node& node2)
+{
+ DOM::Node n1 = node1;
+ DOM::Node n2 = node2;
+
+ unsigned d1 = nodeDepth(n1);
+ unsigned d2 = nodeDepth(n2);
+
+ cout << "finding common ancestor " << d1 << " " << d2 << endl;
+
+ while (d1 < d2)
+ {
+ assert(n2);
+ n2 = n2.get_parentNode();
+ d2--;
+ }
+
+ while (d1 > d2)
+ {
+ assert(n1);
+ n1 = n1.get_parentNode();
+ d1--;
+ }
+
+ while (n1 != n2)
+ {
+ assert(n1);
+ assert(n2);
+ n1 = n1.get_parentNode();
+ n2 = n2.get_parentNode();
+ }
+
+ return n1;
+}
+
+DOM::Node
+TDocument::findIdNode(const DOM::Node& node)
+{
+ DOM::Node n = node;
+ while (n)
+ {
+ if (n.get_nodeType() == DOM::Node::ELEMENT_NODE)
+ {
+ DOM::Element el = n;
+ if (el.hasAttribute("id")) return el;
+ }
+ n = n.get_parentNode();
+ }
+
+ return DOM::Node(0);
+}
+
+void
+TDocument::handleEvent(const DOM::Event& ev)
+{
+ DOM::MutationEvent me(ev);
+ assert(me);
+
+ if (dirty)
+ cout << "TDocument::handleEvent DIRTY BEFORE = " << dirty.getAttribute("id") << endl;
+ else
+ cout << "TDocument::handleEvent DIRTY BEFORE = (nil)" << endl;
+
+ if (DOM::Node node = me.get_target())
+ if (dirty)
+ dirty = findIdNode(findCommonAncestor(dirty, node));
+ else
+ dirty = findIdNode(node);
+ else
+ assert(0);
+
+ cout << "TDocument::handleEvent target = " << DOM::Node(me.get_target()).get_nodeName() << " DIRTY AFTER = "
+ << dirty.getAttribute("id") << " ME = " << DOM::Node(me.get_target()).get_nodeName() << endl;
+
+}