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.
tdewebdev/quanta/parts/kafka/kafkacommon.cpp

4258 lines
140 KiB

/***************************************************************************
kafkacommon.cpp
-------------------
copyright : (C) 2003, 2004 - Nicolas Deschildre
email : ndeschildre@kdewebdev.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. *
* *
***************************************************************************/
#include <qptrdict.h>
#include <kdebug.h>
#include <dom/dom_exception.h>
#include <dom/dom_doc.h>
#include <dom/dom_element.h>
#include <dom/dom_text.h>
#include "node.h"
#include "tag.h"
#include "document.h"
#include "resource.h"
#include "quantacommon.h"
#include "kafkacommon.h"
#include "wkafkapart.h"
#include "undoredo.h"
#include "cursors.h"
#include <cassert>
Node *kafkaCommon::getNextNode(Node *node, bool &goUp, Node *endNode)
{
//goto next node, my favorite part :)
if(!node || node == endNode)
return 0L;
if(goUp)
{
if(node->next)
{
goUp = false;
if(node->next == endNode)
return 0L;
return node->next;
}
else
{
if(node->parent == endNode)
return 0L;
return getNextNode(node->parent, goUp);
}
}
else
{
if(node->child)
{
if(node->child == endNode)
return 0L;
return node->child;
}
else if(node->next)
{
if(node->next == endNode)
return 0L;
return node->next;
}
else
{
goUp = true;
if(node->parent == endNode)
return 0L;
return getNextNode(node->parent, goUp);
}
}
}
Node* kafkaCommon::getNextNodeNE(Node *node, bool &goUp, Node *endNode)
{
Node *n = node;
n = getNextNode(n, goUp, endNode);
while(n && n->tag->type == Tag::Empty)
n = getNextNode(n, goUp, endNode);
return n;
}
Node* kafkaCommon::getPrevNode(Node *node, Node *endNode)
{
Node *n = node;
if(!node)
return 0L;
if(n->prev && n->prev->child)
{
n = n->prev;
if(n == endNode)
return 0L;
while(n->child)
{
n = n->child;
while(n && n->next)
n = n->next;
if(n == endNode)
return 0L;
}
}
else if(n->prev)
{
n = n->prev;
if(n == endNode)
return 0L;
}
else
{
n = n->parent;
if(n == endNode)
return 0L;
}
return n;
}
Node* kafkaCommon::getPrevNodeNE(Node *node, Node *endNode)
{
Node *n = node;
n = getPrevNode(node, endNode);
while(n && n->tag->type == Tag::Empty)
n = getPrevNode(n, endNode);
return n;
}
Node* kafkaCommon::DTDGetCommonParent(Node* startNode, Node* endNode,
QValueList<int>& commonParentStartChildLocation,
QValueList<int>& commonParentEndChildLocation, Node* nodeSubtree)
{
// look for commonParent
Node* commonParent = 0;
Node* commonParentStartChild = 0, *commonParentEndChild = 0;
int locOffset = 1;
QValueList<int> startNodeLocation = getLocation(startNode);
QValueList<int> endNodeLocation = getLocation(endNode);
QValueList<int>::iterator itStart = startNodeLocation.begin();
QValueList<int>::iterator itEnd = endNodeLocation.begin();
while(itStart != startNodeLocation.end() && itEnd != endNodeLocation.end() &&
(*itStart) == (*itEnd))
{
commonParent = getNodeFromSubLocation(startNodeLocation, locOffset, nodeSubtree);
itStart++;
itEnd++;
locOffset++;
}
//look for commonParentStartChild and commonParentEndChild
if(itStart != startNodeLocation.end())
commonParentStartChild = getNodeFromSubLocation(startNodeLocation, locOffset, nodeSubtree);
else
commonParentStartChild = commonParent;
if(itEnd != endNodeLocation.end())
commonParentEndChild = getNodeFromSubLocation(endNodeLocation, locOffset, nodeSubtree);
else
commonParentEndChild = commonParent;
//If commonParent isn't inline, move commonParent to the closest non inline node
if(commonParent && (commonParent->tag->type == Tag::Text || commonParent->tag->type == Tag::Empty))
{
Node* oldCommonParent = commonParent;
commonParent = commonParent->parent;
commonParentStartChild = oldCommonParent;
commonParentEndChild = oldCommonParent;
}
//startNode or endNode can't be the commonParent.
else if(commonParent && (itStart == startNodeLocation.end() || itEnd == endNodeLocation.end()))
commonParent = commonParent->parent;
commonParentStartChildLocation = getLocation(commonParentStartChild);
commonParentEndChildLocation = getLocation(commonParentEndChild);
return commonParent;
}
Node* kafkaCommon::DTDGetNonInlineCommonParent(Node* startNode, Node* endNode,
QValueList<int>& commonParentStartChildLocation,
QValueList<int>& commonParentEndChildLocation, Node* nodeSubtree)
{
// look for commonParent
Node* commonParent = 0;
Node* commonParentStartChild = 0, *commonParentEndChild = 0;
int locOffset = 1;
QValueList<int> startNodeLocation = getLocation(startNode);
QValueList<int> endNodeLocation = getLocation(endNode);
QValueList<int>::iterator itStart = startNodeLocation.begin();
QValueList<int>::iterator itEnd = endNodeLocation.begin();
while(itStart != startNodeLocation.end() && itEnd != endNodeLocation.end() &&
(*itStart) == (*itEnd))
{
commonParent = getNodeFromSubLocation(startNodeLocation, locOffset, nodeSubtree);
itStart++;
itEnd++;
locOffset++;
}
//look for commonParentStartChild and commonParentEndChild
if(itStart != startNodeLocation.end())
commonParentStartChild = getNodeFromSubLocation(startNodeLocation, locOffset, nodeSubtree);
else
commonParentStartChild = commonParent;
if(itEnd != endNodeLocation.end())
commonParentEndChild = getNodeFromSubLocation(endNodeLocation, locOffset, nodeSubtree);
else
commonParentEndChild = commonParent;
//If commonParent isn't inline, move commonParent to the closest non inline node
if(commonParent && (isInline(commonParent->tag->name) ||
commonParent->tag->type == Tag::Text || commonParent->tag->type == Tag::Empty))
{
Node* oldCommonParent = commonParent;
commonParent = commonParent->parent;
while(commonParent && isInline(commonParent->tag->name))
{
oldCommonParent = commonParent;
commonParent = commonParent->parent;
}
commonParentStartChild = oldCommonParent;
commonParentEndChild = oldCommonParent;
}
//startNode or endNode can't be the commonParent.
else if(commonParent && (itStart == startNodeLocation.end() || itEnd == endNodeLocation.end()))
commonParent = commonParent->parent;
commonParentStartChildLocation = getLocation(commonParentStartChild);
commonParentEndChildLocation = getLocation(commonParentEndChild);
return commonParent;
}
DOM::Node kafkaCommon::getNextDomNode(DOM::Node node, bool &goUp, bool returnParentNode, DOM::Node endNode)
{
if(node.isNull())
return 0L;
if(node.hasChildNodes() && !goUp)
{
if(endNode == node.firstChild())
return 0L;
else
return node.firstChild();
}
else if(!node.nextSibling().isNull())
{
goUp = false;
if(endNode == node.nextSibling())
return 0L;
else
return node.nextSibling();
}
else
{
goUp = true;
if(node.parentNode().isNull() || endNode == node.parentNode())
return 0L;
if(returnParentNode)
return node.parentNode();
else
return getNextDomNode(node.parentNode(), goUp, returnParentNode, endNode);
}
}
DOM::Node kafkaCommon::getPrevDomNode(DOM::Node node, DOM::Node endNode)
{
DOM::Node n = node;
if(node.isNull())
return 0L;
if(!n.previousSibling().isNull() && !n.previousSibling().firstChild().isNull())
{
n = n.previousSibling();
if(n == endNode)
return 0L;
while(!n.firstChild().isNull())
{
n = n.firstChild();
while(!n.isNull() && !n.nextSibling().isNull())
n = n.nextSibling();
if(n == endNode)
return 0L;
}
}
else if(!n.previousSibling().isNull())
{
n = n.previousSibling();
if(n == endNode)
return 0L;
}
else
{
n = n.parentNode();
if(n == endNode)
return 0L;
}
return n;
}
Node* kafkaCommon::getCorrectStartNode(Node* startNode, int& start_offset)
{
Node* start_node = startNode;
while(start_node && (start_node->tag->type != Tag::Text || (uint)start_offset == start_node->tag->tagStr().length()))
{
start_node = start_node->nextSibling();
if(start_node->tag->type == Tag::Text || start_node->tag->type == Tag::Empty)
{
start_offset = 0;
break;
}
}
return start_node;
}
Node* kafkaCommon::getCorrectEndNode(Node* endNode, int& end_offset)
{
Node* end_node = endNode;
while(end_node && (end_node->tag->type != Tag::Text || end_offset == 0))
{
end_node = end_node->previousSibling();
if(end_node && end_node->tag->type == Tag::Text)
{
end_offset = end_node->tag->tagStr().length();
break;
}
}
return end_node;
}
Node* kafkaCommon::getCommonParentChild(Node* node, Node* commonParent)
{
assert(node && commonParent);
Node* aux = commonParent->child;
assert(aux);
while(aux && aux != node)
{
if(aux->hasForChild(node))
return aux;
aux = aux->nextSibling();
}
return aux;
}
void kafkaCommon::applyIndentation(Node *node, int nbOfSpaces, int nbOfTabs, NodeModifsSet* modifs, bool inlineNodeIndentation)
{
#ifdef LIGHT_DEBUG
kdDebug(25001)<< "kafkaCommon::applyIndentation()" << endl;
#endif
Node *parent, *nextNE, *prevNE, *realPrevNE, *realNextNE, *realPrev, *realNext, *prev, *next;
int nonInlineDepth = 0, nonInlineDepth2 = 0, i;
bool b = false;
QString indentation1, indentation2, text;
if(!node)
return;
prev = node->previousSibling();
next = node->nextSibling();
prevNE = getPrevNodeNE(node);
nextNE = getNextNodeNE(node, b);
realPrevNE = node->prevNE();
realNextNE = node->nextNE();
realPrev = node->prev;
realNext = node->next;
if(inlineNodeIndentation &&
!node->prev && getNodeDisplay(node->parent, true) == kafkaCommon::blockDisplay)
{
AreaStruct node_area = node->tag->area();
AreaStruct parent_area = node->parent->tag->area();
if(node_area.bLine == parent_area.bLine)
{
node->tag->setIndentationDone(true);
return;
}
}
//First remove all the indentation
if(node->tag->type == Tag::Text)
setTagString(node, removeUnnecessaryWhitespaces(node->tag->tagStr()), modifs);
//compute the "non-inline depth" of the Node and of the next NE (not Empty) Node
// i.e. we count how many non-inline parent they have.
parent = node->parent;
while(parent)
{
if(getNodeDisplay(parent, true) == kafkaCommon::blockDisplay)
++nonInlineDepth;
parent = parent->parent;
}
//compute the "non-inline depth" of the next non-empty Node.
if (nextNE)
parent = nextNE->parent;
else
parent = 0L;
while(parent)
{
if(getNodeDisplay(parent, true) == kafkaCommon::blockDisplay)
++nonInlineDepth2;
parent = parent->parent;
}
parent = node->parent;
if(!parent || getNodeDisplay(parent, true) == kafkaCommon::blockDisplay)
{
//prepare the indentation
indentation1 = "\n";
indentation2 = "\n";
if(nbOfSpaces == 0) // tabs are used
{
indentation1 += QString().fill('\t', nbOfTabs * nonInlineDepth);
indentation2 += QString().fill('\t', nbOfTabs * nonInlineDepth2);
}
else // spaces are used
{
indentation1 += QString().fill(' ', nbOfSpaces * nonInlineDepth);
indentation2 += QString().fill(' ', nbOfSpaces * nonInlineDepth2);
}
//test and add indentations if necessary
if(!prevNE || (prevNE && getNodeDisplay(node, true) ==
kafkaCommon::blockDisplay) ||
(prevNE && getNodeDisplay(node, true) == kafkaCommon::inlineDisplay &&
getNodeDisplay(prevNE, true) == kafkaCommon::blockDisplay))
{
if(node->tag->type == Tag::Text && !hasParent(node, "pre"))
{
setTagStringAndFitsNodes(node, indentation1 + node->tag->tagStr(), modifs);
}
else if(prev && prev->tag->type == Tag::Empty)
{
setTagStringAndFitsNodes(prev, indentation1, modifs);
}
//The indentation is always done at the left because we apply this function "from left to right"
else if(prev && prev->tag->type == Tag::Text /** && prev->tag->indentationDone() */)
{
//Remove the indentation at the right of the text Node
text = prev->tag->tagStr();
for(i = 0; (unsigned)i < text.length(); ++i)
{
if(!text[i].isSpace())
break;
}
if(i == 0)
prev->tag->setStr(removeUnnecessaryWhitespaces(text));
else
prev->tag->setStr(text.mid(0, i) + removeUnnecessaryWhitespaces(text, true));
setTagStringAndFitsNodes(prev, prev->tag->tagStr() + indentation1, modifs);
}
}
if(!nextNE || (nextNE && getNodeDisplay(node, true) ==
kafkaCommon::blockDisplay) ||
(nextNE && getNodeDisplay(node, true) == kafkaCommon::inlineDisplay &&
getNodeDisplay(nextNE, true) == kafkaCommon::blockDisplay))
{
if(node->tag->type == Tag::Text && !hasParent(node, "pre"))
{
setTagStringAndFitsNodes(node, node->tag->tagStr() + indentation2, modifs);
}
else if(next && next->tag->type == Tag::Empty)
{
setTagStringAndFitsNodes(next, indentation2, modifs);
}
//If next's cleanStrBuilt is not true, the next node to be processed will be this
//one and the indentation spaces will be handled as real spaces.
else if(next && next->tag->type == Tag::Text && next->tag->indentationDone())
{
//Remove the indentation at the left of the text Node
text = next->tag->tagStr();
for(i = text.length() - 1; i <= 0; i--)
{
if(!text[i].isSpace())
break;
}
if((unsigned)i == text.length() - 1)
next->tag->setStr(removeUnnecessaryWhitespaces(text));
else
next->tag->setStr(removeUnnecessaryWhitespaces(text, false, true) +
text.mid(i + 1));
setTagStringAndFitsNodes(next, indentation2 + next->tag->tagStr(), modifs);
}
}
}
else
{
//The parent is inline, so no indentation.
//Nothing to do.
}
node->tag->setIndentationDone(true);
}
void kafkaCommon::fitIndentationNodes(Node *n1, Node *n2, NodeModifsSet *modifs)
{
#ifdef LIGHT_DEBUG
kdDebug(25001)<< "kafkaCommon::fitIndentationNodes()" << endl;
#endif
Node *parent, *child, *node, *emptyNode = 0L, *emptyNode2 = 0L;
int nbEmptyNodes = 0, n1Depth, n2Depth;
bool lastChild = false, firstChild = false;
if(!n1 || !n2 || n1 == n2 || n1->tag->type == Tag::Empty || n2->tag->type == Tag::Empty)
return;
n1Depth = nodeDepth(n1);
n2Depth = nodeDepth(n2);
if(n1Depth != n2Depth)
{
if(n1Depth > n2Depth)
{
child = n1;
parent = n2;
}
else
{
child = n2;
parent = n1;
}
if(child->parent->firstChildNE() == child)
firstChild = true;
if(child->parent->lastChildNE() == child)
lastChild = true;
//counting the Empty Nodes and deleting them to have only one empty node.
if(firstChild)
{
node = child->prev;
while(node)
{
if(node->tag->type == Tag::Empty)
nbEmptyNodes++;
node = node->prev;
}
node = child->prev;
while(nbEmptyNodes > 1)
{
extractAndDeleteNode(node, modifs, false, false, false);
nbEmptyNodes--;
node = child->prev;
}
if(nbEmptyNodes == 1)
emptyNode = child->prev;
}
nbEmptyNodes = 0;
if(lastChild)
{
node = child->next;
while(node)
{
if(node->tag->type == Tag::Empty)
nbEmptyNodes++;
node = node->next;
}
node = child->next;
while(nbEmptyNodes > 1)
{
extractAndDeleteNode(node, modifs, false, false, false);
nbEmptyNodes--;
node = child->next;
}
if(nbEmptyNodes == 1)
emptyNode2 = child->next;
}
//adding/deleting a empty node if necessary
if(firstChild)
{
if(getNodeDisplay(parent, true) == kafkaCommon::blockDisplay)
{
if(child->tag->type != Tag::Text && !emptyNode)
{
createAndInsertNode("", "", Tag::Empty, n2->tag->write(), child->parent,
child, child, modifs);
}
}
else
{
if(child->tag->type == Tag::Text && emptyNode)
{
extractAndDeleteNode(emptyNode, modifs, false, false, false);
}
}
}
if(lastChild)
{
if(getNodeDisplay(parent, true) == kafkaCommon::blockDisplay)
{
if(child->tag->type != Tag::Text && !emptyNode2)
{
createAndInsertNode("", "", Tag::Empty, n2->tag->write(), child->parent,
0L, 0L, modifs);
}
}
else
{
if(child->tag->type == Tag::Text && emptyNode2)
{
extractAndDeleteNode(emptyNode2, modifs, false, false, false);
}
}
}
}
else
{
if(n1->next != n2)
{
//counting the Empty Nodes and deleting them to have only one empty node.
node = n1->next;
while(node && node != n2)
{
if(node->tag->type == Tag::Empty)
nbEmptyNodes++;
node = node->next;
}
node = n1->next;
while(nbEmptyNodes > 1 || (nbEmptyNodes > 0 && n1->getClosingNode() == n2))
{
extractAndDeleteNode(node, modifs, false, false, false);
nbEmptyNodes--;
node = n1->next;
}
if(nbEmptyNodes == 1)
emptyNode = n1->next;
if(n1->getClosingNode() == n2 && n1->child && n1->child->tag->type == Tag::Empty)
emptyNode = n1->child;
}
//adding/deleting a empty node if necessary
parent = n1->parent;
if(!parent || getNodeDisplay(parent, true) == kafkaCommon::blockDisplay)
{
if(getNodeDisplay(n1, true) == kafkaCommon::blockDisplay &&
n1->tag->type != Tag::Text)
{
if(n2->tag->type == Tag::Text && emptyNode)
{
extractAndDeleteNode(emptyNode, modifs, false, false, false);
}
else if(n2->tag->type != Tag::Text && !emptyNode)
{
if(n1->getClosingNode() == n2)
{
createAndInsertNode("", "", Tag::Empty, n2->tag->write(), n1, 0L, 0L, modifs);
}
else
{
createAndInsertNode("", "", Tag::Empty, n2->tag->write(), parent, n2, n2, modifs);
}
}
}
else
{
if((n2->tag->type == Tag::Text ||
getNodeDisplay(n2, true) == kafkaCommon::inlineDisplay) &&
emptyNode)
{
extractAndDeleteNode(emptyNode, modifs, false, false, false);
}
else if(n2->tag->type != Tag::Text &&
getNodeDisplay(n2, true) == kafkaCommon::blockDisplay &&
n1->tag->type != Tag::Text && !emptyNode)
{
if(n1->getClosingNode() == n2)
{
createAndInsertNode("", "", Tag::Empty, n2->tag->write(), n1, 0L, 0L, modifs);
}
else
{
createAndInsertNode("", "", Tag::Empty, n2->tag->write(), parent, n2, n2, modifs);
}
}
}
}
else
{
if(emptyNode)
extractAndDeleteNode(emptyNode, modifs, false, false, false);
}
}
}
void kafkaCommon::fitsNodesPosition(Node* startNode, int colMovement, int lineMovement, int colEnd, int lineEnd)
{
bool b = false;
int j, SNbeginLine, SNbeginCol/**, SNlastLine, SNlastCol*/;
int beginLine, beginCol, lastLine, lastCol;
Node *node = startNode;
if(!node)
return;
node->tag->beginPos(SNbeginLine, SNbeginCol);
//node->tag->endPos(SNlastLine, SNlastCol);
while(node)
{
node->tag->beginPos(beginLine, beginCol);
node->tag->endPos(lastLine, lastCol);
if(beginLine >= lineEnd && beginCol >= colEnd &&
colEnd != -2 && lineEnd != -2)
return;
if(beginLine == SNbeginLine && lastLine == SNbeginLine)
node->tag->setTagPosition(beginLine + lineMovement,
beginCol + colMovement, lastLine + lineMovement,
lastCol + colMovement);
else if(beginLine == SNbeginLine)//&&lastLine != SNbeginLine
node->tag->setTagPosition(beginLine + lineMovement,
beginCol + colMovement, lastLine + lineMovement,
lastCol);
else
node->tag->setTagPosition(beginLine + lineMovement,
beginCol, lastLine + lineMovement, lastCol);
for(j = 0; j < node->tag->attrCount(); ++j)
{
if(node->tag->getAttribute(j).nameLine == SNbeginLine)
{
node->tag->getAttribute(j).nameLine += lineMovement;
node->tag->getAttribute(j).nameCol += colMovement;
node->tag->getAttribute(j).valueLine += lineMovement;
node->tag->getAttribute(j).valueCol += colMovement;
}
else
{
node->tag->getAttribute(j).nameLine += lineMovement;
node->tag->getAttribute(j).valueLine += lineMovement;
}
}
node = getNextNode(node, b);
}
}
int kafkaCommon::getNodeDisplay(Node *node, bool closingNodeToo)
{
QString nodeName;
if(!node)
return kafkaCommon::errorDisplay;
if(node->tag->type == Tag::Text)
return kafkaCommon::inlineDisplay;
else if(node->tag->type == Tag::XmlTag || (node->tag->type == Tag::XmlTagEnd &&
closingNodeToo))
{
//If we areusing a non (X)HTML DTD, make everything blockDisplay by default
if(node->tag->dtd() && node->tag->dtd()->name.contains("HTML", false) == 0)
return kafkaCommon::blockDisplay;
nodeName = node->tag->name.lower();
if(closingNodeToo && nodeName.startsWith("/"))
nodeName = nodeName.mid(1);
if(nodeName == "html" || nodeName == "head" || nodeName == "meta" ||
nodeName == "link" || nodeName == "style" || nodeName == "option" ||
nodeName == "optgroup" || nodeName == "area" || nodeName == "param" ||
nodeName == "thead" || nodeName == "tbody" || nodeName == "dt" ||
nodeName == "tfoot" || nodeName == "col" || nodeName == "colgroup" ||
nodeName == "tr" || nodeName == "td" || nodeName == "th" || nodeName == "caption" ||
nodeName == "ins" || nodeName == "legend")
//Ok right, but this is only for indentation...
//return kafkaCommon::noneDisplay;
return kafkaCommon::blockDisplay;
else if(nodeName == "body" || nodeName == "p" || nodeName == "div" ||
nodeName == "blockquote" || nodeName == "isindex" ||
nodeName == "center" || nodeName == "hr" || nodeName == "h1" ||
nodeName == "h2" || nodeName == "h3" || nodeName == "h4" || nodeName == "h5" ||
nodeName == "h6" || nodeName == "table" ||
nodeName == "ul" || nodeName == "menu" || nodeName == "dir" || nodeName == "ol" ||
nodeName == "li" || nodeName == "ul" || nodeName == "dd" || nodeName == "dl" ||
nodeName == "form" || nodeName == "fieldset" ||
nodeName == "pre" || nodeName == "noscript" || nodeName == "noframes" ||
nodeName == "frameset" || nodeName == "frame" ||
nodeName == "address" || nodeName == "del" || nodeName == "br")
return kafkaCommon::blockDisplay;
else if(nodeName == "q" || nodeName == "u" || nodeName == "i" || nodeName == "b" ||
nodeName == "cite" || nodeName == "em" || nodeName == "var" || nodeName == "em" ||
nodeName == "tt" || nodeName == "code" || nodeName == "kbd" || nodeName == "samp" ||
nodeName == "big" || nodeName == "small" || nodeName == "s" || nodeName == "strike" ||
nodeName == "sub" || nodeName == "sup" || nodeName == "abbr" || nodeName == "title" ||
nodeName == "acronym" || nodeName == "a" || nodeName == "bdo" ||
nodeName == "font" || nodeName == "#text" || nodeName == "strong" || nodeName == "dfn" ||
nodeName == "img" || nodeName == "applet" || nodeName == "object" || nodeName == "basefont" || nodeName == "script" || nodeName == "map" || nodeName == "span" ||
nodeName == "iframe" || nodeName == "input" || nodeName == "select" || nodeName == "textarea" ||
nodeName == "label" || nodeName == "button" )
return kafkaCommon::inlineDisplay;
else
{
#ifdef LIGHT_DEBUG
kdDebug(25001)<< "kafkaCommon::getNodeType() - ERROR " << nodeName <<
" not found" << endl;
#endif
return kafkaCommon::noneDisplay;
}
}
return kafkaCommon::errorDisplay;
}
QString kafkaCommon::removeUnnecessaryWhitespaces(const QString &string,
bool removeAllSpacesAtTheLeft, bool removeAllSpacesAtTheRight)
{
/**QString newString;
int i;
if(string.length() == 0)
return "";
newString = string[0];
for(i = 1; (unsigned)i < string.length(); ++i)
{
if(!string[i - 1].isSpace() || !string[i].isSpace())
newString += string[i];
}
if(removeAllSpacesAtTheLeft && newString.length() > 0 && newString[0].isSpace())
newString = newString.mid(1);
if(removeAllSpacesAtTheRight && newString.length() > 0 &&
newString[newString.length() - 1].isSpace())
newString = newString.mid(0, newString.length() - 1);
return newString;*/
QString newString;
bool hasLeftWhiteSpaces, hasRightWhiteSpaces;
if(string.length() == 0)
return QString();
hasLeftWhiteSpaces = (string[0].isSpace());
hasRightWhiteSpaces = (string[string.length() - 1].isSpace());
newString = string.stripWhiteSpace();
if(hasLeftWhiteSpaces && !removeAllSpacesAtTheLeft)
newString.insert(0, " ");
if(hasRightWhiteSpaces && !removeAllSpacesAtTheRight)
newString.insert(newString.length(), " ");
return newString;
}
Node* kafkaCommon::createNode(const QString &nodeName, const QString &tagString, int nodeType, Document *doc)
{
Node *node;
//create the Node.
node = new Node(0L);
//Create the corresponding Tag.
node->tag = new Tag();
if(doc)
node->tag->setDtd(doc->defaultDTD());
else
node->tag->setDtd(0L);
node->tag->setWrite(doc);
node->tag->type = nodeType;
node->tag->name = QuantaCommon::tagCase(nodeName);
if(doc)
node->tag->single = QuantaCommon::isSingleTag(doc->defaultDTD()->name, nodeName);
else
node->tag->single = false;
node->tag->setStr(tagString);
node->tag->setCleanStrBuilt(false);
node->tag->setIndentationDone(false);
return node;
}
void kafkaCommon::restorePastedNode(Node* node, Document* doc)
{
if(doc)
node->tag->setDtd(doc->defaultDTD());
else
node->tag->setDtd(0L);
node->tag->setWrite(doc);
}
Node *kafkaCommon::createDoctypeNode(Document *doc)
{
Node *node, *child, *closingNode;
if(!doc)
return 0L;
//Build the script Tag
node = kafkaCommon::createNode("DTD block", "", Tag::ScriptTag, doc);
closingNode = kafkaCommon::createNode("", "", Tag::XmlTagEnd, doc);
node->next = closingNode;
closingNode->prev = node;
//Then build the Script tag which will be child of the above node.
child = kafkaCommon::createNode("#text", "DOCTYPE" + doc->defaultDTD()->doctypeStr, Tag::Text, doc);
child->tag->setCleanStrBuilt(true);
child->insideSpecial = true;
insertNode(child, node, 0L, 0L, false);
return node;
}
Node *kafkaCommon::createXmlDeclarationNode(Document *doc, const QString &encoding)
{
Node *node, *child, *closingNode;
QString text;
if(!doc)
return 0L;
//build the script Tag
node = kafkaCommon::createNode("XML PI block" ,"", Tag::ScriptTag, doc);
closingNode = kafkaCommon::createNode("", "", Tag::XmlTagEnd, doc);
node->next = closingNode;
closingNode->prev = node;
//Then build the Text tag which will be child of the above node.
text = " encoding=\"" + encoding + "\" version=\"1.0\"";
child = kafkaCommon::createNode("#text", text, Tag::Text, doc);
child->tag->setCleanStrBuilt(true);
child->insideSpecial = true;
insertNode(child, node, 0L, 0L, false);
return node;
}
Node* kafkaCommon::createMandatoryNodeSubtree(Node *node, Document *doc)
{
QTag *nodeQTag, *oldNodeQTag;
bool searchForMandatoryNode;
Node *currentParent;
QMap<QString, bool>::iterator it;
if(!node)
return 0L;
nodeQTag = QuantaCommon::tagFromDTD(node);
if(!nodeQTag)
return false;
searchForMandatoryNode = true;
currentParent = node;
while(searchForMandatoryNode)
{
oldNodeQTag = nodeQTag;
for(it = nodeQTag->childTags.begin(); it != nodeQTag->childTags.end(); ++it)
{
if(it.data())
{
nodeQTag = QuantaCommon::tagFromDTD(nodeQTag->parentDTD, it.key());
if(!nodeQTag)
return node;
currentParent = createAndInsertNode(nodeQTag->name(), "", Tag::XmlTag, doc,
currentParent, 0L, 0L, (NodeModifsSet*)0L);
break;
}
}
if(oldNodeQTag == nodeQTag)
searchForMandatoryNode = false;
}
return currentParent;
}
Node* kafkaCommon::insertNode(Node *node, Node* parentNode, Node* nextSibling,
NodeModifsSet *modifs, bool merge)
{
#ifdef LIGHT_DEBUG
kdDebug(25001)<< "kafkaCommon::insertNode()" << endl;
#endif
NodeModif* modif;
Node *n, *closingNode;
bool nodeIsFirstChild = false, b;
if(!node)
return 0L;
//Reset the listviews items pointers for node and its children
n = node;
b = false;
while(n)
{
/**node->mainListItem = 0L;
node->listItems.clear();
node->groupElementLists.clear();*/
n = getNextNode(n, b);
}
//place the new Node.
if(parentNode)
n = parentNode->child;
else
n = baseNode;
while(n && n->next)
n = n->next;
if(!parentNode && (!baseNode || (nextSibling && !nextSibling->prev)))
{
nodeIsFirstChild = true;
baseNode = node;
parser->setRootNode(baseNode);
}
if(parentNode && (!parentNode->child || nextSibling == parentNode->child))
{
nodeIsFirstChild = true;
parentNode->child = node;
}
node->parent = parentNode;
if(nextSibling && nextSibling->prev)
{
nextSibling->prev->next = node;
node->prev = nextSibling->prev;
}
else if(n && !nodeIsFirstChild)
{
n->next = node;
node->prev = n;
}
if(nextSibling)
nextSibling->prev = node;
node->next = nextSibling;
//log this.
if(modifs)
{
modif = new NodeModif();
if(node->child)
modif->setType(NodeModif::NodeAndChildsAdded);
else
modif->setType(NodeModif::NodeAdded);
modif->setLocation(getLocation(node));
modifs->addNodeModif(modif);
}
//Then try to merge with the siblings
if(merge)
{
if(node->prev)
{
n = node->prev;
if(mergeNodes(node->prev, node, modifs))
node = n;
}
if(node->next)
{
mergeNodes(node, node->next, modifs);
}
}
//update the closesPrevious switch
closingNode = node->getClosingNode();
if(closingNode)
closingNode->closesPrevious = true;
#ifdef HEAVY_DEBUG
coutTree(baseNode, 2);
#endif
return node;
}
Node* kafkaCommon::insertNode(Node *node, Node* parentNode, Node* nextSibling, NodeSelection& cursorHolder,
NodeModifsSet *modifs, bool merge)
{
#ifdef LIGHT_DEBUG
kdDebug(25001)<< "kafkaCommon::insertNode()" << endl;
#endif
NodeModif* modif;
Node *n, *closingNode;
bool nodeIsFirstChild = false, b;
if(!node)
return 0L;
//Reset the listviews items pointers for node and its children
n = node;
b = false;
while(n)
{
/**node->mainListItem = 0L;
node->listItems.clear();
node->groupElementLists.clear();*/
n = getNextNode(n, b);
}
//place the new Node.
if(parentNode)
n = parentNode->child;
else
n = baseNode;
while(n && n->next)
n = n->next;
if(!parentNode && (!baseNode || (nextSibling && !nextSibling->prev)))
{
nodeIsFirstChild = true;
baseNode = node;
parser->setRootNode(baseNode);
}
if(parentNode && (!parentNode->child || nextSibling == parentNode->child))
{
nodeIsFirstChild = true;
parentNode->child = node;
}
node->parent = parentNode;
if(nextSibling && nextSibling->prev)
{
nextSibling->prev->next = node;
node->prev = nextSibling->prev;
}
else if(n && !nodeIsFirstChild)
{
n->next = node;
node->prev = n;
}
if(nextSibling)
nextSibling->prev = node;
node->next = nextSibling;
//log this.
if(modifs)
{
modif = new NodeModif();
if(node->child)
modif->setType(NodeModif::NodeAndChildsAdded);
else
modif->setType(NodeModif::NodeAdded);
modif->setLocation(getLocation(node));
modifs->addNodeModif(modif);
}
//Then try to merge with the siblings
if(merge)
{
if(node->prev)
{
n = node->prev;
if(mergeNodes(node->prev, node, cursorHolder, modifs))
node = n;
}
if(node->next)
{
mergeNodes(node, node->next, cursorHolder, modifs);
}
}
//update the closesPrevious switch
closingNode = node->getClosingNode();
if(closingNode)
closingNode->closesPrevious = true;
#ifdef HEAVY_DEBUG
coutTree(baseNode, 2);
#endif
return node;
}
Node *kafkaCommon::insertNode(Node *newNode, Node *parent, Node *nextSibling, Node *nextEndSibling,
NodeModifsSet *modifs, bool merge)
{
#ifdef LIGHT_DEBUG
kdDebug(25001)<< "kafkaCommon::insertNode()1" << endl;
#endif
Node *n, *nodeEnd = 0;
if(!newNode)
return 0L;
//place the new Node.
newNode = insertNode(newNode, parent, nextSibling, modifs, merge);
if(!newNode->tag->single && newNode->tag->type == Tag::XmlTag)
{
//create the new closing Node.
nodeEnd = createNode("/" + newNode->tag->name, "", Tag::XmlTagEnd, newNode->tag->write());
nodeEnd->closesPrevious = true;
//place the new closing Node.
nodeEnd = insertNode(nodeEnd, parent, nextEndSibling, modifs, merge);
}
//If nextSibling != nextEndSibling, move all Nodes between node and nodeEnd as child of node
if(nextSibling != nextEndSibling)
{
n = newNode->next;
while(newNode->next && newNode->next != nodeEnd)
moveNode(newNode->next, newNode, 0L, modifs);
}
return newNode;
}
Node* kafkaCommon::insertNode(Node *newNode, Node *parent, Node *startNodeToSurround,
Node *endNodeToSurround, int startOffset, int endOffset, NodeModifsSet *modifs)
{
#ifdef LIGHT_DEBUG
kdDebug(25001)<< "kafkaCommon::insertNode()2" << endl;
#endif
if(!newNode || !startNodeToSurround || !endNodeToSurround)
return 0L;
//first split the Nodes.
if(splitNode(startNodeToSurround, startOffset, modifs))
{
if(endNodeToSurround == startNodeToSurround)
{
endNodeToSurround = endNodeToSurround->next;
endOffset -= startOffset;
}
startNodeToSurround = startNodeToSurround->next;
}
if(splitNode(endNodeToSurround, endOffset, modifs))
endNodeToSurround = endNodeToSurround->next;
//Then create and insert the new Node.
return insertNode(newNode, parent, startNodeToSurround,
endNodeToSurround, modifs);
}
Node* kafkaCommon::insertNodeSubtree(Node *node, Node* parentNode, Node* nextSibling,
NodeModifsSet *modifs, bool merge)
{
Node *nextNode, *currentNode;
if(!node || (node && node->prev))
return 0L;
//insert the node subtree
currentNode = node;
while(currentNode)
{
nextNode = currentNode->next;
if(currentNode == node)
node = insertNode(currentNode, parentNode, nextSibling, nextSibling, modifs, merge);
else
insertNode(currentNode, parentNode, nextSibling, nextSibling, modifs, merge);
currentNode = nextNode;
}
return node;
}
Node* kafkaCommon::insertNodeSubtree(Node *node, Node* parentNode, Node* nextSibling,
Node* nextEndSibling, NodeModifsSet *modifs, bool merge)
{
Node *nextNode, *currentNode, *currentParent;
if(!node || (node && node->prev))
return 0L;
//insert the node subtree.
currentNode = node;
currentParent = parentNode;
while(currentNode)
{
nextNode = currentNode->child;
currentNode->child = 0L;
//If the closing tag of currentNode is present, let's delete it
if(currentNode->next && QuantaCommon::closesTag(currentNode->tag, currentNode->next->tag))
delete extractNode(currentNode->next, 0L);
//insert the node and its closing tag if necessary.
if(currentNode == node)
{
currentParent = insertNode(currentNode, currentParent, nextSibling,
nextEndSibling, modifs, merge);
node = currentParent;
}
else
currentParent = insertNode(currentNode, currentParent, nextSibling,
0L, modifs, merge);
currentNode = nextNode;
}
return node;
}
Node* kafkaCommon::DTDInsertNodeSubtree(Node *newNode, NodeSelectionInd& selection,
Node **cursorNode, long& cursorOffset, NodeModifsSet *modifs)
{
Q_ASSERT(!selection.hasSelection());
Node* startNode = 0;
if(!(*cursorNode)) // see KafkaDocument::slotPaste()
startNode = getNodeFromLocation(selection.cursorNode());
else
startNode = *cursorNode;
if(!startNode)
{
kdError() << "NULL startNode in kafkaCommon::DTDInsertNodeSubtree given by NodeSelectionInd::cursorNode()" << endl;
return 0;
}
Node* endNode = 0;
if(!cursorNode)
return 0;
//int startOffset = selection.cursorOffset();
int startOffset = cursorOffset;
/**
* TODO : Optionnal for the moment : move the cursor coordinates so that we have good locations.
* e.g. <b>boo|</b>baa should be translated to <b>boo</b>|baa
*/
if(cursorOffset == (signed)startNode->tag->tagStr().length())
{
while(startNode && startNode->tag->type != Tag::Text)
startNode = startNode->nextSibling();
if(!startNode)
{
insertNodeSubtree(newNode, baseNode->child, 0, modifs, true);
return newNode;
}
else
cursorOffset = 0;
}
// look for commonParent
QValueList<int> commonParentStartChildLocation;
QValueList<int> commonParentEndChildLocation;
Node* commonParent = DTDGetNonInlineCommonParent(startNode, startNode,
commonParentStartChildLocation, commonParentEndChildLocation, 0);
Node* commonParentStartChild = getNodeFromLocation(commonParentStartChildLocation);
//OK now, we are sure the node can be inserted. Start the work by splitting
//startNode if necessary
if(cursorOffset != 0)
{
if(startNode->tag->type == Tag::Text || startNode->tag->type == Tag::Empty)
{
if(splitNode(startNode, startOffset, modifs))
{
//</TEMPORARY>
if(startNode == commonParentStartChild)
commonParentStartChild = commonParentStartChild->nextSibling();
endNode = startNode->nextSibling();
}
else if(startOffset == (signed)startNode->tag->tagStr().length())
{
//No need to update endNode. If endNode == startNode && startOffset == endOffset,
//we'll catch this later.
if(startNode == commonParentStartChild)
commonParentStartChild = commonParentStartChild->nextSibling();
startNode = startNode->nextSibling();
}
}
}
if(newNode->tag->type == Tag::Text || newNode->tag->type == Tag::Empty)
{
*cursorNode = newNode;
cursorOffset = newNode->tag->tagStr().length();
return insertNodeSubtree(newNode, startNode->parent, endNode, modifs);
}
//Then we "split" the lastValidStartParent - startNode subtree into two : the first part is untouched
// and the second will be surrounded by the new Node. Same thing for endNode.
Node* node = startNode;
Node* parentNode = startNode->parent;
Node* newParentNode = 0, *child = 0, *next = 0;
while(parentNode && commonParent && parentNode != commonParent)
{
if(true/*node != parentNode->firstChild()*/)
{
//node is not the first Child of parentNode, we have to duplicate parentNode, and put node and
//all its next sibling as child of the new parentNode.
/**newParentNode = insertNode(parentNode->tag->name, parentNode->tag->tagStr(),
parentNode->tag->type, parentNode->tag->write(), parentNode->parentNode(),
parentNode, parentNode, modifs);*/
newParentNode = duplicateNode(parentNode);
insertNode(newParentNode, parentNode->parentNode(), parentNode, parentNode, modifs);
child = parentNode->firstChild();
if(cursorOffset != 0)
{
while(child && (child != endNode) && !child->hasForChild(endNode))
{
next = child->next;
moveNode(child, newParentNode, 0L, modifs);
child = next;
}
}
else
{
while(child)
{
next = child->next;
moveNode(child, newParentNode, 0L, modifs, true, true);
if(child == startNode || child->hasForChild(startNode))
break;
child = next;
}
}
}
//commonParentStartChild = parentNode;
node = parentNode;
parentNode = parentNode->parent;
}
if(endNode)
{
node = endNode;
parentNode = endNode->parent;
while(parentNode && commonParent && parentNode != commonParent)
{
if(true/*node != parentNode->firstChild()*/)
{
//node is not the first Child of parentNode, we have to duplicate parentNode, and put node and
//all its next sibling as child of the new parentNode.
/**newParentNode = insertNode(parentNode->tag->name, parentNode->tag->tagStr(),
parentNode->tag->type, parentNode->tag->write(), parentNode->parentNode(),
parentNode, parentNode, modifs);*/
newParentNode = duplicateNode(parentNode);
insertNode(newParentNode, parentNode->parentNode(), parentNode, parentNode, modifs);
child = parentNode->firstChild();
while(child /*&& child == endNode*/ &&
(child == endNode || child->hasForChild(endNode)/* ||
(child->prev && child->prev->hasForChild(endNode) && child->closesPrevious)*/))
{
next = child->next;
moveNode(child, newParentNode, 0L, modifs, true, true);
child = next;
}
}
commonParentStartChild = newParentNode;
node = parentNode;
Node* aux = parentNode;
parentNode = parentNode->parent;
// Remove node subtree if empty
if(!aux->hasChildNodes())
extractAndDeleteNode(aux, modifs);
}
}
if(newNode->next && QuantaCommon::closesTag(newNode->tag, newNode->next->tag))
delete extractNode(newNode->next, 0L);
Node* nextSibling = commonParentStartChild;
/*
if(cursorOffset == 0)
nextSibling = nextSibling->SNext();
*/
return insertNodeSubtree(newNode, commonParent, nextSibling/*, nextSibling*/, modifs);
//mergeInlineNode(commonParent, commonParent->next, cursorNode, cursorOffset, modifs);
//return newNode;
}
Node* kafkaCommon::DTDInsertNodeSubtree(Node* newNode, Node* parentNode, Node* nextSibling,
NodeSelection& /*cursorHolder*/, NodeModifsSet *modifs)
{
QTag* nodeQTag = QuantaCommon::tagFromDTD(parentNode);
if(!nodeQTag || !nodeQTag->isChild(newNode))
return 0;
else
return insertNodeSubtree(newNode, parentNode, nextSibling, modifs);
}
bool kafkaCommon::DTDinsertNode(Node *newNode, Node *startNode, int startOffset, Node *endNode,
int endOffset, Document *doc, Node **cursorNode, long &cursorOffset, NodeModifsSet *modifs)
{
#ifdef LIGHT_DEBUG
kdDebug(25001)<< "kafkaCommon::DTDinsertNode()" << endl;
#endif
QValueList<int> startNodeLocation, endNodeLocation;
QValueList<int>::iterator itStart, itEnd;
Node *commonParent = 0L, *commonParentStartChild, *commonParentEndChild, *parentNode, *node;
Node *lastValidStartParent = 0L, *lastValidEndParent = 0L, *newParentNode, *child, *next;
Node *oldCommonParent, *lastNewNode, *oldParentNode;
QTag *parentNodeQTag = 0, *newNodeQTag, *lastNewNodeQTag;
NodeModif modif;
int locOffset = 1;
bool newNodeIsInline, isAfter;
if(!startNode || !endNode || !newNode || !doc)
{
Node::deleteNode(newNode);
return false;
}
//FIrst get the mandatory Nodes if necessary, and get the qTag of the first and last Node.
lastNewNode = createMandatoryNodeSubtree(newNode, doc);
lastNewNodeQTag = QuantaCommon::tagFromDTD(lastNewNode);
newNodeQTag = QuantaCommon::tagFromDTD(newNode);
if(!newNodeQTag || !lastNewNodeQTag)
{
Node::deleteNode(newNode);
return false;
}
//Then search for the common parent of startNode and endNode (commonParent)
//and for the childs of commonParent which are parent of startNode and endNode
//(commonParentStartChild && commonParentEndChild)
//CommonParent will be the limit (startNode -- commonNode) where Nodes can
//be splitted in order to insert the newNode.
startNodeLocation = getLocation(startNode);
endNodeLocation = getLocation(endNode);
itStart = startNodeLocation.begin();
itEnd = endNodeLocation.begin();
while(itStart != startNodeLocation.end() && itEnd != endNodeLocation.end() &&
(*itStart) == (*itEnd))
{
commonParent = getNodeFromSubLocation(startNodeLocation, locOffset);
itStart++;
itEnd++;
locOffset++;
}
//look for commonParentStartChild and commonParentEndChild
if(itStart != startNodeLocation.end())
commonParentStartChild = getNodeFromSubLocation(startNodeLocation, locOffset);
else
commonParentStartChild = commonParent;
if(itEnd != endNodeLocation.end())
commonParentEndChild = getNodeFromSubLocation(endNodeLocation, locOffset);
else
commonParentEndChild = commonParent;
//If newNode isn't inline, move commonParent to the closest non inline node
newNodeIsInline = isInline(newNode->tag->name);
if(!newNodeIsInline && commonParent && (isInline(commonParent->tag->name) ||
commonParent->tag->type == Tag::Text || commonParent->tag->type == Tag::Empty))
{
oldCommonParent = commonParent;
commonParent = commonParent->parent;
while(commonParent && isInline(commonParent->tag->name))
{
oldCommonParent = commonParent;
commonParent = commonParent->parent;
}
commonParentStartChild = oldCommonParent;
commonParentEndChild = oldCommonParent;
}
//startNode or endNode can't be the commonParent.
else if(commonParent && (itStart == startNodeLocation.end() || itEnd == endNodeLocation.end()))
commonParent = commonParent->parent;
//Now look if at least one of the parent Nodes between startNode and commonParent
//can have nodeName as child. If so for startNode and endNode, let's find the last
//parent Nodes which can have nodeName as child.
parentNode = startNode->parent;
oldParentNode = startNode;
while(parentNode && commonParent && parentNode != commonParent->parent)
{
parentNodeQTag = QuantaCommon::tagFromDTD(parentNode);
if(parentNodeQTag && parentNodeQTag->isChild(newNode) &&
lastNewNodeQTag->isChild(oldParentNode))
lastValidStartParent = parentNode;
else if(newNodeIsInline || !isInline(parentNode->tag->name))
break;
//else if(!newNodeIsInline && isInline(parentNode)), we continue : BLOCK element can
//cut some inline tag in order to be inserted.
oldParentNode = parentNode;
parentNode = parentNode->parent;
}
parentNode = endNode->parent;
oldParentNode = endNode;
while(parentNode && commonParent && parentNode != commonParent->parent)
{
parentNodeQTag = QuantaCommon::tagFromDTD(parentNode);
if(parentNodeQTag && parentNodeQTag->isChild(newNode) &&
lastNewNodeQTag->isChild(oldParentNode))
lastValidEndParent = parentNode;
else if(newNodeIsInline || !isInline(parentNode->tag->name))
break;
//else if(!newNodeIsInline && isInline(parentNode)), we continue : BLOCK element can
//cut some inline tag in order to be inserted.
oldParentNode = parentNode;
parentNode = parentNode->parent;
}
/**if(!lastValidEndParent || !lastValidStartParent)
{
Node::deleteNode(newNode);
return false;
}*/
//OK now, we are sure the node can be inserted. Start the work by splitting
//startNode and endNode if necessary
if(startNode->tag->type == Tag::Text || startNode->tag->type == Tag::Empty)
{
if(splitNode(startNode, startOffset, modifs))
{
//<TEMPORARY>
if(startNode == (*cursorNode) && cursorOffset > startOffset)
{
(*cursorNode) = (*cursorNode)->nextSibling();
cursorOffset -= startOffset;
}
//</TEMPORARY>
if(startNode == commonParentStartChild)
commonParentStartChild = commonParentStartChild->nextSibling();
if(startNode == endNode)
{
endNode = endNode->nextSibling();
endOffset -= startOffset;
}
startNode = startNode->nextSibling();
startOffset = 0;
}
else if(startOffset == (signed)startNode->tag->tagStr().length())
{
//No need to update endNode. If endNode == startNode && startOffset == endOffset,
//we'll catch this later.
if(startNode == commonParentStartChild)
commonParentStartChild = commonParentStartChild->nextSibling();
startNode = startNode->nextSibling();
}
}
if(endNode->tag->type == Tag::Text || endNode->tag->type == Tag::Empty)
{
if(!splitNode(endNode, endOffset, modifs) && endOffset == 0)
{
//No need to update startNode. If startNode == endNode && startOffset == endOffset,
//we'll catch this later.
if(endNode == commonParentEndChild)
commonParentEndChild = commonParentEndChild->previousSibling();
if (endNode->previousSibling())
endNode = endNode->previousSibling();
}
}
//Then we "split" the lastValidStartParent - startNode subtree into two : the first part is untouched
// and the second will be surrounded by the new Node. Same thing for endNode.
node = startNode;
if (!startNode) //Andras: it can happen.
return false;
parentNode = startNode->parent;
while(lastValidStartParent && parentNode && parentNode != lastValidStartParent)
{
if(node != parentNode->firstChild())
{
//node is not the first Child of parentNode, we have to duplicate parentNode, and put node and
//all its next sibling as child of the new parentNode.
/**newParentNode = insertNode(parentNode->tag->name, parentNode->tag->tagStr(),
parentNode->tag->type, parentNode->tag->write(), parentNode->parentNode(),
parentNode, parentNode, modifs);*/
newParentNode = duplicateNode(parentNode);
insertNode(newParentNode, parentNode->parentNode(), parentNode, parentNode, modifs);
child = parentNode->firstChild();
while(child && child != startNode && !child->hasForChild(startNode))
{
next = child->next;
moveNode(child, newParentNode, 0L, modifs);
child = next;
}
}
node = parentNode;
parentNode = parentNode->parent;
}
node = endNode;
parentNode = endNode->parent;
while(lastValidEndParent && parentNode && parentNode != lastValidEndParent)
{
if(node != parentNode->lastChild())
{
//node is not the last Child of parentNode, we have to duplicate parentNode, and put all
//the next sibling of node as child of the new parentNode
/**newParentNode = insertNode(parentNode->tag->name, parentNode->tag->tagStr(),
parentNode->tag->type, parentNode->tag->write(), parentNode->parentNode(),
parentNode, parentNode, modifs);*/
newParentNode = duplicateNode(parentNode);
insertNode(newParentNode, parentNode->parentNode(), parentNode, parentNode, modifs);
if(parentNode == commonParentStartChild)
commonParentStartChild = newParentNode;
if(parentNode == commonParentEndChild)
commonParentEndChild = newParentNode;
child = parentNode->firstChild();
while(child)
{
next = child->next;
moveNode(child, newParentNode, 0L, modifs);
if(child == endNode || child->hasForChild(endNode))
{
if(QuantaCommon::closesTag(child->tag, next->tag))
moveNode(next, newParentNode, 0L, modifs);
break;
}
child = next;
}
}
node = parentNode;
parentNode = parentNode->parent;
}
//Now if startNode is after endNode, this means that a selectionless insertion is being done.
//(This is due to the text splitting)
//Let's insert it and return
isAfter = (compareNodePosition(startNode, endNode) == kafkaCommon::isAfter);
if(isAfter || (startNode == endNode && startOffset == endOffset &&
(signed)startNode->tag->tagStr().length() == startOffset))
{
if(isAfter)
parentNodeQTag = QuantaCommon::tagFromDTD(commonParent);
else if((signed)startNode->tag->tagStr().length() == startOffset && startNode->tag->type == Tag::XmlTag)
parentNodeQTag = QuantaCommon::tagFromDTD(startNode);
else if((signed)startNode->tag->tagStr().length() == startOffset && startNode->tag->type == Tag::XmlTagEnd)
parentNodeQTag = QuantaCommon::tagFromDTD(startNode->parent);
if(!parentNodeQTag || (parentNodeQTag && parentNodeQTag->isChild(newNode)))
{
if(isAfter)
insertNodeSubtree(newNode, commonParent, commonParentStartChild, modifs);
else if((signed)startNode->tag->tagStr().length() == startOffset && startNode->tag->type == Tag::XmlTag)
insertNodeSubtree(newNode, startNode, 0L, modifs);
else if((signed)startNode->tag->tagStr().length() == startOffset && startNode->tag->type == Tag::XmlTagEnd)
insertNodeSubtree(newNode, startNode->parent, startNode->next, modifs);
//<TEMPORARY>
(*cursorNode) = lastNewNode;
cursorOffset = 0;
//</TEMPORARY>
return true;
}
else
{
Node::deleteNode(newNode);
return false;
}
}
else
{
//Else we apply the recursive function to add the new Node when necessary/possible.
bool addingStarted = false;
bool examinationStarted = false;
bool nodeInserted = false;
int level = 0;
addNodeRecursively(newNode, lastNewNode,
(compareNodePosition(lastValidStartParent, commonParentStartChild) ==
kafkaCommon::isAfter)?lastValidStartParent:commonParentStartChild,
(compareNodePosition(lastValidEndParent, commonParentEndChild) ==
kafkaCommon::isAfter)?lastValidEndParent:commonParentEndChild,
startNode, endNode, commonParentStartChild, examinationStarted,
addingStarted, nodeInserted, level, modifs);
//And we merge if necessary some identical inline Nodes.
mergeInlineNode(startNode, endNode, cursorNode, cursorOffset, modifs);
return nodeInserted;
}
}
bool kafkaCommon::DTDinsertRemoveNode(Node *newNode, Node *startNode, int startOffset,
Node *endNode, int endOffset, Document *doc, Node **cursorNode, long &cursorOffset,
NodeModifsSet *modifs)
{
int result;
if(!newNode || !startNode || !endNode || !doc)
return false;
//First try to remove the Nodes. If unsuccessfull, try to insert it.
result = DTDExtractNode(newNode->tag->name, doc, startNode, startOffset, endNode, endOffset,
cursorNode, cursorOffset, modifs);
if(result == kafkaCommon::nothingExtracted || result == kafkaCommon::extractionBadParameters)
{
return DTDinsertNode(newNode, startNode, startOffset, endNode, endOffset, doc, cursorNode,
cursorOffset, modifs);
}
else
return true;
//else if result == kafkaCommon::extractionStoppedDueToBadNodes,
//what should we do?
}
Node *kafkaCommon::createAndInsertNode(const QString &nodeName, const QString &tagString,
int nodeType, Document *doc, Node* parent, Node* nextSibling, NodeModifsSet *modifs,
bool merge)
{
#ifdef LIGHT_DEBUG
kdDebug(25001)<< "kafkaCommon::createAndInsertNode() - nodeName :" << nodeName <<
" - tagStr :" << tagString << " - nodeType :" << nodeType << endl;
#endif
Node *node;
//create the new Node.
node = createNode(nodeName, tagString, nodeType, doc);
//insert the new Node.
insertNode(node, parent, nextSibling, modifs, merge);
return node;
}
Node *kafkaCommon::createAndInsertNode(const QString &nodeName, const QString &tagString,
int nodeType, Document *doc, Node *parent, Node *nextSibling, Node *nextEndSibling,
NodeModifsSet *modifs)
{
#ifdef LIGHT_DEBUG
kdDebug(25001)<< "kafkaCommon::createAndInsertNode()2- nodeName :" << nodeName <<
" - tagStr :" << tagString << " - nodeType :" << nodeType << endl;
#endif
Node *node;
//create the new Node.
node = createNode(nodeName, tagString, nodeType, doc);
//insert the new Node.
insertNode(node, parent, nextSibling, nextEndSibling, modifs);
return node;
}
Node *kafkaCommon::createAndInsertNode(const QString &nodeName, const QString &tagString,
int nodeType, Document *doc, Node *parent, Node *startNodeToSurround,
Node *endNodeToSurround, int startOffset, int endOffset, NodeModifsSet *modifs)
{
#ifdef LIGHT_DEBUG
kdDebug(25001)<< "kafkaCommon::createAndInsertNode()3 - nodeName :" << nodeName <<
" - tagStr :" << tagString << " - nodeType :" << nodeType << endl;
#endif
Node *node;
if(!startNodeToSurround || !endNodeToSurround)
return 0L;
//create the new Node.
node = createNode(nodeName, tagString, nodeType, doc);
//insert the new Node.
insertNode(node, parent, startNodeToSurround, endNodeToSurround, startOffset, endOffset,
modifs);
return node;
}
bool kafkaCommon::DTDcreateAndInsertNode(const QString &nodeName, const QString &tagString,
int nodeType, Document *doc, Node *startNode, int startOffset, Node *endNode, int endOffset,
Node **cursorNode, long &cursorOffset, NodeModifsSet *modifs)
{
#ifdef LIGHT_DEBUG
kdDebug(25001)<< "kafkaCommon::DTDcreateAndInsertNode()2 - nodeName : " << nodeName <<
" - tagStr" <<tagString << endl;
#endif
Node *node;
if(!startNode || !endNode)
return false;
//create the new Node.
node = createNode(nodeName, tagString, nodeType, doc);
//insert the new Node.
return DTDinsertNode(node, startNode, startOffset, endNode, endOffset, doc, cursorNode,
cursorOffset, modifs);
}
bool kafkaCommon::addNodeRecursively(Node *newNode, Node *leafNode,
Node *startExaminationNode, Node *endExaminationNode, Node* startNode, Node *endNode,
Node* currentNode, bool &examinationStarted, bool &addingStarted, bool &nodeInserted, int level,
NodeModifsSet *modifs)
{
QTag *leafNodeQTag, *currentNodeParentQTag;
Node *startSelection = 0L, *endSelection = 0L, *oldCurrentNode, *copyNewNode;
bool selectionInProgress = false, validCurNodeParent = false;
leafNodeQTag = QuantaCommon::tagFromDTD(leafNode);
if(!leafNodeQTag)
return false;
if(currentNode && currentNode->parent)
{
currentNodeParentQTag = QuantaCommon::tagFromDTD(currentNode->parent);
if(currentNodeParentQTag && currentNodeParentQTag->isChild(newNode))
validCurNodeParent = true;
}
while(currentNode)
{
#ifdef HEAVY_DEBUG
kdDebug(25001)<< "kafkaCommon::addNodeRevursively() [" << level << "] - currentNode :" <<
currentNode->tag->name << "("<< currentNode->tag->type << ")(" << currentNode << ")" << endl;
#endif
//If currentNode is the startExaminationNode, let's start to examine Nodes (=> search the startNode)
if(currentNode == startExaminationNode)
examinationStarted = true;
//If currentNode is the startNode, let's start to try to add Nodes.
if(currentNode == startNode)
addingStarted = true;
//If the currentNode is text or XmlTag, and if it is DTD valid to insert the node Subtree and
//if the examination has started and currentNode doesn't have endExaminationNode as
//child, let's start/extend the selection over this node.
if((currentNode->tag->type == Tag::XmlTag || currentNode->tag->type == Tag::Text) &&
leafNodeQTag->isChild(currentNode) && validCurNodeParent && examinationStarted &&
!currentNode->hasForChild(endExaminationNode))
{
#ifdef HEAVY_DEBUG
kdDebug(25001)<< "kafkaCommon::addNodeRevursively() [" << level <<
"] - Valid Child : " << currentNode->tag->name << endl;
#endif
//extend the selection to this node.
if(currentNode->tag->type == Tag::XmlTag && currentNode->getClosingNode())
endSelection = currentNode->getClosingNode();
else
endSelection = currentNode;
//If this Node is, or has for child startNode, let's start to add newNode
if(currentNode->hasForChild(startNode) || currentNode == startNode)
{
#ifdef HEAVY_DEBUG
kdDebug(25001)<< "kafkaCommon::addNodeRevursively() [" << level <<
"] - This Node has the startNode as Child : " << currentNode->tag->name << endl;
#endif
addingStarted = true;
}
//If there isn't a previously started selection, let's start it now.
if(!selectionInProgress && addingStarted)
{
#ifdef HEAVY_DEBUG
kdDebug(25001)<< "kafkaCommon::addNodeRevursively() [" << level <<
"] - selection started at Node " << currentNode->tag->name << endl;
#endif
selectionInProgress = true;
startSelection = currentNode;
}
}
else if(currentNode->tag->type == Tag::XmlTag || currentNode->tag->type == Tag::Text)
{
#ifdef HEAVY_DEBUG
kdDebug(25001)<< "kafkaCommon::addNodeRevursively() [" << level <<
"] - Invalid Child : " << currentNode->tag->name << endl;
#endif
//the current Node can't handle newNode as a child, let's stop the selection
// here and surround the current selection with newNode
endSelection = currentNode->prev;
if(selectionInProgress)
{
#ifdef HEAVY_DEBUG
kdDebug(25001)<< "kafkaCommon::addNodeRevursively() [" << level <<
"] - selection ended(2) at Node " << currentNode->tag->name << endl;
#endif
selectionInProgress = false;
if(addingStarted)
{
while(startSelection && startSelection->tag->type == Tag::Empty)
startSelection = startSelection->next;
while(endSelection && endSelection->tag->type == Tag::Empty)
endSelection = endSelection->prev;
if (startSelection && endSelection)
{
/**copyNewNode = duplicateNode(newNode);
insertNode(copyNewNode, startSelection->parentNode(), startSelection,
endSelection->next, modifs);*/
copyNewNode = duplicateNodeSubtree(newNode);
insertNodeSubtree(copyNewNode, startSelection->parentNode(), startSelection,
endSelection->next, modifs);
nodeInserted = true;
}
}
}
//TESTING: If this Node is, or has for child startNode, let's start to add newNode
/**if(currentNode->hasForChild(startNode) || currentNode == startNode)
{
#ifdef HEAVY_DEBUG
kdDebug(25001)<< "kafkaCommon::addNodeRevursively() [" << level <<
"] - This Node has the startNode as Child : " << currentNode->tag->name << endl;
#endif
addingStarted = true;
}*/
//Let's try to surround some of the childs of currentNode.
if(currentNode->child)
{
addNodeRecursively(newNode, leafNode, startExaminationNode,
endExaminationNode, startNode, endNode, currentNode->child,
examinationStarted, addingStarted, nodeInserted, level + 1, modifs);
}
}
//If the currentNode is XmlTagEnd, Empty or whatever but not XmlTag and Text,
// we will surround them with newNode if a selection was started.
else
{
if(selectionInProgress)
{
if((currentNode->tag->type == Tag::XmlTag || currentNode->tag->type == Tag::ScriptTag) &&
currentNode->getClosingNode())
endSelection = currentNode->getClosingNode();
else
endSelection = currentNode;
}
//If this Node is, or has for child startNode, let's start to add newNode
if((currentNode->hasForChild(startNode) || currentNode == startNode) &&
examinationStarted)
{
#ifdef HEAVY_DEBUG
kdDebug(25001)<< "kafkaCommon::addNodeRevursively() [" << level <<
"] - This Node has the startNode as Child : " << currentNode->tag->name << endl;
#endif
addingStarted = true;
}
}
//If the current Node is, or has for child endNode, or if currentNode is
//endExaminationNode or if examination is stopped, let's stop the current selection.
if(currentNode->hasForChild(endNode) || currentNode == endNode ||
currentNode == endExaminationNode)
{
#ifdef HEAVY_DEBUG
kdDebug(25001)<< "kafkaCommon::addNodeRevursively() [" << level <<
"] - This Node has the endNode as Child : " << currentNode->tag->name << endl;
#endif
addingStarted = false;
examinationStarted = false;
if(selectionInProgress)
{
#ifdef HEAVY_DEBUG
kdDebug(25001)<< "kafkaCommon::addNodeRevursively() [" << level <<
"] - selection ended at Node " << currentNode->tag->name << endl;
#endif
selectionInProgress = false;
while(startSelection && startSelection->tag->type == Tag::Empty)
startSelection = startSelection->next;
while(endSelection && endSelection->tag->type == Tag::Empty)
endSelection = endSelection->prev;
if (startSelection && endSelection)
{
/**copyNewNode = duplicateNode(newNode);
insertNode(copyNewNode, startSelection->parentNode(), startSelection,
endSelection->next, modifs);*/
copyNewNode = duplicateNodeSubtree(newNode);
insertNodeSubtree(copyNewNode, startSelection->parentNode(), startSelection,
endSelection->next, modifs);
nodeInserted = true;
}
}
}
oldCurrentNode = currentNode;
currentNode = currentNode->next;
}
if(selectionInProgress)
{
#ifdef HEAVY_DEBUG
kdDebug(25001)<< "kafkaCommon::addNodeRevursively() [" << level <<
"] - selection ended(3) at Node " << oldCurrentNode->tag->name << endl;
#endif
selectionInProgress = false;
endSelection = oldCurrentNode;
if(addingStarted)
{
while(startSelection && startSelection->tag->type == Tag::Empty)
startSelection = startSelection->next;
while(endSelection && endSelection->tag->type == Tag::Empty)
endSelection = endSelection->prev;
/**copyNewNode = duplicateNode(newNode);
insertNode(copyNewNode, startSelection->parentNode(), startSelection,
endSelection->next, modifs);*/
copyNewNode = duplicateNodeSubtree(newNode);
insertNodeSubtree(copyNewNode, startSelection->parentNode(), startSelection,
endSelection->next, modifs);
nodeInserted = true;
}
}
//The newNode was a template, let's delete it now.
if(level == 0)
Node::deleteNode(newNode);
return true;
}
Node *kafkaCommon::duplicateNode(Node *node)
{
Node *newNode;
if(!node)
return 0L;
newNode = new Node(0L);
(*newNode) = node;
newNode->tag->setCleanStrBuilt(false);
newNode->tag->setIndentationDone(false);
return newNode;
}
typedef struct boo
{
boo()
{
m_n1 = m_n2 = 0L;
}
boo(Node *n1, Node *n2)
{
m_n1 = n1;
m_n2 = n2;
}
Node *m_n1;
Node *m_n2;
}
NodeLink;
Node* kafkaCommon::getLastChild(Node* node)
{
assert(node);
Node* end_node = node->getClosingNode();
if(!end_node && node->hasChildNodes())
end_node = node->lastChildNE();
else if(!end_node)
end_node = node;
assert(end_node);
return end_node;
}
Node *kafkaCommon::duplicateNodeSubtree(Node *node, bool childAndClosingTagOnly)
{
QPtrList<NodeLink> nodeLinkList;
bool goUp = false;
Node *currentNode, *currentNewNode, *newRootNode = 0, *newNext, *newParent, *newPrev;
NodeLink *link;
Node* endNode = 0;
if(!node)
return 0L;
if(childAndClosingTagOnly)
endNode = getLastChild(node);
nodeLinkList.setAutoDelete(true);
currentNode = node;
while(currentNode)
{
currentNewNode = duplicateNode(currentNode);
nodeLinkList.append(new NodeLink(currentNode, currentNewNode));
newNext = 0L;
newParent = 0L;
newPrev = 0L;
for(link = nodeLinkList.first(); link; link = nodeLinkList.next())
{
if(link->m_n1 == currentNode->parent)
newParent = link->m_n2;
else if(link->m_n1 == currentNode->next)
newNext = link->m_n2;
else if(link->m_n1 == currentNode->prev)
newPrev = link->m_n2;
}
if(!newParent && !newPrev)
newRootNode = currentNewNode;
else if(!newParent)
{
//Temporary, insertNode would rely on baseNode which can be dangerous
currentNewNode->prev = newPrev;
newPrev->next = currentNewNode;
}
else
insertNode(currentNewNode, newParent, newNext, 0L, false);
if(childAndClosingTagOnly)
currentNode = getNextNode(currentNode, goUp, endNode);
else
currentNode = getNextNode(currentNode, goUp, node);
}
return newRootNode;
}
Node* kafkaCommon::extractNode(Node *node, NodeModifsSet *modifs, bool extractChildren,
bool extractClosingTag)
{
NodeModif *modif = 0, *modifChild;
Node *lastChild, *curNode;
Node *parent, *next, *child, *n;
//Node *prev;
bool isSingle;
int type;
QString namespaceName, nodeName, caseSensitive;
QString closingNamespaceName, closingNodeName, closingCaseSensitive;
QValueList<int> location;
if(!node)
return 0L;
if(!node->child)
extractChildren = true;
parent = node->parent;
next = node->next;
//prev = node->prev; //Should this be used at all?
child = node->child;
lastChild = node->lastChild();
isSingle = node->tag->single;
type = node->tag->type;
namespaceName = node->tag->nameSpace;
nodeName = node->tag->name;
caseSensitive = node->tag->dtd()->caseSensitive;
//logging
if(modifs)
{
modif = new NodeModif();
if(extractChildren)
modif->setType(NodeModif::NodeAndChildsRemoved);
else
modif->setType(NodeModif::NodeRemoved);
modif->setLocation(getLocation(node));
//log the children move if we don't extract the children
if(!extractChildren)
{
location = getLocation(node);
location.last()++;
n = lastChild;
while(n)
{
modifChild = new NodeModif();
modifChild->setType(NodeModif::NodeAndChildsMoved);
modifChild->setLocation(getLocation(n));
modifChild->setFinalLocation(location);
modifs->addNodeModif(modifChild);
n = n->prev;
}
}
}
//starting to extract.
if(node == baseNode)
{
if(extractChildren)
baseNode = 0L;
else
baseNode = node->child;
parser->setRootNode(baseNode);
}
if(!extractChildren)
{
curNode = node->child;
while(curNode)
{
curNode->parent = node->parent;
curNode = curNode->next;
}
}
if(node->parent && node->parent->child == node)
{
if(extractChildren)
node->parent->child = node->next;
else
node->parent->child = node->child;
}
node->parent = 0L;
if(node->prev)
{
if(extractChildren)
node->prev->next = node->next;
else
{
node->prev->next = node->child;
node->child->prev = node->prev;
}
}
if(node->next)
{
if(extractChildren)
node->next->prev = node->prev;
else
{
/**lastChild = node->child;
while(lastChild->next)
lastChild = lastChild->next;*/
node->next->prev = lastChild;
lastChild->next = node->next;
}
}
node->prev = 0L;
node->next = 0L;
if(!extractChildren)
node->child = 0L;
if(modifs)
{
modif->setNode(0/*node*/); // this deletes the node!!???
modifs->addNodeModif(modif);
}
//extract the closing Tag
if(extractClosingTag && type == Tag::XmlTag && !isSingle && next)
{
while(next && next->tag->type == Tag::Empty)
next = next->next;
if(next)
{
closingNamespaceName = next->tag->nameSpace;
closingNodeName = next->tag->name;
closingCaseSensitive = next->tag->dtd()->caseSensitive;
if(QuantaCommon::closesTag(namespaceName, nodeName, caseSensitive,
closingNamespaceName, closingNodeName, closingCaseSensitive))
extractNode(next, modifs, false, false);
}
}
#ifdef HEAVY_DEBUG
coutTree(baseNode, 2);
#endif
return node;
}
Node* kafkaCommon::DTDExtractNodeSubtree(Node *startNode, int startOffset, Node *endNode, int endOffset,
Node **cursorNode, long &cursorOffset, NodeModifsSet *modifs, bool extractInlineParentNodes)
{
#ifdef LIGHT_DEBUG
kdDebug(25001) << "kafkaCommon::extractNodeSubtree()" << endl;
#endif
if(!startNode || !endNode)
return 0;
QValueList<int> commonParentStartChildLocation;
QValueList<int> commonParentEndChildLocation;
Node* commonParent = 0;
NodeSelection cursorHolder;
cursorHolder.setCursorNode(*cursorNode);
cursorHolder.setCursorOffset(cursorOffset);
splitStartAndEndNodeSubtree(startNode, startOffset, endNode, endOffset, commonParent,
commonParentStartChildLocation, commonParentEndChildLocation,
cursorHolder, 0, modifs, extractInlineParentNodes);
*cursorNode = cursorHolder.cursorNode();
cursorOffset = cursorHolder.cursorOffset();
Node* commonParentStartChild = getNodeFromLocation(commonParentStartChildLocation);
Node* commonParentEndChild = getNodeFromLocation(commonParentEndChildLocation);
if(startNode == endNode)
{
Q_ASSERT(startNode->tag->type == Tag::Text || startNode->tag->type == Tag::Empty);
Node* prev = startNode->prev;
Node* next = startNode->next;
Node* aux = extractNode(startNode, modifs);
mergeInlineNode(prev, next, cursorNode, cursorOffset, modifs);
return aux;
}
// now let us extract the subtree
if(!commonParentEndChild)
commonParentEndChild = endNode;
extractNodeSubtreeAux(commonParentStartChild, commonParentEndChild, modifs);
// merge identical nodes
Node* commonParentEndChild_next = commonParentEndChild->SNext();
mergeInlineNode(commonParent, commonParentEndChild_next, cursorNode, cursorOffset, modifs);
mergeInlineNode(commonParentStartChild, commonParentEndChild, cursorNode, cursorOffset, modifs);
#ifdef LIGHT_DEBUG
coutTree(commonParentStartChild, 3);
#endif
return commonParentStartChild;
}
Node* kafkaCommon::DTDExtractNodeSubtree(Node *startNode, int startOffset, Node *endNode, int endOffset,
Node* nodeSubtree, NodeModifsSet* modifs, bool extractInlineParentNodes)
{
#ifdef LIGHT_DEBUG
kdDebug(25001) << "kafkaCommon::extractNodeSubtree()" << endl;
#endif
if(!startNode || !endNode)
return 0;
QValueList<int> commonParentStartChildLocation;
QValueList<int> commonParentEndChildLocation;
Node* commonParent = 0;
if(extractInlineParentNodes)
{
commonParent = DTDGetNonInlineCommonParent(startNode, endNode,
commonParentStartChildLocation, commonParentEndChildLocation, nodeSubtree);
}
else
{
commonParent = DTDGetCommonParent(startNode, endNode,
commonParentStartChildLocation, commonParentEndChildLocation, nodeSubtree);
}
assert(commonParent == nodeSubtree);
NodeSelection selection;
splitStartAndEndNodeSubtree(startNode, startOffset, endNode, endOffset, commonParent,
commonParentStartChildLocation, commonParentEndChildLocation,
selection, nodeSubtree, modifs);
Node* cursorNode = selection.cursorNode();
long cursorOffset = selection.cursorOffset();
Node* commonParentStartChild = getNodeFromLocation(commonParentStartChildLocation, nodeSubtree);
Node* commonParentEndChild = getNodeFromLocation(commonParentEndChildLocation, nodeSubtree);
if(startNode == endNode)
{
Q_ASSERT(startNode->tag->type == Tag::Text || startNode->tag->type == Tag::Empty);
return extractNode(startNode, modifs);
}
// now let us extract the subtree
commonParentStartChild = getNodeFromLocation(commonParentStartChildLocation, commonParent);
commonParentEndChild = getNodeFromLocation(commonParentEndChildLocation, commonParent);
if(!commonParentEndChild)
commonParentEndChild = endNode;
extractNodeSubtreeAux(commonParentStartChild, commonParentEndChild, modifs);
//merge identical nodes
/* Node* cursorNode = 0;
int cursorOffset = 0;*/
Node* commonParentEndChild_next = commonParentEndChild->SNext();
mergeInlineNode(commonParent, commonParentEndChild_next, &cursorNode, cursorOffset, modifs);
mergeInlineNode(commonParentStartChild, commonParentEndChild, &cursorNode, cursorOffset, modifs);
#ifdef LIGHT_DEBUG
coutTree(commonParentStartChild, 3);
#endif
return commonParentStartChild;
}
Node* kafkaCommon::extractNodeSubtreeAux(Node* commonParentStartChild, Node* commonParentEndChild, NodeModifsSet* modifs)
{
Node* node = commonParentStartChild;
Node* prev_node = 0;
Node* next_node = 0;
Node* significant_next_node = 0;
Node* node_extracted = 0;
Node* commonParentEndChild_next = commonParentEndChild->SNext();
while(node && node != commonParentEndChild_next)
{
next_node = node->next;
significant_next_node = node->SNext();
node_extracted = extractNode(node, modifs, true, true);
if(node_extracted)
{
node_extracted->prev = prev_node;
if(significant_next_node != commonParentEndChild_next || (next_node && next_node->closesPrevious))
node_extracted->next = next_node;
if(next_node && next_node->closesPrevious)
{
next_node->prev = node_extracted;
node_extracted->_closingNode = next_node;
}
}
prev_node = node_extracted;
node = significant_next_node;
}
return commonParentStartChild;
}
Node* kafkaCommon::getNodeSubtree(Node *startNode, int startOffset, Node *endNode, int endOffset, bool extractInlineParentNodes)
{
#ifdef LIGHT_DEBUG
kdDebug(25001) << "kafkaCommon::getNodeSubtree()" << endl;
#endif
if(!startNode || !endNode)
return 0;
QValueList<int> commonParentStartChildLocation;
QValueList<int> commonParentEndChildLocation;
Node* commonParent = 0;
if(extractInlineParentNodes)
commonParent = DTDGetNonInlineCommonParent(startNode, endNode,
commonParentStartChildLocation, commonParentEndChildLocation, 0);
else
commonParent = DTDGetCommonParent(startNode, endNode,
commonParentStartChildLocation, commonParentEndChildLocation, 0);
// get the subtree to operate
Node* newStartNode = 0;
Node* newEndNode = 0;
Node* newCommonParent = duplicateNodeSubtree(commonParent, true);
QValueList<int> const startNodeLocation = getLocation(startNode);
QValueList<int> const commonParentLocation = getLocation(commonParent);
uint const commonParentDepth = commonParentLocation.size();
uint const newStartNodeDepth = startNodeLocation.size() - commonParentDepth + 1;
uint const newEndNodeDepth = startNodeLocation.size() - commonParentDepth + 1;
QValueList<int> newStartNodeLocation, newEndNodeLocation;
newStartNodeLocation.push_back(1);
newEndNodeLocation.push_back(1);
for(uint i = 1; i != newStartNodeDepth; ++i)
newStartNodeLocation.push_back(startNodeLocation[i + commonParentDepth - 1]);
QValueList<int> const endNodeLocation = getLocation(endNode);
for(uint i = 1; i != newEndNodeDepth; ++i)
newEndNodeLocation.push_back(endNodeLocation[i + commonParentDepth - 1]);
newStartNode = getNodeFromLocation(newStartNodeLocation, newCommonParent);
newEndNode = getNodeFromLocation(newEndNodeLocation, newCommonParent);
return DTDExtractNodeSubtree(newStartNode, startOffset, newEndNode, endOffset, newCommonParent, 0);
}
Node* kafkaCommon::DTDRemoveSelection(NodeSelectionInd& selection,
Node **cursorNode, long& cursorOffset, NodeModifsSet *modifs, bool extractInlineParentNodes)
{
Q_ASSERT(selection.hasSelection());
int startOffset = selection.cursorOffset();
int endOffset = selection.cursorOffsetEndSel();
Node* startNode = getNodeFromLocation(selection.cursorNode());
Node* endNode = getNodeFromLocation(selection.cursorNodeEndSel());
return DTDExtractNodeSubtree(startNode, startOffset, endNode, endOffset, cursorNode, cursorOffset, modifs, extractInlineParentNodes);
}
void kafkaCommon::extractAndDeleteNode(Node *node, NodeModifsSet *modifs, bool deleteChildren,
bool deleteClosingTag, bool mergeAndFormat)
{
NodeModif modif;
Node *curNode, *nodePrev, *nodeNext, *nodeNext2, *n, *n2;
QString nodeName, closingNodeName, namespaceName, namespaceName2;
bool isSingle, caseSensitive, caseSensitive2;
if(!node)
return;
isSingle = node->tag->single;
nodeName = node->tag->name;
namespaceName = node->tag->nameSpace;
caseSensitive = node->tag->dtd()->caseSensitive;
nodePrev = node->prev;
nodeNext = node->next;
if(!node->child)
deleteChildren = true;
node = extractNode(node, modifs, deleteChildren);
//delete the closing Tag
if(!isSingle && deleteClosingTag && nodeNext)
{
curNode = nodeNext;
while(curNode && curNode->tag->type == Tag::Empty)
curNode = curNode->next;
if(curNode)
{
closingNodeName = curNode->tag->name;
namespaceName2 = curNode->tag->nameSpace;
caseSensitive2 = curNode->tag->dtd()->caseSensitive;
if(QuantaCommon::closesTag(namespaceName, nodeName, caseSensitive,
namespaceName2, closingNodeName, caseSensitive2))
{
curNode = nodeNext;
while(curNode)
{
nodeNext2 = curNode->next;
closingNodeName = curNode->tag->name;
namespaceName2 = curNode->tag->nameSpace;
caseSensitive2 = curNode->tag->dtd()->caseSensitive;
curNode = extractNode(curNode, modifs, deleteChildren);
curNode = nodeNext2;
if(QuantaCommon::closesTag(namespaceName, nodeName, caseSensitive,
namespaceName2, closingNodeName, caseSensitive2))
break;
}
nodeNext = curNode;
}
}
}
//merge the next and prev Nodes if they are both of type Text or Empty
if(mergeAndFormat && nodePrev)
{
n = nodePrev;
n2 = nodePrev->next;
while(n && n2 && n2->prev != nodeNext)
{
if(!mergeNodes(n, n2, modifs))
break;
n2 = n->next;
}
}
}
int kafkaCommon::DTDExtractNode(const QString &nodeName, Document *doc, Node *startNode,
int startOffset, Node *endNode, int endOffset, Node **cursorNode, long &cursorOffset,
NodeModifsSet *modifs)
{
QTag *nodeNameQTag, *parentQTag;
Node *node, *lastNodeNameStartNode, *lastNodeNameEndNode;
Node *parentNode, *newParentNode, *child, *next;
bool goUp, nodesRemoved = false, DTDError = false, result;
bool startNodeSplitted = false, endNodeSplitted = false;
if(!doc || !startNode || !endNode)
return kafkaCommon::extractionBadParameters;
//First check that nodeName is really inline and that an area is selected.
nodeNameQTag = QuantaCommon::tagFromDTD(doc->defaultDTD(), nodeName);
if(!nodeNameQTag)
return kafkaCommon::extractionBadParameters;
if(!isInline(nodeName))
return kafkaCommon::extractionBadParameters;
if(startNode->tag->type == Tag::Text && startOffset == (signed)startNode->tag->tagStr().length())
{
startOffset = 0;
while(startNode && startNode->nextSibling())
{
startNode = startNode->nextSibling();
if(startNode == endNode || startNode->tag->type == Tag::Text)
break;
}
}
if(startNode == endNode && startOffset == endOffset)
return kafkaCommon::extractionBadParameters;
//Then, process startNode and endNode : look if a nodeName parent is one of
//startNode/endNode's inline parents and if it is the case, split the necessary Nodes.
//The comparaison is made in lowercase, even in xml : it could be strange, for an user, to have
//its nodes not removed because there are in the wrong case.
node = startNode;
lastNodeNameStartNode = 0L;
while(node && (isInline(node->tag->name) || node->tag->type == Tag::Text))
{
if(node->tag->name.lower() == nodeName.lower())
lastNodeNameStartNode = node;
node = node->parent;
}
node = endNode;
lastNodeNameEndNode = 0L;
while(node && (isInline(node->tag->name) || node->tag->type == Tag::Text))
{
if(node->tag->name.lower() == nodeName.lower())
lastNodeNameEndNode = node;
node = node->parent;
}
if(startNode->tag->type == Tag::Text)
{
if(splitNode(startNode, startOffset, modifs))
{
startNodeSplitted = true;
//<TEMPORARY>
if(startNode == (*cursorNode) && cursorOffset > startOffset)
{
(*cursorNode) = (*cursorNode)->nextSibling();
cursorOffset -= startOffset;
}
//</TEMPORARY>
if(startNode == endNode)
{
endNode = endNode->nextSibling();
endOffset -= startOffset;
}
startNode = startNode->nextSibling();
}
}
if(endNode->tag->type == Tag::Text)
{
result = splitNode(endNode, endOffset, modifs);
if(result)
endNodeSplitted = true;
else if(!result && endOffset == 0)
endNode = endNode->previousSibling();
}
if(lastNodeNameStartNode)
{
node = startNode;
parentNode = startNode->parent;
while(parentNode && parentNode != lastNodeNameStartNode->parent)
{
if(node != parentNode->firstChild())
{
newParentNode = duplicateNode(parentNode);
insertNode(newParentNode, parentNode->parentNode(), parentNode, parentNode, modifs);
child = parentNode->firstChild();
while(child && child != startNode && !child->hasForChild(startNode))
{
next = child->next;
moveNode(child, newParentNode, 0L, modifs);
child = next;
}
}
node = parentNode;
parentNode = parentNode->parent;
}
}
if(lastNodeNameEndNode)
{
node = endNode;
parentNode = endNode->parent;
while(parentNode && parentNode != lastNodeNameEndNode->parent)
{
if(node != parentNode->SLastChild())
{
newParentNode = duplicateNode(parentNode);
insertNode(newParentNode, parentNode->parentNode(), parentNode, parentNode, modifs);
if(parentNode == lastNodeNameStartNode)
lastNodeNameStartNode = newParentNode;
child = parentNode->firstChild();
while(child)
{
next = child->next;
moveNode(child, newParentNode, 0L, modifs);
if(child == endNode || child->hasForChild(endNode))
{
if(QuantaCommon::closesTag(child->tag, next->tag))
moveNode(next, newParentNode, 0L, modifs);
break;
}
child = next;
}
}
node = parentNode;
parentNode = parentNode->parent;
}
}
//Now delete the nodeName Nodes when possible from lastNodeNameStartParent to endNode.
node = lastNodeNameStartNode?lastNodeNameStartNode:startNode;
goUp = false;
while(node && !DTDError)
{
next = getNextNode(node, goUp);
if(node->tag->type == Tag::XmlTag && node->tag->name.lower() == nodeName.lower())
{
parentQTag = QuantaCommon::tagFromDTD(node->parent);
if(parentQTag)
{
child = node->firstChild();
while(child)
{
if(!parentQTag->isChild(child))
DTDError = true;
child = child->next;
}
if(!DTDError)
{
extractNode(node, modifs, false, true);
nodesRemoved = true;
}
}
}
if(node == endNode)
break;
node = next;
}
//TODO: merge the unnecessary splitted Nodes.
if(endNode && endNodeSplitted)
mergeNodes(endNode, endNode->nextSibling(), modifs, true);
if(startNode && startNodeSplitted)
{
node = startNode->previousSibling();
result = mergeNodes(startNode->previousSibling(), startNode, modifs, true);
startNode = node;
//<TEMPORARY>
if(result)
{
(*cursorNode) = node;
cursorOffset += startOffset;
}
//</TEMPORARY>
}
if(DTDError)
return kafkaCommon::extractionStoppedDueToBadNodes;
else if(!nodesRemoved)
return kafkaCommon::nothingExtracted;
else
{
//merge when necessary some text/identical inlines.
mergeInlineNode(startNode, endNode, cursorNode, cursorOffset, modifs);
return kafkaCommon::extractionDone;
}
}
void kafkaCommon::moveNode(Node *nodeToMove, Node *newParent, Node *newNextSibling,
NodeModifsSet *modifs, bool merge, bool moveClosingNode)
{
NodeModif *modif = 0;
Node *newNode, *closingNode;
closingNode = nodeToMove->getClosingNode();
//DON'T log the removal and addition of the same Node!! When spliting the undoRedo stack
//it will delete the remove NodeModif and thus the Node inside which is the Node inserted.
if(modifs)
{
modif = new NodeModif();
modif->setType(NodeModif::NodeAndChildsMoved);
modif->setLocation(getLocation(nodeToMove));
}
//extract the old Node.
newNode = extractNode(nodeToMove, 0L, true);
//insert the new Node.
insertNode(newNode, newParent, newNextSibling, 0L, merge);
if(modifs)
modif->setFinalLocation(getLocation(newNode));
if(moveClosingNode && closingNode)
moveNode(closingNode, newParent, newNextSibling,
modifs, merge, false);
if(modifs)
modifs->addNodeModif(modif);
}
void kafkaCommon::moveNode(Node *nodeToMove, Node *newParent, Node *newNextSibling, NodeSelection& cursorHolder,
NodeModifsSet *modifs, bool merge, bool moveClosingNode)
{
NodeModif *modif = 0;
Node *newNode, *closingNode;
closingNode = nodeToMove->getClosingNode();
//DON'T log the removal and addition of the same Node!! When spliting the undoRedo stack
//it will delete the remove NodeModif and thus the Node inside which is the Node inserted.
if(modifs)
{
modif = new NodeModif();
modif->setType(NodeModif::NodeAndChildsMoved);
modif->setLocation(getLocation(nodeToMove));
}
//extract the old Node.
newNode = extractNode(nodeToMove, 0L, true);
cursorHolder.setCursorNode(newNode);
//insert the new Node.
insertNode(newNode, newParent, newNextSibling, cursorHolder, 0L, merge);
if(modifs)
modif->setFinalLocation(getLocation(newNode));
if(moveClosingNode && closingNode)
moveNode(closingNode, newParent, newNextSibling,
modifs, merge, false);
if(modifs)
modifs->addNodeModif(modif);
}
bool kafkaCommon::splitNode(Node *n, int offset, NodeModifsSet *modifs)
{
NodeModif *modif;
Tag *tag;
QString tagStr;
Node *node;
if(!n || (n->tag->type != Tag::Text && n->tag->type != Tag::Empty) || offset <= 0 || offset >=
(signed)n->tag->tagStr().length())
return false;
//logging
if(modifs)
{
tag = new Tag(*(n->tag));
modif = new NodeModif();
modif->setType(NodeModif::NodeModified);
modif->setTag(tag);
modif->setLocation(getLocation(n));
modifs->addNodeModif(modif);
}
tagStr = n->tag->tagStr();
n->tag->setStr(tagStr.left(offset));
if(n->tag->type == Tag::Text)
node = createAndInsertNode("#text", tagStr.right(tagStr.length() - offset), Tag::Text, n->tag->write(),
n->parent, n->next, modifs, false);
else
node = createAndInsertNode("", tagStr.right(tagStr.length() - offset), Tag::Empty, n->tag->write(),
n->parent, n->next, modifs, false);
//Node's string is a part of n's clean string
node->tag->setCleanStrBuilt(true);
node->tag->setIndentationDone(true);
return true;
}
void kafkaCommon::splitStartNodeSubtree(Node* startNode, Node* commonParent,
QValueList<int>& commonParentStartChildLocation, NodeModifsSet* modifs)
{
//Then we "split" the lastValidStartParent - startNode subtree into two : the first part is untouched
// and the second will be surrounded by the new Node. Same thing for endNode.
Node* node = startNode;
Node* parentNode = startNode->parent;
Node* commonParentStartChild = 0;
while(parentNode && commonParent && parentNode != commonParent)
{
if(node != parentNode->firstChild())
{
Node* newParentNode = duplicateNode(parentNode);
insertNode(newParentNode, parentNode->parentNode(), parentNode, parentNode, modifs);
Node* child = parentNode->firstChild();
while(child && child != startNode && !child->hasForChild(startNode))
{
Node* next = child->next;
moveNode(child, newParentNode, 0L, modifs);
child = next;
}
}
commonParentStartChild = parentNode;
node = parentNode;
parentNode = parentNode->parent;
}
if(commonParentStartChild)
commonParentStartChildLocation = getLocation(commonParentStartChild);
}
void kafkaCommon::splitEndNodeSubtree(Node* endNode, Node* commonParent,
QValueList<int>& commonParentStartChildLocation,
QValueList<int>& commonParentEndChildLocation,
bool subTree, NodeModifsSet* modifs)
{
Node* node = endNode;
Node* parentNode = endNode->parent;
Node* aux = 0;
if(subTree)
aux = commonParent;
else
aux = baseNode;
Node* commonParentStartChild = getNodeFromLocation(commonParentStartChildLocation, aux);
Node* commonParentEndChild = getNodeFromLocation(commonParentEndChildLocation, aux);
while(parentNode && commonParent && parentNode != commonParent)
{
if(node != parentNode->lastChild())
{
Node* newParentNode = duplicateNode(parentNode);
insertNode(newParentNode, parentNode->parentNode(), parentNode, parentNode, modifs);
if(parentNode == commonParentStartChild)
commonParentStartChild = newParentNode;
if(parentNode == commonParentEndChild)
commonParentEndChild = newParentNode;
Node* child = parentNode->firstChild();
while(child)
{
Node* next = child->next;
moveNode(child, newParentNode, 0L, modifs);
if(child == endNode || child->hasForChild(endNode))
{
if(QuantaCommon::closesTag(child->tag, next->tag))
moveNode(next, newParentNode, 0L, modifs);
break;
}
child = next;
}
}
node = parentNode;
parentNode = parentNode->parent;
}
commonParentStartChildLocation = getLocation(commonParentStartChild);
commonParentEndChildLocation = getLocation(commonParentEndChild);
}
void kafkaCommon::splitStartAndEndNodeSubtree(Node*& startNode, int startOffset, Node*& endNode, int endOffset, Node*& commonParent,
QValueList<int>& commonParentStartChildLocation,
QValueList<int>& commonParentEndChildLocation,
NodeSelection& cursorHolder,
Node* subTree, NodeModifsSet* modifs, bool extractInlineParentNodes)
{
assert(startNode && endNode);
assert(startOffset >= 0);
assert(endOffset >= 0);
// get correct start and end nodes and offsets
startNode = getCorrectStartNode(startNode, startOffset);
endNode = getCorrectEndNode(endNode, endOffset);
// look for common parent
if(!commonParent)
{
if(extractInlineParentNodes)
// get the non inline common parent
commonParent =
DTDGetNonInlineCommonParent(startNode, endNode, commonParentStartChildLocation, commonParentEndChildLocation, subTree);
else
commonParent =
DTDGetCommonParent(startNode, endNode, commonParentStartChildLocation, commonParentEndChildLocation, subTree);
}
else
{
assert(commonParent->hasForChild(startNode));
assert(commonParent->hasForChild(endNode));
assert(!commonParentStartChildLocation.empty());
assert(!commonParentEndChildLocation.empty());
}
Node* commonParentStartChild = kafkaCommon::getNodeFromLocation(commonParentStartChildLocation, subTree);
Node* commonParentEndChild = kafkaCommon::getNodeFromLocation(commonParentEndChildLocation, subTree);
Node* cursorNode = cursorHolder.cursorNode();
int cursorOffset = cursorHolder.cursorOffset();
// split start and end node
if(splitNode(startNode, startOffset, modifs))
{
if(startNode == cursorNode && cursorOffset > startOffset)
{
cursorNode = cursorNode->nextSibling();
cursorOffset -= startOffset;
}
if(startNode == commonParentStartChild)
commonParentStartChild = commonParentStartChild->nextSibling();
if(startNode == endNode)
{
endNode = endNode->nextSibling();
endOffset -= startOffset;
}
startNode = startNode->nextSibling();
startOffset = 0;
}
splitNode(endNode, endOffset, modifs);
// split start and end nodes subtree in function of common parent
commonParentStartChildLocation = kafkaCommon::getLocation(commonParentStartChild);
splitStartNodeSubtree(startNode, commonParent, commonParentStartChildLocation, modifs);
commonParentEndChildLocation = kafkaCommon::getLocation(commonParentEndChild);
splitEndNodeSubtree(endNode, commonParent, commonParentStartChildLocation, commonParentEndChildLocation, subTree, modifs);
cursorHolder.setCursorNode(cursorNode);
cursorHolder.setCursorOffset(cursorOffset);
}
bool kafkaCommon::mergeNodes(Node *n, Node *n2, NodeModifsSet *modifs, bool mergeTextOnly)
{
NodeModif *modif;
Tag *tag;
if(!n || !n2)
return false;
if(((n->tag->type == Tag::Empty && !mergeTextOnly) || n->tag->type == Tag::Text) &&
((n2->tag->type == Tag::Empty && !mergeTextOnly) || n2->tag->type == Tag::Text))
{
tag = new Tag(*(n->tag));
//logging
if(modifs)
{
modif = new NodeModif();
modif->setType(NodeModif::NodeModified);
modif->setTag(tag);
modif->setLocation(getLocation(n));
modifs->addNodeModif(modif);
}
// have in consideration two spaces in a row
QString nStr(n->tag->tagStr());
QString n2Str(n2->tag->tagStr());
if(nStr[nStr.length() - 1] == ' ' && n2Str[0] == ' ')
{
nStr = nStr.left(nStr.length() - 1);
nStr.append("&nbsp;");
n->tag->setStr(nStr);
n2Str = n2Str.right(n2Str.length() - 1);
n2Str.prepend("&nbsp;");
n2->tag->setStr(n2Str);
}
if((n->tag->type == Tag::Text && n2->tag->type == Tag::Text) ||
(n->tag->type == Tag::Empty && n2->tag->type == Tag::Empty))
n->tag->setStr(n->tag->tagStr() + n2->tag->tagStr());
else if(n->tag->type == Tag::Empty && n2->tag->type == Tag::Text)
n->tag->setStr(n2->tag->tagStr());
//else n's string is already in n
if(n->tag->type == Tag::Text || n2->tag->type == Tag::Text)
n->tag->type = Tag::Text;
if(!n->tag->cleanStrBuilt() || !n2->tag->cleanStrBuilt())
n->tag->setCleanStrBuilt(false);
if(!n->tag->indentationDone() || !n2->tag->indentationDone())
n->tag->setIndentationDone(false);
kafkaCommon::extractAndDeleteNode(n2, modifs, false, false, false);
return true;
}
return false;
}
bool kafkaCommon::mergeNodes(Node *n, Node *n2, NodeSelection& cursorHolder, NodeModifsSet *modifs, bool mergeTextOnly)
{
NodeModif *modif;
Tag *tag;
if(!n || !n2)
return false;
if(((n->tag->type == Tag::Empty && !mergeTextOnly) || n->tag->type == Tag::Text) &&
((n2->tag->type == Tag::Empty && !mergeTextOnly) || n2->tag->type == Tag::Text))
{
tag = new Tag(*(n->tag));
//logging
if(modifs)
{
modif = new NodeModif();
modif->setType(NodeModif::NodeModified);
modif->setTag(tag);
modif->setLocation(getLocation(n));
modifs->addNodeModif(modif);
}
// have in consideration two spaces in a row
QString nStr(n->tag->tagStr());
QString n2Str(n2->tag->tagStr());
if(nStr[nStr.length() - 1] == ' ' && n2Str[0] == ' ')
{
nStr = nStr.left(nStr.length() - 1);
nStr.append("&nbsp;");
n->tag->setStr(nStr);
n2Str = n2Str.right(n2Str.length() - 1);
n2Str.prepend("&nbsp;");
n2->tag->setStr(n2Str);
}
if((n->tag->type == Tag::Text && n2->tag->type == Tag::Text) ||
(n->tag->type == Tag::Empty && n2->tag->type == Tag::Empty))
{
if(cursorHolder.cursorNode() == n2)
cursorHolder.setCursorOffset(n->tag->tagStr().length() + cursorHolder.cursorOffset() - 1);
n->tag->setStr(n->tag->tagStr() + n2->tag->tagStr());
}
else if(n->tag->type == Tag::Empty && n2->tag->type == Tag::Text)
n->tag->setStr(n2->tag->tagStr());
//else n's string is already in n
if(n->tag->type == Tag::Text || n2->tag->type == Tag::Text)
n->tag->type = Tag::Text;
if(!n->tag->cleanStrBuilt() || !n2->tag->cleanStrBuilt())
n->tag->setCleanStrBuilt(false);
if(!n->tag->indentationDone() || !n2->tag->indentationDone())
n->tag->setIndentationDone(false);
kafkaCommon::extractAndDeleteNode(n2, modifs, false, false, false);
cursorHolder.setCursorNode(n);
return true;
}
return false;
}
void kafkaCommon::mergeInlineNode(Node *startNode, Node *endNode, Node **cursorNode,
long &cursorOffset, NodeModifsSet *modifs)
{
Node *startNodeLastInlineParent, *parent, *node, *next;
bool goUp, success, isCursorNode, isEndNode;
int nodeLength;
if(!startNode || !endNode)
return;
//first search for the last inline parent of startNode, and then its last prev neighbour
// which is also inline : the merge will start from this Node.
startNodeLastInlineParent = startNode;
parent = startNode->parent;
while(parent && isInline(parent->tag->name))
{
startNodeLastInlineParent = parent;
parent = parent->parent;
}
if(startNodeLastInlineParent->prev)
{
if(startNodeLastInlineParent->prev->tag->type == Tag::Text)
startNodeLastInlineParent = startNodeLastInlineParent->prev;
else
{
node = startNodeLastInlineParent->prev;
while(node && (node->tag->type == Tag::Empty || node->tag->type == Tag::XmlTagEnd))
node = node->prev;
if(node && node->tag->type == Tag::XmlTag && isInline(node->tag->name))
startNodeLastInlineParent = node;
}
}
//Then navigate though the tree and merge.
node = startNodeLastInlineParent;
goUp = false;
while(node)
{
if(node->tag->type == Tag::XmlTag && isInline(node->tag->name))
{
next = node->next;
while(next && (next->tag->type == Tag::XmlTagEnd || next->tag->type == Tag::Empty))
next = next->next;
while(next && next != node && compareNodes(node, next))
{
while(next->firstChild())
moveNode(next->firstChild(), node, 0L, modifs, false);
if(next == endNode)
endNode = node;
else if((*cursorNode) == node->next)
{
//<TEMPORARY>
(*cursorNode) = node;
//</TEMPORARY>
}
extractNode(next, modifs, false, true);
next = node->next;
while(next && (next->tag->type == Tag::XmlTagEnd || next->tag->type == Tag::Empty))
next = next->next;
}
}
else if(node->tag->type == Tag::Text)
{
while(node->next && (node->next->tag->type == Tag::Text ||
node->next->tag->type == Tag::Empty))
{
nodeLength = (signed)node->tag->tagStr().length();
isCursorNode = ((*cursorNode) == node->next);
isEndNode = (endNode == node->next);
success = mergeNodes(node, node->next, modifs);
if(isCursorNode && success)
{
//<TEMPORARY>
(*cursorNode) = node;
cursorOffset += nodeLength;
//</TEMPORARY>
}
else if(isEndNode && success)
endNode = node;
}
}
if(node == endNode)
break;
node = getNextNode(node, goUp);
}
}
void kafkaCommon::getEndPosition(const QString &tagString, int bLine, int bCol, int &eLine, int &eCol)
{
/**int result, oldResult;
result = tagString.find("\n", 0);
if(result == -1)
{
eLine = bLine;
eCol = bCol + tagString.length() - 1;
}
else
{
eLine = bLine;
while(result != -1)
{
eLine++;
oldResult = result;
result = tagString.find("\n", result + 1);
}
eCol = tagString.length() - oldResult - 2;
}*/
int i;
eLine = bLine;
eCol = bCol - 1;
for(i = 0; i < (signed)tagString.length(); ++i)
{
if(tagString[i] == "\n")
{
eLine++;
eCol = -1;
}
else
eCol++;
}
}
void kafkaCommon::getEndPosition(Node *node, int bLine, int bCol, int &eLine, int &eCol)
{
if(!node)
{
eLine = 0;
eCol = 0;
return;
}
getEndPosition(node->tag->tagStr(), bLine, bCol, eLine, eCol);
}
void kafkaCommon::setTagString(Node *node, const QString &newTagString, NodeModifsSet* modifs)
{
int eLine, eCol, bLine, bCol;
Tag *tag;
NodeModif* modif;
if(!node)
return;
//logging
if(modifs)
{
tag = new Tag(*(node->tag));
modif = new NodeModif();
modif->setType(NodeModif::NodeModified);
modif->setTag(tag);
modif->setLocation(getLocation(node));
modifs->addNodeModif(modif);
}
node->tag->beginPos(bLine, bCol);
node->tag->setStr(newTagString);
getEndPosition(node, bLine, bCol, eLine, eCol);
node->tag->setTagPosition(bLine, bCol, eLine, eCol);
}
void kafkaCommon::setTagStringAndFitsNodes(Node *node, const QString &newTagString, NodeModifsSet* modifs)
{
int eLine, eCol, oldELine, oldECol;
bool b = false;
if(!node)
return;
node->tag->endPos(oldELine, oldECol);
setTagString(node, newTagString, modifs);
node->tag->endPos(eLine, eCol);
fitsNodesPosition(getNextNode(node, b), eCol - oldECol, eLine - oldELine);
}
void kafkaCommon::editNodeAttribute(Node* node, const QString& name, const QString& value, NodeModifsSet* modifs)
{
NodeModif *modif = 0;
if(!node)
return;
if(modifs)
{
modif = new NodeModif();
modif->setType(NodeModif::NodeModified);
modif->setTag(new Tag(*(node->tag)));
modif->setLocation(getLocation(node));
}
if(node->tag->editAttribute(name, value))
{
node->tag->setCleanStrBuilt(false);
if(modifs)
modifs->addNodeModif(modif);
}
}
QValueList<int> kafkaCommon::getLocation(Node * node)
{
QValueList<int> loc;
int i = 0;
while(node)
{
i = 1;
while(node->prev)
{
++i;
node = node->prev;
}
loc.prepend(i);
node = node->parent;
}
return loc;
}
QValueList<int> kafkaCommon::getLocation(DOM::Node domNode)
{
QValueList<int> loc;
int i = 0;
while(!domNode.isNull())
{
i = 1;
while(!domNode.previousSibling().isNull())
{
++i;
domNode = domNode.previousSibling();
}
loc.prepend(i);
domNode = domNode.parentNode();
}
return loc;
}
Node* kafkaCommon::getNodeFromLocation(QValueList<int> loc)
{
QValueList<int>::iterator it;
Node *node = baseNode;
Node *m = 0L;
int i;
if(!node)
return 0L;
for(it = loc.begin(); it != loc.end(); ++it)
{
if(!node)
return 0L;
for(i = 1; i < (*it); ++i)
{
if(!node->next)
return 0L;
node = node->next;
}
m = node;
node = node->child;
}
return m;
}
Node* kafkaCommon::getNodeFromLocation(QValueList<int> loc, Node* nodeTree)
{
QValueList<int>::iterator it;
Node *node = nodeTree;
if(!node)
node = baseNode;
Node *m = 0L;
int i;
if(!node)
return 0L;
for(it = loc.begin(); it != loc.end(); ++it)
{
if(!node)
return 0L;
for(i = 1; i < (*it); ++i)
{
if(!node->next)
return 0L;
node = node->next;
}
m = node;
node = node->child;
}
return m;
}
DOM::Node kafkaCommon::getNodeFromLocation(QValueList<int> loc, DOM::Node rootNode)
{
QValueList<int>::iterator it;
DOM::Node node = rootNode;
DOM::Node m = rootNode;
int i;
if(rootNode.isNull())
return DOM::Node();
for(it = loc.begin(); it != loc.end(); ++it)
{
if(node.isNull())
return DOM::Node();
for(i = 1; i < (*it); ++i)
{
if(node.nextSibling().isNull())
return DOM::Node();
node = node.nextSibling();
}
m = node;
node = node.firstChild();
}
return m;
}
Node* kafkaCommon::getNodeFromSubLocation(QValueList<int> loc, int locOffset)
{
QValueList<int>::iterator it = loc.begin();
QValueList<int> list;
int i;
for(i = 0; i < locOffset; ++i)
{
list.append((*it));
++it;
}
return getNodeFromLocation(list);
}
Node* kafkaCommon::getNodeFromSubLocation(QValueList<int> loc, int locOffset, Node* nodeTree)
{
QValueList<int>::iterator it = loc.begin();
QValueList<int> list;
int i;
for(i = 0; i != locOffset; ++i)
{
list.append((*it));
++it;
}
return getNodeFromLocation(list, nodeTree);
}
int kafkaCommon::compareNodePosition(QValueList<int> pos1, QValueList<int> pos2)
{
QValueList<int>::iterator it1, it2;
it1 = pos1.begin();
it2 = pos2.begin();
while(it1 != pos1.end() && it2 != pos2.end() && (*it1) == (*it2))
{
it1++;
it2++;
}
if(it1 == pos1.end() && it2 == pos2.end())
return kafkaCommon::isAtTheSamePosition;
else if(it1 == pos1.end())
return kafkaCommon::isBefore;
else if(it2 == pos2.end() || (*it1) > (*it2))
return kafkaCommon::isAfter;
else if((*it1) < (*it2))
return kafkaCommon::isBefore;
else
return kafkaCommon::positionError;
}
int kafkaCommon::compareNodePosition(Node *n1, Node *n2)
{
QValueList<int> pos1, pos2;
if(!n1 || !n2)
return kafkaCommon::positionError;
pos1 = getLocation(n1);
pos2 = getLocation(n2);
return compareNodePosition(pos1, pos2);
}
bool kafkaCommon::compareNodes(Node *n1, Node *n2)
{
int i, j;
if(!n1 || !n2)
return false;
if(n1->tag->type != n2->tag->type)
return false;
if(n1->tag->type == Tag::XmlTag)
{
if(n1->tag->name.lower() != n2->tag->name.lower())
return false;
if(n1->tag->attrCount() != n2->tag->attrCount())
return false;
for(i = 0; i < n1->tag->attrCount(); ++i)
{
for(j = 0; j < n2->tag->attrCount(); ++j)
{
if(n1->tag->getAttribute(i).name.lower() == n2->tag->getAttribute(j).name.lower() &&
n1->tag->getAttribute(i).value.lower() == n2->tag->getAttribute(j).value.lower())
break;
}
if(j == n2->tag->attrCount())
return false;
}
}
else if(n1->tag->type == Tag::Text)
{
//TODO
}
return true;
}
int kafkaCommon::nodeDepth(Node *node)
{
int depth = 0;
if(!node)
return -1;
node = node->parent;
while(node)
{
depth++;
node = node->parent;
}
return depth;
}
Node* kafkaCommon::hasParent(Node *node, const QString &name)
{
node = node->parent;
while(node)
{
if(node->tag->name.lower() == name.lower())
return node;
node = node->parent;
}
return 0L;
}
Node* kafkaCommon::hasParent(Node* startNode, Node* endNode, const QString &name)
{
Q_ASSERT(startNode && endNode);
//Andras: don't crash
if (!startNode || !endNode)
return 0;
QValueList<int> commonParentStartChildLocation;
QValueList<int> commonParentEndChildLocation;
Node* node = DTDGetCommonParent(startNode, endNode, commonParentStartChildLocation, commonParentEndChildLocation, 0);
while(node)
{
if(node->tag->name.lower() == name.lower())
return node;
node = node->parent;
}
return 0;
}
bool kafkaCommon::insertDomNode(DOM::Node node, DOM::Node parent, DOM::Node nextSibling,
DOM::Node rootNode)
{
if(node.isNull())
return false;
if(parent.isNull())
{
if(rootNode.isNull())
return false;
parent = rootNode;
}
//Andras: avoid exceptions
if (!nextSibling.isNull() && nextSibling.parentNode() != parent)
{
kdDebug(25001)<< "kafkaCommon::insertDomNode() - invalid nextSibling!" << endl;
return false;
}
if (node.ownerDocument() != parent.ownerDocument())
{
kdDebug(25001)<< "kafkaCommon::insertDomNode() - ownerDocument is different!" << endl;
return false;
}
try
{
parent.insertBefore(node, nextSibling);
}
catch(DOM::DOMException e)
{
kdDebug(25001)<< "kafkaCommon::insertDomNode() - ERROR code :" << e.code << endl;
}
return true;
}
bool kafkaCommon::removeDomNode(DOM::Node node)
{
DOM::Node parent = node.parentNode();
if(parent.isNull())
return false;
parent.removeChild(node);
return true;
}
DOM::Node kafkaCommon::createDomNode(const QString &nodeName, const DTDStruct* dtd,
DOM::Document rootNode)
{
// FIXME
//this will change with the futur multi-DTDs support
//It does not use exceptions handling, so everything is checked via the DTEP definitions.
DOM::Node dn;
QTag *qTag = 0L;
qTag = QuantaCommon::tagFromDTD(dtd, nodeName);
if(qTag)
dn = rootNode.createElement(nodeName);
#ifdef HEAVY_DEBUG
else
kdDebug(25001)<< "kafkaCommon::createDomNode() - ERROR bad nodeName :" <<
nodeName << endl;
#endif
return dn;
}
DOM::Node kafkaCommon::createDomNode(Node *node, DOM::Document rootNode)
{
if(!node)
return DOM::Node();
return createDomNode(node->tag->name, node->tag->dtd(), rootNode);
}
DOM::Node kafkaCommon::createTextDomNode(const QString &textString, DOM::Document rootNode)
{
return rootNode.createTextNode(textString);
}
DOM::Node kafkaCommon::createDomNodeAttribute(const QString &nodeName, const DTDStruct* dtd,
const QString &attrName, const QString &attrValue, DOM::Document rootNode)
{
DOM::Node attr;
QTag *qTag = 0L;
qTag = QuantaCommon::tagFromDTD(dtd, nodeName);
if(!qTag)
return DOM::Node();
if(qTag->isAttribute(attrName))
{
attr = rootNode.createAttribute(attrName);
attr.setNodeValue(attrValue);
}
#ifdef HEAVY_DEBUG
else
kdDebug(25001)<< "kafkaCommon::createDomNodeAttribute() - ERROR bad attrName " <<
attrName << endl;
#endif
return attr;
}
DOM::Node kafkaCommon::createDomNodeAttribute(Node* node, const QString &attrName,
DOM::Document rootNode)
{
if(!node)
return DOM::Node();
return createDomNodeAttribute(node->tag->name, node->tag->dtd(), attrName, "", rootNode);
}
//DOM::node kafkaCommon::createDomNodeAttribute(DOM::Node node, const QString &attrName,
// DOM::Document rootNode)
//{
/**if(node.isNull())
return DOM::node();
return createDomNodeAttribute()*/
//}
bool kafkaCommon::insertDomNodeAttribute(DOM::Node node, DOM::Node attr)
{
if(node.isNull())
return false;
//should we check if the attr is valid???
node.attributes().setNamedItem(attr);
return true;
}
bool kafkaCommon::editDomNodeAttribute(DOM::Node node, const QString &nodeName, const DTDStruct* dtd,
const QString &attrName, const QString &attrValue, DOM::Document rootNode)
{
DOM::Node attr;
if(node.isNull())
return false;
attr = node.attributes().getNamedItem(attrName);
if(attr.isNull())
{
//let's create it
attr = createDomNodeAttribute(nodeName, dtd, attrName, attrValue, rootNode);
if(attr.isNull())
return false;
insertDomNodeAttribute(node, attr);
}
return true;
}
bool kafkaCommon::editDomNodeAttribute(DOM::Node domNode, Node* node,
const QString &attrName, const QString &attrValue, DOM::Document rootNode)
{
if(!node)
return false;
return editDomNodeAttribute(domNode, node->tag->name, node->tag->dtd(),
attrName, attrValue, rootNode);
}
DOM::Node kafkaCommon::hasParent(DOM::Node domNode, const QString &name)
{
while(!domNode.isNull())
{
if(domNode.nodeName().string().lower() == name.lower())
return domNode;
domNode = domNode.parentNode();
}
return DOM::Node();
}
int kafkaCommon::childPosition(DOM::Node domNode)
{
DOM::Node parentNode, child;
int position = 1;
if(domNode.isNull())
return -1;
parentNode = domNode.parentNode();
child = parentNode.firstChild();
while(!child.isNull() && child != domNode)
{
position++;
child = child.nextSibling();
}
if(child == domNode)
return position;
else
return -1;
}
DOM::Node kafkaCommon::getChildNode(DOM::Node parentNode, int position, bool fallback)
{
DOM::Node child;
if(parentNode.isNull())
return DOM::Node();
child = parentNode.firstChild();
while(!child.isNull() && position > 1 && ((fallback && !child.nextSibling().isNull()) || !fallback ))
{
child = child.nextSibling();
position--;
}
return child;
}
bool kafkaCommon::isInline(DOM::Node domNode)
{
if(domNode.isNull())
return false;
if(domNode.nodeType() == DOM::Node::TEXT_NODE)
return true;
return isInline(domNode.nodeName().string());
}
bool kafkaCommon::parentSupports(DOM::Node parent, DOM::Node startNode, DOM::Node endNode,
const DTDStruct* dtd)
{
QTag *parentQTag;
DOM::Node child;
if(!dtd || parent.isNull())
return false;
parentQTag = QuantaCommon::tagFromDTD(dtd, parent.nodeName().string());
if(!parentQTag)
return false;
child = startNode;
while(!child.isNull())
{
if(!parentQTag->isChild(child.nodeName().string()))
return false;
if(child == endNode)
return true;
child = child.nextSibling();
}
return true;
}
bool kafkaCommon::isInline(const QString &nodeNam)
{
QString nodeName = nodeNam.lower();
if(nodeName == "q" || nodeName == "u" || nodeName == "i" || nodeName == "b" ||
nodeName == "cite" || nodeName == "em" || nodeName == "var" || nodeName == "em" ||
nodeName == "tt" || nodeName == "code" || nodeName == "kbd" || nodeName == "samp" ||
nodeName == "big" || nodeName == "small" || nodeName == "s" || nodeName == "strike" ||
nodeName == "sub" || nodeName == "sup" || nodeName == "abbr" ||
nodeName == "acronym" || nodeName == "a" || nodeName == "bdo" ||
nodeName == "font" || nodeName == "#text" || nodeName == "strong" || nodeName == "dfn" ||
nodeName == "img" || nodeName == "applet" || nodeName == "object" || nodeName == "basefont" ||
nodeName == "br" || nodeName == "script" || nodeName == "map" || nodeName == "span" ||
nodeName == "iframe" || nodeName == "input" || nodeName == "select" || nodeName == "textarea" ||
nodeName == "label" || nodeName == "button" )
return true;
else
return false;
}
#ifdef HEAVY_DEBUG
void kafkaCommon::coutDomTree(DOM::Node rootNode, int indent)
#else
void kafkaCommon::coutDomTree(DOM::Node, int)
#endif
{
#ifdef HEAVY_DEBUG
QString output, dots;
int j;
DOM::Node node;
if(rootNode.isNull())
kdDebug(25001)<< "kafkaCommon::coutDomTree() - bad node!" << endl;
node = rootNode;
while (!node.isNull())
{
dots = "";
dots.fill('_', indent);
output = dots;
if (node.nodeType() != DOM::Node::TEXT_NODE)
output += node.nodeName().string().replace('\n'," ");
else
{
output += "\"";
output+= node.nodeValue().string().replace('\n'," ");
output += "\"";
}
kdDebug(25001) << output <<" (" << node.nodeType() << ") "<<
node.handle() << endl;
kdDebug(25001)<< dots << " +++ prev " << node.previousSibling().handle() << " next " <<
node.nextSibling().handle() << " parent " <<
node.parentNode().handle() << " child " << node.firstChild().handle() << endl;
for(j = 0; j < (int)node.attributes().length(); ++j)
{
kdDebug(25001)<< dots << " *** attr" << j << " " <<
node.attributes().item(j).nodeName().string() << " - " <<
node.attributes().item(j).nodeValue().string() << endl;
}
if (node.hasChildNodes())
coutDomTree(node.firstChild(), indent + 4);
node = node.nextSibling();
}
#endif
}
void kafkaCommon::coutTree(Node *node, int indent)
{
QString output, dots;
int bLine, bCol, eLine, eCol, j;
if(!node)
kdDebug(25001)<< "kafkaCommon::coutTree() - bad node!" << endl;
while (node)
{
dots = "";
dots.fill('.', indent);
output = dots;
node->tag->beginPos(bLine, bCol);
node->tag->endPos(eLine, eCol);
if (node->tag->type == Tag::XmlTag || node->tag->type == Tag::XmlTagEnd ||
node->tag->type == Tag::ScriptTag)
output += node->tag->name.replace('\n',"<return>");
else
{
output += "\"";
output+= node->tag->tagStr().replace('\n',"<return>");
output += "\"";
}
kdDebug(25001) << output <<" (" << node->tag->type << ", " << node->tag->cleanStrBuilt() << ", " <<
node->tag->indentationDone() << ") "<< node << " at pos " << bLine << ":" << bCol << " - " <<
eLine << ":" << eCol << endl;
kdDebug(25001)<< dots << " +++ prev " << node->prev << " next " << node->next << " parent " <<
node->parent << " child " << node->child << endl;
for(j = 0; j < node->tag->attrCount(); ++j)
{
kdDebug(25001)<< dots << " *** attr" << j << " " <<
node->tag->getAttribute(j).nameLine << ":" <<
node->tag->getAttribute(j).nameCol << ":" <<
node->tag->getAttribute(j).name << " - " <<
node->tag->getAttribute(j).valueLine << ":" <<
node->tag->getAttribute(j).valueCol << ":" <<
node->tag->getAttribute(j).value << endl;
}
if (node->child)
coutTree(node->child, indent + 4);
if(node == node->next || (node->next && node == node->next->next) ||
(node->next && node->next->next && node == node->next->next->next) ||
(node->next && node->next->next && node->next->next->next &&
node == node->next->next->next->next) || (node->next && node->next->next &&
node->next->next->next && node->next->next->next->next && node ==
node->next->next->next->next->next))
{
//try to detect invalid pointers.
kdDebug(25001)<< "ERROR - node == node->[..]next" << endl;
return;
}
node = node->next;
}
}
int kafkaCommon::isInsideTag(Node* start_node, Node* end_node, QString const& tag_name)
{
Q_ASSERT(start_node && end_node);
//Andras: don't crash
if (!start_node || !end_node)
return -1;
Node* tag_start = hasParent(start_node, end_node, tag_name);
if(tag_start)
return 1; // both start_node and end_node are surrounded by tag_name
tag_start = hasParent(start_node, tag_name);
if(tag_start)
return 0; // only start_node has tag_name as parent
tag_start = hasParent(end_node, tag_name);
if(tag_start)
return 0; // only end_node has tag_name as parent
return -1; // neither the nodes have tag_name as parent
}
int kafkaCommon::isInsideTag(Node* start_node, Node* end_node, QString const& tag_name,
QString const& attribute_name, QString const& attribute_value)
{
Q_ASSERT(start_node && end_node);
//Andras: don't crash
if (!start_node || !end_node)
return -1;
Node* tag_start = hasParent(start_node, end_node, tag_name);
if(tag_start && tag_start->tag->hasAttribute(attribute_name) && tag_start->tag->attributeValue(attribute_name, true) == attribute_value)
return 1; // both start_node and end_node are surrounded by tag_name
tag_start = hasParent(start_node, tag_name);
if(tag_start && tag_start->tag->hasAttribute(attribute_name) && tag_start->tag->attributeValue(attribute_name, true) == attribute_value)
return 0; // only start_node has tag_name as parent
tag_start = hasParent(end_node, tag_name);
if(tag_start && tag_start->tag->hasAttribute(attribute_name) && tag_start->tag->attributeValue(attribute_name, true) == attribute_value)
return 0; // only end_node has tag_name as parent
return -1; // neither the nodes have tag_name as parent
}
bool kafkaCommon::isBetweenWords(Node* node, int offset)
{
Q_ASSERT(node->tag->type == Tag::Text || node->tag->type == Tag::Empty);
Q_ASSERT(offset >= 0);
Q_ASSERT(node);
if (!node)
return false; //FIXME: Andras: don't crash
QString tag_str = node->tag->tagStr();
return !
(tag_str[offset].isSpace() || tag_str[offset].isPunct() ||
tag_str[offset - 1].isSpace() || tag_str[offset - 1].isPunct());/* ||
tag_str[offset + 1].isSpace() || tag_str[offset + 1].isPunct());*/
}
void kafkaCommon::getStartOfWord(Node*& node, int& offset)
{
Q_ASSERT(node);
// Q_ASSERT(isBetweenWords(node, offset)); recursive
Q_ASSERT(offset >= 0);
//Andras: don't crash
if (!node || offset < 0)
return;
kdDebug(23100) << "getStartOfWord node length: " << node->tag->tagStr().length() << endl;
kdDebug(23100) << "getStartOfWord offset BEGIN: " << offset << endl;
QString tag_str = node->tag->tagStr();
while(offset >= 0 && !tag_str[offset].isSpace() && !tag_str[offset].isPunct())
--offset;
if(offset == -1)
{
Node* aux = node->previousSibling();
while(aux && aux->tag->type != Tag::Text)
{
if(!isInline(aux->tag->name))
{
++offset;
return;
}
aux = aux->previousSibling();
}
if(aux)
{
node = aux;
offset = aux->tag->tagStr().length() - 1;
kdDebug(23100) << "getStartOfWord node length: " << node->tag->tagStr().length() << endl;
kdDebug(23100) << "getStartOfWord offset RECURS: " << offset << endl;
getStartOfWord(node, offset);
return;
}
}
++offset;
kdDebug(23100) << "getStartOfWord node length: " << node->tag->tagStr().length() << endl;
kdDebug(23100) << "getStartOfWord offset END: " << offset << endl;
}
void kafkaCommon::getEndOfWord(Node*& node, int& offset)
{
Q_ASSERT(node);
// assert(isBetweenWords(node, offset)); recursive
Q_ASSERT(isBetweenWords(node, offset));
Q_ASSERT(offset >= 0);
//Andras: if the following asserts are hit, don't do anything = don't crash
if (!node || !isBetweenWords(node, offset) || offset < 0)
return;
QString tag_str = node->tag->tagStr();
while((uint)offset != tag_str.length() && !tag_str[offset].isSpace() && !tag_str[offset].isPunct())
++offset;
if((uint)offset == tag_str.length())
{
Node* aux = node->nextSibling();
while(aux && aux->tag->type != Tag::Text)
{
if(!isInline(aux->tag->name))
return;
aux = aux->nextSibling();
}
if(aux)
{
node = aux;
offset = 0;
getEndOfWord(node, offset);
}
}
}
void kafkaCommon::getStartOfParagraph(Node*& node, int& offset)
{
Q_ASSERT(node);
//Andras: don't crash
if (!node)
{
offset = 0;
return;
}
Node* previous = node->previousSibling();
while(previous && (isInline(previous->tag->name) || previous->tag->name.lower() == "br" || previous->tag->type == Tag::Text))
previous = previous->previousSibling();
offset = 0;
if(previous)
{
node = previous->nextSibling();
return;
}
Q_ASSERT(node->tag->type == Tag::Text);
}
void kafkaCommon::getEndOfParagraph(Node*& node, int& offset)
{
Q_ASSERT(node);
if (!node)
{
offset = 0;
return;
}
Node* begin_paragraph = node;
getStartOfParagraph(begin_paragraph, offset);
Node* next = begin_paragraph->nextSibling();
while(nodeDepth(next) > nodeDepth(begin_paragraph))
next = next->nextSibling();
while(next && (isInline(next->tag->name) || next->tag->name.lower() == "br" || next->tag->type == Tag::Text))
{
next = next->nextSibling();
while(nodeDepth(next) > nodeDepth(node))
next = next->nextSibling();
}
if(next)
{
node = next;
if(nodeDepth(next) < nodeDepth(begin_paragraph))
node = node->previousSibling();
if(node->tag->type == Tag::Text)
offset = node->tag->tagStr().length() - 1;
else
offset = 0;
return;
}
}