/*************************************************************************** node.cpp - description ------------------- begin : Sun Apr 16 2000 copyright : (C) 2000 by Dmitry Poplavsky <pdima@mail.univ.kiev.ua> (C) 2001-2003 Andras Mantia <amantia@kde.org> ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ //qt includes #include <tqlistview.h> #include <tqdom.h> #include <kdebug.h> #include "node.h" #include "tag.h" #include "qtag.h" #include "quantacommon.h" #include "structtreetag.h" #include "kafkacommon.h" TQMap<Node*, int> nodes; //list of all created nodes. Used to do some own memory management and avoid double deletes, for whatever reason they happen... int NN = 0; //for debugging purposes: count the Node objects GroupElementMapList globalGroupMap; Node::Node(Node *parent) { this->parent = parent; prev = next = child = 0L; tag = 0L; mainListItem = 0L; opened = false; removeAll = true; closesPrevious = false; insideSpecial = false; _closingNode = 0L; m_rootNode = 0L; m_leafNode = 0L; m_groupElements.clear(); NN++; // if (nodes.contains(this) == 0) nodes[this] = 1; // else // { // kdError(24000) << "A node with this address " << this << " already exists!" << endl; // } } bool Node::deleteNode(Node *node) { if (!node) return true; if (!nodes.contains(node)) { kdDebug(24000) << "Trying to delete a node with address " << node << " that was not allocated!" << endl; return false; } delete node; return true; } Node::~Node() { // if (!nodes.contains(this)) // { // kdError(24000) << "No node with this address " << this << " was allocated!" << endl; // return; // } //It has no use, except to know when it crash why it has crashed. //If it has crashed here, the Node doesn't exist anymore. // If it has crashed the next line, it is a GroupElements bug. //FIXME: Andras: or it is a VPL undo/redo bug... Q_ASSERT(tag); if (tag) tag->setCleanStrBuilt(false); detachNode(); nodes.erase(this); if (prev && prev->next == this) prev->next = 0L; if (parent && parent->child == this) parent->child = 0L; if (removeAll) { deleteNode(child); child = 0L; deleteNode(next); next = 0L; } else { if (next && next->prev == this) next->prev = 0L; if (child && child->parent == this) child->parent = 0L; } delete tag; tag = 0L; delete m_rootNode; delete m_leafNode; NN--; } void Node::save(TQDomElement& element) const { //kdDebug(25001) << "Save:\n" << element.ownerDocument().toString() << endl; TQDomElement child_element; if(next) { child_element = element.ownerDocument().createElement("nodeNext"); element.appendChild(child_element); next->save(child_element); } if(child) { child_element = element.ownerDocument().createElement("nodeChild"); element.appendChild(child_element); child->save(child_element); } if(_closingNode) { if(_closingNode != next) { child_element = element.ownerDocument().createElement("nodeClosing"); element.appendChild(child_element); _closingNode->save(child_element); } } Q_ASSERT(tag); child_element = element.ownerDocument().createElement("tag"); element.appendChild(child_element); tag->save(child_element); element.setAttribute("closesPrevious", closesPrevious); // bool element.setAttribute("opened", opened); // bool element.setAttribute("removeAll", removeAll); // bool element.setAttribute("insideSpecial", insideSpecial); // bool element.setAttribute("specialInsideXml", specialInsideXml); // bool element.setAttribute("fileName", fileName); // TQString /* TQString s_element; TQTextStream stream(&s_element, IO_WriteOnly); element.save(stream, 3);*/ //kdDebug(25001) << "Load:\n" << s_element << endl; //kdDebug(25001) << "Save:\n" << element.ownerDocument().toString() << endl; } bool Node::load(TQDomElement const& element) { /* TQString s_element; TQTextStream stream(&s_element, IO_WriteOnly); element.save(stream, 3);*/ //kdDebug(25001) << "Load:\n" << s_element << endl; TQDomNodeList list = element.childNodes(); for(unsigned int i = 0; i != list.count(); ++i) { if(list.item(i).isElement()) { TQDomElement e = list.item(i).toElement(); if(e.tagName() == "nodeNext") { next = new Node(0); next->prev = this; next->parent = this->parent; next->load(e); } else if(e.tagName() == "nodeChild") { child = new Node(0); child->parent = this; child->load(e); } else if(e.tagName() == "nodeClosing") { _closingNode = new Node(0); _closingNode->load(e); } else if(e.tagName() == "tag") { tag = new Tag(); tag->load(e); } } } closesPrevious = TQString(element.attribute("closesPrevious")).toInt(); // bool opened = TQString(element.attribute("opened")).toInt(); // bool removeAll = TQString(element.attribute("removeAll")).toInt(); // bool insideSpecial = TQString(element.attribute("insideSpecial")).toInt(); // bool specialInsideXml = TQString(element.attribute("specialInsideXml")).toInt(); // bool fileName = element.attribute("fileName"); // TQString //kafkaCommon::coutTree(this, 3); return true; } Node *Node::nextSibling() { Node *result = 0L; if (child) { result = child; } else if (next) { result = next; } else { Node *n = this; while (n) { if (n->parent && n->parent->next) { result = n->parent->next; break; } else { n = n->parent; } } } return result; } Node *Node::previousSibling() { Node *result = 0L; if (prev) { Node *n = prev; while (n->child) { n = n->child; while (n->next) n = n->next; } result = n; } else { result = parent; } return result; } Node *Node::nextNotChild() { if (next) return next; else { Node *n = this; while (n) { if (n->parent && n->parent->next) { n = n->parent->next; break; } else { n = n->parent; } } return n; } } TQString Node::nodeName() { if(tag) return tag->name; return TQString(); } TQString Node::nodeValue() { if(tag) return tag->tagStr(); return TQString(); } void Node::setNodeValue(const TQString &value) { if(!tag) tag = new Tag(); tag->setStr(value); kdDebug(24000) << "Node::setNodeValue: dtd is 0L for " << value << endl; } Node* Node::lastChild() { Node *n, *m = 0; n = child; while(n) { m = n; n = n->next; } return m; } Node *Node::nextNE() { Node *n = next; while(n && n->tag->type == Tag::Empty) n = n->next; return n; } Node *Node::prevNE() { Node *n = prev; while(n && n->tag->type == Tag::Empty) n = n->prev; return n; } Node *Node::firstChildNE() { Node *n = child; while(n && n->tag->type == Tag::Empty) n = n->next; return n; } Node *Node::lastChildNE() { Node *n = lastChild(); while(n && n->tag->type == Tag::Empty) n = n->prev; return n; } Node *Node::SPrev() { Node *node = prev; int bCol, bLine, eCol, eLine, col, line; if(parent) { parent->tag->beginPos(bLine, bCol); parent->tag->endPos(eLine, eCol); } while(node && node->tag->type != Tag::XmlTag && node->tag->type != Tag::Text) { if (parent && node->tag->type == Tag::ScriptTag) { //Check if it is an embedded ScriptTag. If it is, continue. node->tag->beginPos(line, col); if(QuantaCommon::isBetween(line, col, bLine, bCol, eLine, eCol) != 0) break; } node = node->prev; } return node; } Node *Node::SNext() { Node *node = next; int bCol, bLine, eCol, eLine, col, line; if(parent) { tag->beginPos(bLine, bCol); tag->endPos(eLine, eCol); } while(node && node->tag->type != Tag::XmlTag && node->tag->type != Tag::Text) { if (parent && node->tag->type == Tag::ScriptTag) { //Check if it is an embedded ScriptTag. If it is, continue. node->tag->beginPos(line, col); if(QuantaCommon::isBetween(line, col, bLine, bCol, eLine, eCol) != 0) break; } node = node->next; } return node; } Node *Node::SFirstChild() { Node *node = child; int bCol, bLine, eCol, eLine, col, line; tag->beginPos(bLine, bCol); tag->endPos(eLine, eCol); while(node && node->tag->type != Tag::XmlTag && node->tag->type != Tag::Text) { if(node->tag->type == Tag::ScriptTag) { //Check if it is an embedded ScriptTag. If it is, continue. node->tag->beginPos(line, col); if(QuantaCommon::isBetween(line, col, bLine, bCol, eLine, eCol) != 0) break; } node = node->next; } return node; } Node *Node::SLastChild() { Node *node = lastChild(); int bCol, bLine, eCol, eLine, col, line; tag->beginPos(bLine, bCol); tag->endPos(eLine, eCol); while(node && node->tag->type != Tag::XmlTag && node->tag->type != Tag::Text) { if(node->tag->type == Tag::ScriptTag) { //Check if it is an embedded ScriptTag. If it is, continue. node->tag->beginPos(line, col); if(QuantaCommon::isBetween(line, col, bLine, bCol, eLine, eCol) != 0) break; } node = node->prev; } return node; } bool Node::hasForChild(Node *node) { //TODO: NOT EFFICIENT AT ALL!! Change by using kafkaCommon::getLocation() and compare! Node *n; bool goUp = false; if(child) { n = child; goUp = false; while(n) { if(n == node) return true; n = kafkaCommon::getNextNode(n, goUp, this); } } return false; } Node *Node::getClosingNode() { Node* n = next; if(next && tag && (tag->type == Tag::XmlTag || tag->type == Tag::ScriptTag) && !tag->single) { while (n && n->tag->type == Tag::Empty) n = n->next; if (n && n->tag->type == Tag::XmlTagEnd && ((tag->type == Tag::XmlTag && QuantaCommon::closesTag(tag, n->tag)) || (tag->type == Tag::ScriptTag && n->tag->name.isEmpty()))) return n; } return 0L; } Node *Node::getOpeningNode() { Node *n = prev; if(prev && tag && tag->type == Tag::XmlTagEnd) { while(n && n->tag->type == Tag::Empty) n = n->prev; if(n && ((n->tag->type == Tag::XmlTag && QuantaCommon::closesTag(n->tag, tag)) || (n->tag->type == Tag::ScriptTag && tag->name.isEmpty()))) return n; } return 0L; } int Node::size() { int l = tag->size(); l += 5*sizeof(Node*) + sizeof(TQListViewItem*) + 2*sizeof(Tag*) + 2*sizeof(DOM::Node); return l; } void Node::operator =(Node* node) { (*this) = (*node); prev = 0L; next = 0L; parent = 0L; child = 0L; mainListItem = 0L; m_groupElements.clear(); setRootNode(0L); setLeafNode(0L); tag = new Tag(*(node->tag)); } void Node::detachNode() { if (nodes.contains(this) == 0) { kdError(24000) << "No node with this address " << this << " was allocated!" << endl; return; } int count = 0; //kdDebug(24000) << &m_groupElements << " " << this << endl; //Remove the references to this node from the list of group elements. //They are actually stored in globalGroupMap. for (TQValueListIterator<GroupElement*> it = m_groupElements.begin(); it != m_groupElements.end(); ++it) { GroupElement *groupElement = (*it); groupElement->node = 0L; groupElement->deleted = true; groupElement->group = 0L; #ifdef DEBUG_PARSER kdDebug(24001) << "GroupElement scheduled for deletion: " << groupElement << " "<< groupElement->tag->area().bLine << " " << groupElement->tag->area().bCol << " "<< groupElement->tag->area().eLine << " "<< groupElement->tag->area().eCol << " " << groupElement->tag->tagStr() << " " << groupElement->type << endl; #endif count++; } #ifdef DEBUG_PARSER if (count > 0) kdDebug(24001) << count << " GroupElement scheduled for deletion. " << &m_groupElements << endl; #endif TQValueListIterator<TQListViewItem*> listItem; for ( listItem = listItems.begin(); listItem != listItems.end(); ++listItem) { static_cast<StructTreeTag*>(*listItem)->node = 0L; static_cast<StructTreeTag*>(*listItem)->groupTag = 0L; } mainListItem = 0L; listItems.clear(); m_groupElements.clear(); //kdDebug(24000) << m_groupElements.count() << " " << this << endl; }