/*************************************************************************** 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 #include #include #include #include #include #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 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, TQValueList& commonParentStartChildLocation, TQValueList& commonParentEndChildLocation, Node* nodeSubtree) { // look for commonParent Node* commonParent = 0; Node* commonParentStartChild = 0, *commonParentEndChild = 0; int locOffset = 1; TQValueList startNodeLocation = getLocation(startNode); TQValueList endNodeLocation = getLocation(endNode); TQValueList::iterator itStart = startNodeLocation.begin(); TQValueList::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, TQValueList& commonParentStartChildLocation, TQValueList& commonParentEndChildLocation, Node* nodeSubtree) { // look for commonParent Node* commonParent = 0; Node* commonParentStartChild = 0, *commonParentEndChild = 0; int locOffset = 1; TQValueList startNodeLocation = getLocation(startNode); TQValueList endNodeLocation = getLocation(endNode); TQValueList::iterator itStart = startNodeLocation.begin(); TQValueList::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; TQString 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 += TQString().fill('\t', nbOfTabs * nonInlineDepth); indentation2 += TQString().fill('\t', nbOfTabs * nonInlineDepth2); } else // spaces are used { indentation1 += TQString().fill(' ', nbOfSpaces * nonInlineDepth); indentation2 += TQString().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) { TQString 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; } TQString kafkaCommon::removeUnnecessaryWhitespaces(const TQString &string, bool removeAllSpacesAtTheLeft, bool removeAllSpacesAtTheRight) { /**TQString 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;*/ TQString newString; bool hasLeftWhiteSpaces, hasRightWhiteSpaces; if(string.length() == 0) return TQString(); 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 TQString &nodeName, const TQString &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 TQString &encoding) { Node *node, *child, *closingNode; TQString 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) { TQTag *nodeTQTag, *oldNodeTQTag; bool searchForMandatoryNode; Node *currentParent; TQMap::iterator it; if(!node) return 0L; nodeTQTag = QuantaCommon::tagFromDTD(node); if(!nodeTQTag) return false; searchForMandatoryNode = true; currentParent = node; while(searchForMandatoryNode) { oldNodeTQTag = nodeTQTag; for(it = nodeTQTag->childTags.begin(); it != nodeTQTag->childTags.end(); ++it) { if(it.data()) { nodeTQTag = QuantaCommon::tagFromDTD(nodeTQTag->parentDTD, it.key()); if(!nodeTQTag) return node; currentParent = createAndInsertNode(nodeTQTag->name(), "", Tag::XmlTag, doc, currentParent, 0L, 0L, (NodeModifsSet*)0L); break; } } if(oldNodeTQTag == nodeTQTag) 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 tqchildren 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 tqchildren 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. boo|baa should be translated to boo|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 TQValueList commonParentStartChildLocation; TQValueList 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)) { // 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) { TQTag* nodeTQTag = QuantaCommon::tagFromDTD(parentNode); if(!nodeTQTag || !nodeTQTag->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 TQValueList startNodeLocation, endNodeLocation; TQValueList::iterator itStart, itEnd; Node *commonParent = 0L, *commonParentStartChild, *commonParentEndChild, *parentNode, *node; Node *lastValidStartParent = 0L, *lastValidEndParent = 0L, *newParentNode, *child, *next; Node *oldCommonParent, *lastNewNode, *oldParentNode; TQTag *parentNodeTQTag = 0, *newNodeTQTag, *lastNewNodeTQTag; 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); lastNewNodeTQTag = QuantaCommon::tagFromDTD(lastNewNode); newNodeTQTag = QuantaCommon::tagFromDTD(newNode); if(!newNodeTQTag || !lastNewNodeTQTag) { 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) { parentNodeTQTag = QuantaCommon::tagFromDTD(parentNode); if(parentNodeTQTag && parentNodeTQTag->isChild(newNode) && lastNewNodeTQTag->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) { parentNodeTQTag = QuantaCommon::tagFromDTD(parentNode); if(parentNodeTQTag && parentNodeTQTag->isChild(newNode) && lastNewNodeTQTag->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)) { // 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; } 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) parentNodeTQTag = QuantaCommon::tagFromDTD(commonParent); else if((signed)startNode->tag->tagStr().length() == startOffset && startNode->tag->type == Tag::XmlTag) parentNodeTQTag = QuantaCommon::tagFromDTD(startNode); else if((signed)startNode->tag->tagStr().length() == startOffset && startNode->tag->type == Tag::XmlTagEnd) parentNodeTQTag = QuantaCommon::tagFromDTD(startNode->parent); if(!parentNodeTQTag || (parentNodeTQTag && parentNodeTQTag->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); // (*cursorNode) = lastNewNode; cursorOffset = 0; // 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 TQString &nodeName, const TQString &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 TQString &nodeName, const TQString &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 TQString &nodeName, const TQString &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 TQString &nodeName, const TQString &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" <parent) { currentNodeParentTQTag = QuantaCommon::tagFromDTD(currentNode->parent); if(currentNodeParentTQTag && currentNodeParentTQTag->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) && leafNodeTQTag->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) { TQPtrList 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; TQString namespaceName, nodeName, caseSensitive; TQString closingNamespaceName, closingNodeName, closingCaseSensitive; TQValueList 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 tqchildren move if we don't extract the tqchildren 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.isEmpty(), closingNamespaceName, closingNodeName, !closingCaseSensitive.isEmpty())) 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; TQValueList commonParentStartChildLocation; TQValueList 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; TQValueList commonParentStartChildLocation; TQValueList 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; TQValueList commonParentStartChildLocation; TQValueList 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); TQValueList const startNodeLocation = getLocation(startNode); TQValueList const commonParentLocation = getLocation(commonParent); uint const commonParentDepth = commonParentLocation.size(); uint const newStartNodeDepth = startNodeLocation.size() - commonParentDepth + 1; uint const newEndNodeDepth = startNodeLocation.size() - commonParentDepth + 1; TQValueList newStartNodeLocation, newEndNodeLocation; newStartNodeLocation.push_back(1); newEndNodeLocation.push_back(1); for(uint i = 1; i != newStartNodeDepth; ++i) newStartNodeLocation.push_back(startNodeLocation[i + commonParentDepth - 1]); TQValueList 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; TQString 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 TQString &nodeName, Document *doc, Node *startNode, int startOffset, Node *endNode, int endOffset, Node **cursorNode, long &cursorOffset, NodeModifsSet *modifs) { TQTag *nodeNameTQTag, *parentTQTag; 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. nodeNameTQTag = QuantaCommon::tagFromDTD(doc->defaultDTD(), nodeName); if(!nodeNameTQTag) 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; // if(startNode == (*cursorNode) && cursorOffset > startOffset) { (*cursorNode) = (*cursorNode)->nextSibling(); cursorOffset -= startOffset; } // 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()) { parentTQTag = QuantaCommon::tagFromDTD(node->parent); if(parentTQTag) { child = node->firstChild(); while(child) { if(!parentTQTag->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; // if(result) { (*cursorNode) = node; cursorOffset += startOffset; } // } 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; TQString 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, TQValueList& 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, TQValueList& commonParentStartChildLocation, TQValueList& 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, TQValueList& commonParentStartChildLocation, TQValueList& 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 TQString nStr(n->tag->tagStr()); TQString n2Str(n2->tag->tagStr()); if(nStr[nStr.length() - 1] == ' ' && n2Str[0] == ' ') { nStr = nStr.left(nStr.length() - 1); nStr.append(" "); n->tag->setStr(nStr); n2Str = n2Str.right(n2Str.length() - 1); n2Str.prepend(" "); 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 TQString nStr(n->tag->tagStr()); TQString n2Str(n2->tag->tagStr()); if(nStr[nStr.length() - 1] == ' ' && n2Str[0] == ' ') { nStr = nStr.left(nStr.length() - 1); nStr.append(" "); n->tag->setStr(nStr); n2Str = n2Str.right(n2Str.length() - 1); n2Str.prepend(" "); 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) { // (*cursorNode) = node; // } 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) { // (*cursorNode) = node; cursorOffset += nodeLength; // } else if(isEndNode && success) endNode = node; } } if(node == endNode) break; node = getNextNode(node, goUp); } } void kafkaCommon::getEndPosition(const TQString &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 TQString &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 TQString &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 TQString& name, const TQString& 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); } } TQValueList kafkaCommon::getLocation(Node * node) { TQValueList loc; int i = 0; while(node) { i = 1; while(node->prev) { ++i; node = node->prev; } loc.prepend(i); node = node->parent; } return loc; } TQValueList kafkaCommon::getLocation(DOM::Node domNode) { TQValueList 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(TQValueList loc) { TQValueList::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(TQValueList loc, Node* nodeTree) { TQValueList::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(TQValueList loc, DOM::Node rootNode) { TQValueList::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(TQValueList loc, int locOffset) { TQValueList::iterator it = loc.begin(); TQValueList list; int i; for(i = 0; i < locOffset; ++i) { list.append((*it)); ++it; } return getNodeFromLocation(list); } Node* kafkaCommon::getNodeFromSubLocation(TQValueList loc, int locOffset, Node* nodeTree) { TQValueList::iterator it = loc.begin(); TQValueList list; int i; for(i = 0; i != locOffset; ++i) { list.append((*it)); ++it; } return getNodeFromLocation(list, nodeTree); } int kafkaCommon::compareNodePosition(TQValueList pos1, TQValueList pos2) { TQValueList::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) { TQValueList 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 TQString &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 TQString &name) { Q_ASSERT(startNode && endNode); //Andras: don't crash if (!startNode || !endNode) return 0; TQValueList commonParentStartChildLocation; TQValueList 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 TQString &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; TQTag *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 TQString &textString, DOM::Document rootNode) { return rootNode.createTextNode(textString); } DOM::Node kafkaCommon::createDomNodeAttribute(const TQString &nodeName, const DTDStruct* dtd, const TQString &attrName, const TQString &attrValue, DOM::Document rootNode) { DOM::Node attr; TQTag *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 TQString &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 TQString &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 TQString &nodeName, const DTDStruct* dtd, const TQString &attrName, const TQString &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 TQString &attrName, const TQString &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 TQString &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) { TQTag *parentTQTag; DOM::Node child; if(!dtd || parent.isNull()) return false; parentTQTag = QuantaCommon::tagFromDTD(dtd, parent.nodeName().string()); if(!parentTQTag) return false; child = startNode; while(!child.isNull()) { if(!parentTQTag->isChild(child.nodeName().string())) return false; if(child == endNode) return true; child = child.nextSibling(); } return true; } bool kafkaCommon::isInline(const TQString &nodeNam) { TQString 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 TQString 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) { TQString 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',""); else { output += "\""; output+= node->tag->tagStr().replace('\n',""); 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, TQString 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, TQString const& tag_name, TQString const& attribute_name, TQString 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 TQString 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; TQString 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; TQString 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; } }