You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
560 lines
14 KiB
560 lines
14 KiB
/***************************************************************************
|
|
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); // QString
|
|
|
|
/* 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"); // QString
|
|
|
|
//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::null;
|
|
}
|
|
|
|
TQString Node::nodeValue()
|
|
{
|
|
if(tag)
|
|
return tag->tagStr();
|
|
return TQString::null;
|
|
}
|
|
|
|
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;
|
|
}
|