From e9ae80694875f869892f13f4fcaf1170a00dea41 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdewebdev@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- quanta/parts/kafka/wkafkapart.cpp | 2407 +++++++++++++++++++++++++++++++++++++ 1 file changed, 2407 insertions(+) create mode 100644 quanta/parts/kafka/wkafkapart.cpp (limited to 'quanta/parts/kafka/wkafkapart.cpp') diff --git a/quanta/parts/kafka/wkafkapart.cpp b/quanta/parts/kafka/wkafkapart.cpp new file mode 100644 index 00000000..5641bb36 --- /dev/null +++ b/quanta/parts/kafka/wkafkapart.cpp @@ -0,0 +1,2407 @@ +/*************************************************************************** + wkafkapart.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. * + * * + ***************************************************************************/ + +#define HEAVY_DEBUG 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "document.h" +#include "viewmanager.h" +#include "quantacommon.h" +#include "resource.h" +#include "undoredo.h" +#include "node.h" +#include "parser.h" +#include "project.h" +#include "tag.h" +#include "nodeproperties.h" +#include "htmlenhancer.h" +#include "kafkacommon.h" +#include "kafkaresource.h" +#include "cursors.h" +#include "kafkadragobject.h" +#include "cursors.h" + +#include "wkafkapart.moc" + +KafkaWidget *kafkaWidget; +KafkaDocument *kafkaDoc; + +KafkaDocument::KafkaDocument(QWidget *parent, QWidget *widgetParent, const char *name) +:domNodeProps(1021), _docLoaded(false) +{ +// i18n reserve +QString a = i18n("Selector");QString b = i18n("Attribute");QString c = i18n("Class"); +QString d = i18n("Pseudo-class");QString e = i18n("CSS rules");QString f = i18n("Universal selector"); +QString g = i18n("Linked stylesheets");QString h = i18n("Embedded stylesheets");QString i = i18n("Inline style attribute"); +QString j = i18n("Link");QString k = i18n("Priority");QString l = i18n("ID"); +QString m = i18n("Browser support");QString n = i18n("Pseudo-element");QString o = i18n("Imported"); +QString p = i18n("Inheritance");QString q = i18n("Inherited");QString r = ""; + +QString s = i18n("Name");QString tt = i18n("Undo");QString u = i18n("Redo"); +QString v = i18n("Undo/Redo history");QString w = i18n("CSS styles"); + +QString x = i18n("Sorry, VPL does not support this functionality yet."); +QString y = i18n("Merge cells"); +QString z = i18n("Split cells"); +QString aa = i18n("Edit CSS style of this Tag"); +QString ab = i18n("Ident all"); +//end + +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::KafkaDocument()" << endl; +#endif + + kafkaDoc = this; + + m_kafkaPart = new KafkaWidget(parent, widgetParent,this, name); + kafkaWidget = m_kafkaPart; + //m_kafkaPart->showDomTree(); + m_currentDoc = 0L; + mainEnhancer = new HTMLEnhancer(this); + domNodeProps.setAutoDelete(false); + + KStandardDirs *m_stddirs = new KStandardDirs(); + QFile file( m_stddirs->findResource("data", "kafkapart/entities" )/**locate("appdata","chars") */); + delete m_stddirs; + QString tmp; + if ( file.open(IO_ReadOnly) ) + { + QTextStream t( &file ); // use a text stream + t.setEncoding(QTextStream::UnicodeUTF8); + while ( !t.eof() ) + { + tmp = t.readLine(); + if(tmp.left(2) == "//") continue;//comments + int begin = tmp.find("(") + 1; + if(begin == (-1 + 1)) continue;//"(" not found : invalid line + int length = tmp.find(")") - begin; + decodedChars.insert(tmp.left(1), tmp.mid(begin, length)); + encodedChars.insert(tmp.mid(begin, length), tmp.left(1)); + } + file.close(); + } + + connect(m_kafkaPart, SIGNAL(domNodeInserted(DOM::Node, bool, NodeModifsSet*)), + this, SLOT(slotDomNodeInserted(DOM::Node, bool, NodeModifsSet*))); + connect(m_kafkaPart, SIGNAL(domNodeModified(DOM::Node, NodeModifsSet*)), + this, SLOT(slotDomNodeModified(DOM::Node, NodeModifsSet*))); + connect(m_kafkaPart, SIGNAL(domNodeIsAboutToBeRemoved(DOM::Node, bool, NodeModifsSet*)), + this, SLOT(slotDomNodeAboutToBeRemoved(DOM::Node, bool, NodeModifsSet*))); + connect(m_kafkaPart, SIGNAL(domNodeIsAboutToBeMoved(DOM::Node, DOM::Node, DOM::Node, NodeModifsSet*)), + this, SLOT(slotDomNodeIsAboutToBeMoved(DOM::Node, DOM::Node, DOM::Node, NodeModifsSet*))); + + connect(m_kafkaPart, SIGNAL(domNodeNewCursorPos(DOM::Node, int)), + this, SLOT(slotdomNodeNewCursorPos(DOM::Node, int))); + +} + +KafkaDocument::~KafkaDocument() +{ +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::~KafkaDocument()" << endl; +#endif + //delete the empty node linked to the DOM::Node #document + disconnectAllDomNodes(); +} + +void KafkaDocument::loadDocument(Document *doc) +{ +#ifdef LIGHT_DEBUG + kdDebug(25001) << "KafkaDocument::loadDocument()" << endl; +#endif + Node *node; + Tag *tag; + DOM::Node domNode; + bool goUp; + + if(!m_kafkaPart) return; + if(!doc) return; +#ifdef LIGHT_DEBUG + QTime t; + t.start(); +#endif + m_currentDoc = doc; + + (static_cast(mainEnhancer))->setBaseURL(Project::ref()->projectBaseURL()); + + //create a empty document with a basic tree : HTML, HEAD, BODY + m_kafkaPart->newDocument(); + + // When loading a weird html file in khtml (e.g. without BODY or HTML), khtml takes care + // to create the necessary tags. But as we are handling directly the Nodes, we have to handle this!! + // creating and linking an empty node to the root DOM::Node (#document) and + // to HEAD, HTML, BODY + node = new Node(0L); + tag = new Tag(); + tag->name = "#document"; + tag->setNotInTree(true); + node->tag = tag; + connectDomNodeToQuantaNode(m_kafkaPart->document(), node); + node = new Node(0L); + tag = new Tag(); + tag->name = "HTML"; + tag->setNotInTree(true); + node->tag = tag; + connectDomNodeToQuantaNode(m_kafkaPart->document().firstChild(), node); + html = m_kafkaPart->document().firstChild(); + node = new Node(0L); + tag = new Tag(); + tag->name = "HEAD"; + tag->setNotInTree(true); + node->tag = tag; + connectDomNodeToQuantaNode(m_kafkaPart->document().firstChild().firstChild(), node); + head = m_kafkaPart->document().firstChild().firstChild(); + node = new Node(0L); + tag = new Tag(); + tag->name = "BODY"; + tag->setNotInTree(true); + node->tag = tag; + connectDomNodeToQuantaNode(m_kafkaPart->document().firstChild().lastChild(), node); + body = m_kafkaPart->document().firstChild().lastChild(); + + //load the DOM::Nodes from the node tree. + node = baseNode; + while(node) + { +#ifdef HEAVY_DEBUG + kdDebug(25001) << "KafkaDocument::loadDocument - Node name :" << + node->tag->name.upper() << "; type : " << + node->tag->type << "; tagstr : " << node->tag->tagStr() << + " is opened :" << node->opened << endl; +#endif + if(!buildKafkaNodeFromNode(node)) + emit loadingError(node); + node = node->nextSibling(); + } + + //post process the DOM::Node Tree by adding Empty TEXT so that the cursor can go + //everywhere the user wants. + domNode = m_kafkaPart->document(); + goUp = false; + while(!domNode.isNull()) + { + mainEnhancer->postEnhanceNode(domNode); + domNode = kafkaCommon::getNextDomNode(domNode, goUp); + } + + m_kafkaPart->putCursorAtFirstAvailableLocation(); + _docLoaded = true; + + //Avoid moving objects... + m_kafkaPart->stopAnimations(); + + m_currentDoc->docUndoRedo->kafkaLoaded(); + emit loaded(); + + m_currentDoc->docUndoRedo->syncKafkaCursorAndSelection(0); + //m_kafkaPart->document().updateRendering(); + +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::loadDocument() in " << t.elapsed() << " ms only!" << endl; +#endif +#ifdef HEAVY_DEBUG + kafkaCommon::coutDomTree(m_kafkaPart->document(), 2); + coutLinkTree(baseNode, 2); +#endif +} + +void KafkaDocument::unloadDocument() +{ +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::unloadDocument()" << endl; +#endif + Node *node; + + domNodeProps.clear(); + //clean the kafkapart + while(m_kafkaPart->document().hasChildNodes()) + m_kafkaPart->document().removeChild(m_kafkaPart->document().firstChild()); + m_currentDoc = 0L; + + html = body = head = DOM::Node(); + + _docLoaded = false; + node = baseNode; + while(node) + { + if(node->rootNode()) + delete node->rootNode(); + node->setRootNode(0L); + if(node->leafNode()) + delete node->leafNode(); + node->setLeafNode(0L); + node = node->nextSibling(); + } + emit unloaded(); +} + +void KafkaDocument::reloadDocument() +{ +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::reloadDocument()" << endl; +#endif + Node *node; + int offsetX, offsetY; + + offsetX = m_kafkaPart->view()->contentsX(); + offsetY = m_kafkaPart->view()->contentsY(); + + m_kafkaPart->closeURL(); + + if(!_docLoaded) + return; + + domNodeProps.clear(); + while(m_kafkaPart->document().hasChildNodes()) + m_kafkaPart->document().removeChild(m_kafkaPart->document().firstChild()); + node = baseNode; + while(node) + { + if(node->rootNode()) + delete node->rootNode(); + node->setRootNode(0L); + if(node->leafNode()) + delete node->leafNode(); + node->setLeafNode(0L); + node = node->nextSibling(); + } + + /**KParts::URLArgs args(false, offsetX, offsetY); + (static_cast(((KParts::ReadOnlyPart *)m_kafkaPart)->child( 0L, + "KParts::BrowserExtension" )))->setURLArgs( args );*/ + + loadDocument(m_currentDoc); + + //m_kafkaPart->view()->setContentsPos(offsetX, offsetY); +} + +kNodeAttrs *KafkaDocument::getAttrs(DOM::Node _domNode) +{ + return domNodeProps[_domNode.handle()]; +} + + +Node *KafkaDocument::getNode(DOM::Node _domNode) +{ + if(_domNode.isNull() || _domNode.nodeName().string() == "#document") + { + kdDebug(25001)<< "KafkaDocument::getNode() - Bad Node given" << + endl; + return 0L; + } + kNodeAttrs *props = domNodeProps[_domNode.handle()]; + if(!props) + { + kdDebug(25001)<< "KafkaDocument::getNode() -" << + " Corresponding Node not Found!!!" << endl; + return 0L; + } + return props->getNode(); +} + +kNodeAttrs* KafkaDocument::connectDomNodeToQuantaNode(DOM::Node domNode, Node *node) +{ + QString name; + kNodeAttrs *props; + + if(domNode.isNull()) + { +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::connectDomNodeToQuantaNode()" << + " - WARNING empty DOM::Node" << endl; +#endif + } + /**qtag = QuantaCommon::tagFromDTD(m_currentDoc->defaultDTD(), + _domNode.nodeName().string());*/ + else + name = domNode.nodeName().string().lower(); + +// kdDebug(25001) << "KafkaDocument::connectDomNodeToQuantaNode() - domNode name: |" << name << "|" << endl; + + props = new kNodeAttrs(); + + //We can split Nodes into several groups essentially for the deletion behavior: + //1- Text + //2- Block in which the cursor can't enter in when deleting e.g. TABLE, IMG + //3- Block in which the cursor can't escape from e.g. TD, BODY + //4- Block in which the cursor can enter in/escape from when deleting e.g. H1, DIV + //5- Inline + //6- "Invisible" Nodes e.g. HTML, HEAD + + //Hmmm... I guess we can do better here... + if(domNode.nodeType() == DOM::Node::TEXT_NODE) + { + props->setCHCursorFocus(kNodeAttrs::textNode); + props->setCCEnter(true); + props->setCBModified(true); + props->setCBDeleted(true); + } + else if(name == "abbr" || name == "acronym" || name == "address" || name == "b" || name == "bdo" || + name == "big" || name == "cite" || name == "code" || + name == "del" || name == "dfn" || name == "dir" || + name == "em" || name == "fieldset" || name == "font" || name == "i" || name == "iframe" || + name == "ins" || name == "kbd" || name == "label" || name == "legend" || name == "menu" || + name == "noframes" || name == "pre" || name == "s" || name == "samp" || + name == "small" || name == "span" || name == "strike" || name == "strong" || name == "sub" || + name == "sup" || name == "tt" || name == "u" || name == "var" || name == "a" || + name == "blockquote" || + name == "em" || name == "form" || name == "ins" || + name == "q" || name == "tt" ) + { + props->setCHCursorFocus(kNodeAttrs::inlineNode); + props->setCCEnter(true); + props->setCBModified(true); + props->setCBDeleted(true); + } + else if(name == "center" || name == "li" || name == "h1" || name == "h2" || name == "h3" || + name == "h4" || name == "h5" || name == "h6" || name == "div" || name == "dd" || + name == "dt" || name == "p") + { + props->setCHCursorFocus(kNodeAttrs::blockNode); + props->setCCEnter(true); + props->setCBModified(true); + props->setCBDeleted(true); + } + else if(name == "applet" || name == "button" || name == "img" || name == "map" || name == "object" || + name == "hr" || name == "input" || name == "select" || name == "table" || name == "textarea" || + name == "br" || name == "dl" || name == "ul" || name == "ol") + { + props->setCHCursorFocus(kNodeAttrs::singleNodeAndItself); + props->setCCEnter(false); + props->setCBModified(true); + props->setCBDeleted(true); + } + else if(name == "basefont" || name == "location" || name == "fieldset" || name == "noscript" || + name == "script") + { + props->setCHCursorFocus(kNodeAttrs::no); + props->setCCEnter(false); + props->setCBModified(true); + props->setCBDeleted(true); + } + else if(name == "caption" || name == "frame" || name == "frameset" || name == "isindex" || + name == "optgroup" || name == "param" || name == "title" || name == "area" || name == "base" || + name == "body" || name == "col" || name == "colgroup" || name == "head" || name == "html" || + name == "link" || name == "meta" || name == "option" || name == "style" || name == "tbody" || + name == "td" || name == "tfoot" || name == "th" || name == "thead" || name == "tr") + { + props->setCHCursorFocus(kNodeAttrs::no); + props->setCCEnter(false); + props->setCBModified(false); + props->setCBDeleted(false); + } + else + { + kdDebug(25001)<< "KafkaDocument::connectDomNodeToQuantaNode () - " << + "No QTag found! Setting default parameters..." << endl; + props->setCHCursorFocus(kNodeAttrs::no); + props->setCCEnter(false); + props->setCBModified(false); + props->setCBDeleted(false); + } + +#ifdef HEAVY_DEBUG + kdDebug(25001)<< "KafkaDocument::connectDomNodeToQuantaNode() - tag name :" << + name << " canBeDeleted:" << props->cbDel() << " canBeModified:" << + props->cbMod() << " canHaveCursorFocus:" << props->chCurFoc() << + " cursorCanEnter:" << props->ccanEnter() << endl; +#endif + props->setNode(node); + props->setDomNode(domNode); + domNodeProps.insert(domNode.handle(), props); + + return props; +} + +void KafkaDocument::disconnectDomNodeFromQuantaNode(DOM::Node _domNode) +{ + if(_domNode.isNull()) + return; + domNodeProps.remove(_domNode.handle()); +} + +void KafkaDocument::disconnectAllDomNodes() +{ + domNodeProps.clear(); +} + +void KafkaDocument::setCursorAndSelection(NodeSelectionInd *nodeSelection) +{ + bool cursorAtSelectionStart; + DOM::Node startDomNode, endDomNode, foo; + Node *startNode, *endNode; + long startOffset, endOffset; + + cursorAtSelectionStart = nodeSelection->cursorAtSelectionStart(); + startNode = kafkaCommon::getNodeFromLocation(nodeSelection->cursorNode()); + endNode = kafkaCommon::getNodeFromLocation(nodeSelection->cursorNodeEndSel()); + + if(startNode && startNode->rootNode()) + startDomNode = *(startNode->rootNode()); + if(endNode && endNode->rootNode()) + endDomNode = *(endNode->rootNode()); + translateNodeIntoKafkaCursorPosition(startNode, nodeSelection->cursorOffset(), foo, startOffset); + translateNodeIntoKafkaCursorPosition(endNode, nodeSelection->cursorOffsetEndSel(), foo, endOffset); + + + if(cursorAtSelectionStart && !startDomNode.isNull()) + { + m_kafkaPart->setCurrentNode(startDomNode, startOffset); + } + else if(!cursorAtSelectionStart && !endDomNode.isNull()) + { + m_kafkaPart->setCurrentNode(endDomNode, endOffset); + } + + if(!startDomNode.isNull() && !endDomNode.isNull()) + m_kafkaPart->setSelection(DOM::Range(startDomNode, (long)startOffset, endDomNode, (long)endOffset)); +} + +void KafkaDocument::setCursor(Node* cursorNode, int cursorOffset) +{ + DOM::Node domNode; + long longDomNodeOffset; + translateNodeIntoKafkaCursorPosition(cursorNode, cursorOffset, domNode, longDomNodeOffset); + if (!domNode.isNull() && domNode.nodeType() != DOM::Node::TEXT_NODE && + !domNode.firstChild().isNull() && domNode.firstChild().nodeType() == DOM::Node::TEXT_NODE) + domNode = domNode.firstChild(); + if (!domNode.isNull()) + m_kafkaPart->setCurrentNode(domNode, (int)longDomNodeOffset); +} + +bool KafkaDocument::buildKafkaNodeFromNode(Node *node, bool insertNode) +{ +#ifdef LIGHT_DEBUG + if(node) + kdDebug(25001)<< "KafkaDocument::buildKafkaNodeFromNode() " << endl; +#endif + DOM::Node newNode, newNode2, attr, nextNode, parentNode, *ptDomNode; + bool removeLeftWhitespaces, removeRightWhitespaces; + QString str, nodeValue; + Node *n, *parent; + int i; + +// Don't create DOM::Nodes from Quanta empty nodes outside the body or inside other not allowed element, or KHTML +// will give us problems. + bool canInsertEmptyNode = false; + if(node->tag->type == Tag::Empty) + { + if(!m_currentDoc->defaultDTD()->name.contains("HTML", false)) + canInsertEmptyNode = true; + else + canInsertEmptyNode = kafkaCommon::hasParent(node, "body"); + + Node* parent_node = node->parent; + QTag* parent_node_description_tag = QuantaCommon::tagFromDTD(parent_node); + if(parent_node_description_tag && !parent_node_description_tag->isChild(node, false, true)) + canInsertEmptyNode = false; + } + + if(node->tag->type == Tag::XmlTag || + ((node->tag->type == Tag::Text || (node->tag->type == Tag::Empty && canInsertEmptyNode)) && !node->insideSpecial)) + { + str = node->tag->name.lower(); + + //The basics DOM::Nodes HTML, HEAD and BODY are loaded anyway, but we must now + // link the real HTML,... to their Nodes. + //A basic Common tree is !doctype<-html<-(head, body) + if(!node->parent) + {//FIXME:html, head and body are HTML-specific tag, for others DTDs it might result to some pbs. + if(str == "html") + { + if(!html.isNull())//delete the empty Node + disconnectDomNodeFromQuantaNode(html); + newNode = html; + insertNode = false; + } + else if(str == "body") + { + if(!body.isNull()) + disconnectDomNodeFromQuantaNode(body); + newNode = body; + insertNode = false; + } + else if(str == "head") + { + if(!head.isNull()) + disconnectDomNodeFromQuantaNode(head); + newNode = head; + insertNode = false; + } + else + { + if(node->tag->type == Tag::Text || node->tag->type == Tag::Empty) + { + newNode = kafkaCommon::createTextDomNode("", m_kafkaPart->document()); + } + else + { + newNode = kafkaCommon::createDomNode(node, m_kafkaPart->document()); + } + } + } + else if(str == "html" && (!node->parent || (node->parent && !node->parent->parent))) + { + if(!html.isNull())//delete the empty Node + disconnectDomNodeFromQuantaNode(html); + newNode = html; + insertNode = false; + } + else if(str == "body" && ((node->parent && !node->parent->parent) || (node->parent && + node->parent->parent && !node->parent->parent->parent))) + { + if(!body.isNull()) + disconnectDomNodeFromQuantaNode(body); + newNode = body; + insertNode = false; + } + else if(str == "head" && ((node->parent && !node->parent->parent) || (node->parent && + node->parent->parent && !node->parent->parent->parent))) + { + if(!head.isNull()) + disconnectDomNodeFromQuantaNode(head); + newNode = head; + insertNode = false; + } + /** else if(node->parent->tag->str == "html")*/ + else + { + if(node->tag->type == Tag::Text || node->tag->type == Tag::Empty) + { + newNode = kafkaCommon::createTextDomNode("", m_kafkaPart->document()); + } + else + { + newNode = kafkaCommon::createDomNode(node->tag->name, m_currentDoc->defaultDTD(), + m_kafkaPart->document()); + } + } + + if(newNode.isNull()) + { +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::buildKafkaNodeFromNode() - ERROR null newNode" << endl; +#endif + return false; + } + + connectDomNodeToQuantaNode(newNode, node); + if(node->tag->type == Tag::Text || node->tag->type == Tag::Empty) + { + //Now we get if the whitespaces at the left and right are kept or not. + //Left whitespaces are removed if: + //- It is the first child of a BLOCK + //- Previous Node(skipping inlines) is a text with spaces at the end + //Right whitespaces are removed if: + //- It is the last child of a BLOCK + removeLeftWhitespaces = false; + n = node; + parent = node->parent; + while(parent && parent->SFirstChild() == n) + { + if(!kafkaCommon::isInline(parent->tag->name)) + { + removeLeftWhitespaces = true; + break; + } + n = parent; + parent = parent->parent; + } + if(!removeLeftWhitespaces) + { + n = node; + n = kafkaCommon::getPrevNodeNE(n); + while(n && (n->tag->type == Tag::XmlTagEnd || + (n->tag->type == Tag::XmlTag && kafkaCommon::isInline(n->tag->name) && + !n->tag->single))) + n = kafkaCommon::getPrevNodeNE(n); + if(n && n->tag->type == Tag::Text) + { + nodeValue = n->tag->tagStr(); + if(nodeValue.length() > 0 && nodeValue[nodeValue.length() - 1].isSpace()) + removeLeftWhitespaces = true; + } + + } + + removeRightWhitespaces = false; + n = node; + parent = node->parent; + while(parent && parent->SLastChild() == n) + { + if(!kafkaCommon::isInline(parent->tag->name)) + { + removeRightWhitespaces = true; + break; + } + n = parent; + parent = parent->parent; + } + + nodeValue = node->tag->tagStr(); + nodeValue = getDecodedText(nodeValue, !kafkaCommon::hasParent(node, "pre"), + removeLeftWhitespaces, removeRightWhitespaces); + newNode.setNodeValue(nodeValue); + } + + for(i = 0; i < node->tag->attrCount(); i++) + { + attr = kafkaCommon::createDomNodeAttribute(node, node->tag->attribute(i), + m_kafkaPart->document()); + if(!attr.isNull()) + { + //TODO: create a createAttr function and add this (setNodeValue sometimes + //don't like null QString) + if(!node->tag->attributeValue(i).isNull()) + attr.setNodeValue(node->tag->attributeValue(i)); + kafkaCommon::insertDomNodeAttribute(newNode, attr); + } + } + + if(node->next && node->next->tag && node->next->tag->name == + ("/" + node->tag->name)) + { + //DEPRECATED, NO USE TO CHANGE THE above check + node->_closingNode = node->next; + } + + if(insertNode) + { + ptDomNode = new DOM::Node(newNode); + node->setRootNode(ptDomNode); + n = node; + while(n->next) + { + n = n->next; + if(n->rootNode()) + { + nextNode = *n->rootNode(); + break; + } + } + if(node->parent && node->parent->leafNode()) + parentNode = *node->parent->leafNode(); + else if(node->parent && !node->parent->leafNode()) + { + //the parent tag was invalid and khtml refuse to insert it + //so impossible to inser the current node + disconnectDomNodeFromQuantaNode(newNode); + if(node->rootNode()) + delete node->rootNode(); + node->setRootNode(0L); + return false; + } + else + parentNode = body; + + //Set the visual enhancements. + ptDomNode = new DOM::Node(newNode); + node->setLeafNode(ptDomNode); + mainEnhancer->enhanceNode(node, parentNode, nextNode); + + QTag* qTag = QuantaCommon::tagFromDTD(getCurrentDoc()->defaultDTD(), + parentNode.nodeName().string()); + + if(qTag && qTag->isChild(node, false)) + { + + if(nextNode.isNull()) + { + if(!kafkaCommon::insertDomNode(newNode, parentNode)) + { + disconnectDomNodeFromQuantaNode(newNode); + if(node->rootNode()) + delete node->rootNode(); + node->setRootNode(0L); + return false; + } + } + else + { + if(!kafkaCommon::insertDomNode(newNode, parentNode, nextNode)) + { + disconnectDomNodeFromQuantaNode(newNode); + if(node->rootNode()) + delete node->rootNode(); + node->setRootNode(0L); + return false; + } + } + } + } + else + { + ptDomNode = new DOM::Node(newNode); + node->setRootNode(ptDomNode); + ptDomNode = new DOM::Node(newNode); + node->setLeafNode(ptDomNode); + } + } + else + { + if(node->parent && node->parent->leafNode()) + parentNode = *node->parent->leafNode(); + else + parentNode = body; + n = node; + while(n->next) + { + n = n->next; + if(n->rootNode()) + { + nextNode = *n->rootNode(); + break; + } + } + mainEnhancer->enhanceNode(node, parentNode, nextNode); + } + return true; +} + +void KafkaDocument::buildNodeFromKafkaNode(Node *node, DOM::Node domNode) +{ +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "void KafkaDocument::buildNodeFromKafkaNode() - Node* DOM::Node" << endl; +#endif + long i; + + if(!node) return; + + node->tag->setCleanStrBuilt(false); + node->tag->setIndentationDone(false); + if(domNode.nodeType() == DOM::Node::TEXT_NODE) + { + QString text = domNode.nodeValue().string(); + text.replace("<", "<"); + text.replace(">", ">"); + node->tag->setStr(text); + } + else + { + while(node->tag->attrCount()) + node->tag->deleteAttribute(0); + for(i = 0; (unsigned)i < domNode.attributes().length(); i++) + { + TagAttr attr; + attr.name = domNode.attributes().item(i).nodeName().string(); + attr.value = domNode.attributes().item(i).nodeValue().string(); + attr.quoted = true; + node->tag->addAttribute(attr); + } + } +} + +Node * KafkaDocument::buildNodeFromKafkaNode(DOM::Node domNode, Node *nodeParent, + Node *beginNode, int beginOffset, Node */*endNode*/, int endOffset, NodeModifsSet *modifs) +{ +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "Node* KafkaDocument::buildNodeFromKafkaNode() - DOM::Node 2xNode* int: " << + beginOffset << " Node* int: " << endOffset << " NodeModifsSet " << endl; +#else + Q_UNUSED(beginOffset); + Q_UNUSED(endOffset); +#endif + DOM::Node *ptDomNode; + Node *node; + + if(domNode.isNull()) + { + kdDebug(25001)<< "Node* KafkaDocument::buildNodeFromKafkaNode(DOM::Node, 2xNode*)" << + " *ERROR* - empty _domNode"<< endl; + } + + //nodeParent can be the false body node which is not in the tree. + if(nodeParent->tag->notInTree()) + nodeParent = 0L; + + /**_node = new Node(_nodeParent);*/ + if(domNode.nodeType() == DOM::Node::TEXT_NODE) + { + node = kafkaCommon::createNode("#text", "",Tag::Text, m_currentDoc); + } + else + { + node = kafkaCommon::createNode(domNode.nodeName().string(), "", + Tag::XmlTag, m_currentDoc); + } + buildNodeFromKafkaNode(node, domNode); + + connectDomNodeToQuantaNode(domNode, node); + + ptDomNode = new DOM::Node(domNode); + node->setRootNode(ptDomNode); + ptDomNode = new DOM::Node(domNode); + node->setLeafNode(ptDomNode); + + kafkaCommon::insertNode(node, nodeParent, beginNode, beginNode, modifs, false); + + return node; +} + +QString KafkaDocument::getDecodedChar(const QString &encodedChar) +{ + QMap::Iterator it = encodedChars.find(encodedChar); + if(it == encodedChars.end()) + { + //try this + return KGlobal::charsets()->resolveEntities(encodedChar);; + } + return it.data(); +} + +QString KafkaDocument::getDecodedText(const QString &a_encodedText, bool translateWhiteSpacesAndLineBreaks, + bool removeLeftWhitespaces, bool removeRightWhitespaces) +{ + QString encodedText = a_encodedText; + if (encodedText.isEmpty()) + encodedText = " "; + QString decodedChar; + int i, j; +#ifdef LIGHT_DEBUG + QString oldEncodedText = encodedText; +#endif + + i = -1; + while((unsigned)++i < encodedText.length() && translateWhiteSpacesAndLineBreaks) + { + if(encodedText[i].isSpace()) + { + encodedText.remove(i, 1); + encodedText.insert(i, " "); + while((unsigned)++i < encodedText.length() && encodedText[i].isSpace()) + { + encodedText.remove(i, 1); + i--; + } + } + } + i = -1; + while((unsigned)++i < encodedText.length()) + { + if(QString(encodedText[i]) == "&") + { + j = i; + while((unsigned)++i < encodedText.length() && + QString(encodedText[i]) != ";") + {} + decodedChar = getDecodedChar(encodedText.mid(j, i - j + 1)); + encodedText.remove(j, i - j + 1); + //TODO:set a special behavior if the encoded symbol doesn't exist + encodedText.insert(j, decodedChar); + i = j + decodedChar.length() - 1; + } + } + + if(translateWhiteSpacesAndLineBreaks && removeLeftWhitespaces && encodedText.length() > 0 && + encodedText[0].isSpace()) + encodedText.remove(0, 1); + + if(translateWhiteSpacesAndLineBreaks && removeRightWhitespaces && encodedText.length() > 0 && + encodedText[encodedText.length() - 1].isSpace()) + encodedText.remove(encodedText.length() - 1, 1); + +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::getDecodedText() - \"" << oldEncodedText << "\" -> \"" << + encodedText << "\"" << endl; +#endif + return encodedText; + //return KGlobal::charsets()->resolveEntities(encodedText); =>nice but not sufficient +} + +QString KafkaDocument::getEncodedChar(const QString &decodedChar, const QString &previousDecodedChar) +{ + if(decodedChar[0].isSpace() && !previousDecodedChar[0].isSpace()) + return " "; + else if(decodedChar[0].isSpace()) + //FIXME:for an unknown reason, by default it return ¿ instead of   + return " "; + QMap::Iterator it = decodedChars.find(decodedChar); + if(it == decodedChars.end()) + return decodedChar; + + return it.data(); + } + +QString KafkaDocument::getEncodedText(const QString &a_decodedText, int bLine, int bCol, int &eLine, int &eCol, + bool translateWhiteSpaces) +{ + QString decodedText = a_decodedText; + QString Encodedchar; + QString decodedChar, previousDecodedChar; +#ifdef LIGHT_DEBUG + QString oldDecodedText = decodedText; +#endif + int i; +#ifdef LIGHT_DEBUG + int _bLine = bLine, _bCol = bCol; +#endif + + i = -1; + while((unsigned)++i < decodedText.length()) + { + previousDecodedChar = decodedChar; + decodedChar = QString(decodedText[i]); + + if(translateWhiteSpaces || !decodedText[i].isSpace()) + Encodedchar = getEncodedChar(QString(decodedText[i]), + (i>=1)?previousDecodedChar:QString("")); + else + Encodedchar = decodedChar; + bCol += Encodedchar.length(); + + decodedText.remove(i,1); + decodedText.insert(i, Encodedchar); + i += Encodedchar.length() - 1; + } + eLine = bLine; + eCol = bCol - 1; +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::getEncodedText() - " << oldDecodedText << " -> " << decodedText << + " - " << _bLine << ":" << _bCol << " - " << eLine << ":" << eCol << endl; +#endif + return decodedText; +} + +QString KafkaDocument::getEncodedText(const QString& decodedText) +{ + int a = 0, b = 0, c, d; + return getEncodedText(decodedText, a, b, c, d); +} + +QString KafkaDocument::generateCodeFromNode(Node *node, int bLine, int bCol, int &eLine, int &eCol, bool encodeText) +{ + QString text, _char; + Node *openingNode; + int bLineAttr, bColAttr; + int j = 0; + bool hasPreParent; + + if(!node) return ""; + + if(node->tag->type == Tag::XmlTag) + { + text = "<" + QuantaCommon::tagCase(node->tag->name); + bCol += node->tag->name.length() + 1; + for(j = 0; j < node->tag->attrCount(); j++) + { + text += " "; + bCol++; + bLineAttr = bLine; + bColAttr = bCol; + text += node->tag->attribute(j); + bCol += node->tag->attribute(j).length(); + + //doctype have only attrNames. + if(node->tag->name.lower() != "!doctype" && !node->tag->getAttribute(j).special) + { + text += "="; + bCol++; + if(node->tag->isQuotedAttribute(j)) + { + text += qConfig.attrValueQuotation; + bCol++; + } + node->tag->setAttributePosition(j, bLineAttr, bColAttr, bLine, bCol); + text += node->tag->attributeValue(j); + bCol += node->tag->attributeValue(j).length(); + if(node->tag->isQuotedAttribute(j)) + { + text += qConfig.attrValueQuotation; + bCol++; + } + } + else + node->tag->setAttributePosition(j, bLineAttr, bColAttr, -2, -2); + } + + //only single Nodes except !doctype and ?xml nodes in XML tag style get the "/" + if ( node->tag->dtd()->singleTagStyle == "xml" && + (node->tag->single || (!qConfig.closeOptionalTags && + QuantaCommon::isOptionalTag(node->tag->dtd()->name, node->tag->name))) + && node->tag->name.lower() != "?xml" && node->tag->name.lower() != "!doctype") + { + text += " /"; + bCol += 2; + } + //?xml nodes get a "?" + if(node->tag->name.lower() == "?xml") + { + text += "?"; + bCol++; + } + + text += ">"; + eCol = bCol; + eLine = bLine; + } + else if(node->tag->type == Tag::XmlTagEnd) + { + openingNode = node->getOpeningNode(); + if(openingNode && openingNode->tag->type == Tag::ScriptTag) + { + if(openingNode->tag->name.contains("XML PI", false) || + openingNode->tag->name.contains("PHP", false)) + text = "?>"; + else if(openingNode->tag->name.contains("DTD", false)) + text = ">"; + else + text = ">"; + } + else + { + if (node->tag->tagStr() == "-->") + text = "-->"; + else + text = "<" + QuantaCommon::tagCase(node->tag->name) + ">"; + } + bCol += text.length(); + eCol = bCol - 1; + eLine = bLine; + } + else if(node->tag->type == Tag::Text) + { + hasPreParent = kafkaCommon::hasParent(node, "pre"); + if(encodeText) + text = getEncodedText(node->tag->tagStr(), bLine, bCol, eLine, eCol, + !hasPreParent); + /** Can't use KGlobal::charsets()->toEntity() : + * It translate all chars into entities! */ + else if(!hasPreParent) + text = node->tag->tagStr().replace(QRegExp("\\s+"), " "); + else + text = node->tag->tagStr(); + } + else if(node->tag->type == Tag::ScriptTag) + { + //WARNING : HTML SPECIFIC + if(node->tag->name.contains("style", false)) + { + text = "<" + QuantaCommon::tagCase("style") + ">"; + } + else if(node->tag->name.contains("DTD", false)) + { + text = "tag->name.contains("XML PI", false)) + { + text = "tag->name.contains("PHP", false)) + { + text = "tag->tagStr() + text = node->tag->tagStr(); + kafkaCommon::getEndPosition(text, bLine, bCol, eLine, eCol); + } + return text; +} + +void KafkaDocument::translateQuantaIntoKafkaCursorPosition(uint curLine, uint curCol, DOM::Node &domNode, long &offset) +{ + Node *node; + int bCol, bLine, eCol, eLine, col, line; + QString curChar, decodedChar, currentLine; + bool lookForEntity, lookForSpaces, found; + + node = baseNode; + while(node) + { + node->tag->beginPos(bLine, bCol); + node->tag->endPos(eLine, eCol); + if((bLine < (signed)curLine || (bLine == (signed)curLine && bCol <= (signed)curCol)) && + (eLine > (signed)curLine || (eLine == (signed)curLine && eCol >= (signed)curCol))) + { + if(bLine == (signed)curLine && bCol == (signed)curCol && node->tag->type != Tag::Text && + node->previousSibling() && node->previousSibling()->tag->type == Tag::Text) + { + //if we are at the end of a text which is recognized as the beginning of the next tag + node = node->previousSibling(); + //we can go directly to the last offset + if(!node->rootNode()) + { + offset = 0; + kdDebug(25001)<< "KafkaDocument::getKafkaCursorPosition() - ERROR DOM::Node not found" + << endl; + return; + } + domNode = *node->rootNode(); + offset = domNode.nodeValue().string().length(); +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::getKafkaCursorPosition() - " << + domNode.nodeName().string() << ":" << offset << endl; +#endif + return; + } + col = bCol; + line = bLine; + break; + } + node = node->nextSibling(); + + } + if(!node) + { + kdDebug(25001)<< "KafkaDocument::getKafkaCursorPosition() - ERROR node not found" << endl; + return; + } +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::getKafkaCursorPosition() - node :" << node->tag->name << ": type:" << + node->tag->type << ": pos " << bLine << ":" << bCol << " - " << eLine << ":" << eCol << endl; +#endif + + offset = 0; + if(node->rootNode() && node->rootNode()->nodeType() == DOM::Node::TEXT_NODE) + { + domNode = *node->rootNode(); + currentLine = m_currentDoc->editIf->textLine(line); + if(line < eLine) + currentLine += " ";//remplace the \n + while(line < (signed)curLine || (col < (signed)curCol && line == (signed)curLine)) + { + lookForEntity = false; + lookForSpaces = false; + curChar = currentLine.mid(col, 1); + if(curChar == "&") + lookForEntity = true; + else if(curChar[0].isSpace()) + lookForSpaces = true; + found = false; + while(!found) + { + if((lookForEntity && curChar == ";") || + !(lookForSpaces || lookForEntity)) + found = true; + else if(lookForSpaces && !curChar[0].isSpace())//curChar != " ") + break; + if((col + 1) >= (signed)currentLine.length()) + { + line++; + col = 0; + currentLine = m_currentDoc->editIf->textLine(line); + if(line < eLine) + currentLine += " ";//remplace the \n + } + else col++; + curChar = currentLine.mid(col, 1); + } +#ifdef HEAVY_DEBUG + kdDebug(25001)<< "endpos at " << line << ":" << col << endl; +#endif + offset++; + } + } + else if(node->rootNode()) + offset = 0;//shoud we select? + else + m_kafkaPart->putCursorAtFirstAvailableLocation();//set the cursor in the first text +#ifdef LIGHT_DEBUG + if(!domNode.isNull()) + kdDebug(25001)<< "KafkaDocument::getKafkaCursorPosition() - " << domNode.nodeName().string() << + ":" << offset << endl; + else + kdDebug(25001)<< "KafkaDocument::getKafkaCursorPosition() - NULL domNode" << endl; +#endif +} + +void KafkaDocument::translateQuantaIntoNodeCursorPosition(uint line, uint col, Node **node, long &offset) +{ + int curCol, curLine, beginCol, beginLine; + QString currentLine; + + *node = parser->nodeAt(line, col, false); + + offset = 0; + if(!*node) + return; + + if((*node)->tag->cleanStrBuilt() && (*node)->tag->indentationDone()) + { + (*node)->tag->beginPos(beginLine, beginCol); + curLine = beginLine; + curCol = beginCol; + while(curLine < (signed)line) + { + currentLine = ViewManager::ref()->activeDocument()->editIf->textLine(curLine); + if(curLine == beginLine) + offset += (signed)currentLine.length() - beginCol; + else + offset += (signed)currentLine.length(); + offset++; + curLine++; + } + if(beginLine != (signed)line) + offset += col; + else + offset += col - beginCol; + } + else + { + //TODO + } +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::translateQuantaIntoNodeCursorPosition() - " << *node << + ":" << offset << endl; +#endif +} + +void KafkaDocument::translateKafkaIntoNodeCursorPosition(DOM::Node domNode, long domNodeOffset, Node **node, long &offset) +{ + QString decodedText, encodedChar, encodedText, currentChar; + QChar curChar, oldChar; + long currentOffset; + bool waitForSpace = false, found = false; + int curNodeOffset, bLine = 0, bCol = 0, eLine, eCol; + + offset = 0; + (*node) = 0L; + + if(domNode.isNull()) + { +#ifdef HEAVY_DEBUG + kdDebug(25001)<< "KafkaDocument::translateKafkaIntoNodeCursorPosition()" << + " - DOM::Node not found!" << endl; +#endif + return ; + } + + //get the corresponding Node* + (*node) = getNode(domNode); + if(!(*node)) + { +#ifdef HEAVY_DEBUG + kdDebug(25001)<< "KafkaDocument::translateKafkaIntoNodeCursorPosition()" << + " - Node not found!" << endl; +#endif + return ; + } + if(!(*node)->tag) + { +#ifdef HEAVY_DEBUG + kdDebug(25001)<< "KafkaDocument::translateKafkaIntoNodeCursorPosition()" << + " - Node tag not found!" << endl; +#endif + (*node) = 0L; + return ; + } + + //If this node is selected (-1 means selected) then return "node selected" ;-) + if(domNodeOffset == -1) + { + return ; + } + + if(!(*node)->tag->cleanStrBuilt()) + { + //We NEED to have the up-to-date string in node. + (*node)->tag->setStr(generateCodeFromNode((*node), bLine, bCol, eLine, eCol)); + //FIXME we shouldn't set it but if we don't the text will be re-encoded! + (*node)->tag->setCleanStrBuilt(true); + } + + decodedText = domNode.nodeValue().string(); + encodedText = (*node)->tag->tagStr(); + currentOffset = domNodeOffset; + curNodeOffset = 0; + +#ifdef HEAVY_DEBUG + kdDebug(25001)<< "KafkaDocument::translateKafkaIntoNodeCursorPosition() - decodedText:"<< + decodedText << ": encoded text:" << encodedText << ":" << endl; +#endif + + if((*node)->tag->type == Tag::Text) + { + while(currentOffset > 0) + { + curChar = decodedText.at(domNodeOffset - currentOffset); +#ifdef HEAVY_DEBUG + //kdDebug(24000)<< "CurChar:" << QString(curChar) << ": oldChar:" << + // QString(oldChar) << endl; +#endif + encodedChar = getEncodedChar(QString(curChar), QString(oldChar)); + if(encodedChar == " ") + encodedChar = " "; + found = false; + waitForSpace = false; + while(!found) + { +#ifdef HEAVY_DEBUG + //kdDebug(25001)<< "look 4 :" << encodedChar << ": found :" << + // encodedText.mid(curNodeOffset, encodedChar.length()) << endl; +#endif + if(encodedChar != " " && encodedChar == encodedText.mid(curNodeOffset, + encodedChar.length())) + found = true; + else if(encodedChar == " " && encodedText.mid(curNodeOffset, 1).at(0).isSpace()) + waitForSpace = true; + else if(waitForSpace) + break;//no more spaces + else if(encodedChar == " " && encodedText.mid(curNodeOffset, 6) == " ") + { + encodedChar = " "; + found = true; + } + + if(curNodeOffset > (signed)encodedText.length() || encodedChar.isEmpty()) + { + //The good nodeOffset was not found. Returns a default value. + //encodedChar.isEmpty() -->prevent an infinite loop + curNodeOffset = 0; + break; + } + else + curNodeOffset += encodedChar.length(); + } + oldChar = curChar; + currentOffset--; + } + } + +#ifdef LIGHT_DEBUG + kdDebug(25001)<<"KafkaDocument::translateKafkaIntoNodeCursorPosition() - " << + curNodeOffset << endl; +#endif + offset = curNodeOffset; +} + +void KafkaDocument::translateKafkaIntoQuantaCursorPosition(DOM::Node _currentDomNode, int offset, int &line, int &col) +{ + Node *_currentNode, *closingNode, *node; + kNodeAttrs *attrs; + QString decodedText, encodedChar, currentLine, currentChar; + QChar curChar, oldChar; + int currentOffset; + int curLine, curCol, endLine, endCol; + int i; + bool waitForSpace = false, found = false; + bool tagLeft = false, tagRight = false, tagMiddle = false; + bool specialBehavior = false; + + //m_kafkaPart->getCurrentNode(_currentDomNode, offset); + currentOffset = offset; + + if(_currentDomNode.isNull()) + { + kdDebug(25001)<< "KafkaDocument::getQuantaCursorPosition() - DOM::Node not found!" << endl; + line = 0; + col = 0; + return; + } + + attrs = getAttrs(_currentDomNode); + if(!attrs) + { + kdDebug(25001)<< "KafkaDocument::getQuantaCursorPosition() - Attrs not found!" << endl; + line = 0; + col = 0; + return; + } + + //If the current DOM::Node has a special behavior (cf nodeproperties.h), get the nearest + //node which can get the focus! + if(attrs->specialBehavior() != kNodeAttrs::none) + { + specialBehavior = true; + if(attrs->specialBehavior() == kNodeAttrs::emptyTextSurroundingBlockElementAtTheLeft) + { + _currentDomNode = _currentDomNode.nextSibling(); + //tagRight means to put the cursor at the left of the tag so that the cursor + //looks at its right place (otherwise as there is no Node for this DOM::Node, + //the cursor won't go anywhere!) + tagLeft = true; + } + else if(attrs->specialBehavior() == kNodeAttrs::emptyTextSurroundingBlockElementAtTheRight) + { + _currentDomNode = _currentDomNode.previousSibling(); + tagRight = true; + } + else if(attrs->specialBehavior() == kNodeAttrs::emptyTextAsChildOfAChildlessElement) + { + _currentDomNode = _currentDomNode.parentNode(); + tagMiddle = true; + } + attrs = getAttrs(_currentDomNode); + if(!attrs) + { + kdDebug(25001)<< "KafkaDocument::getQuantaCursorPosition() - Attrs not found!" << endl; + line = 0; + col = 0; + return; + } + } + + _currentNode = attrs->getNode(); + if(!_currentNode /* && attrs->specialBehavior() == kNodeAttrs::none -- Andras: what happens if _currentNode is null, but this part of the if is not true?*/) + { + kdDebug(25001)<< "KafkaDocument::getQuantaCursorPosition() - Node not found!" << endl; + line = 0; + col = 0; + return; + } + + decodedText = _currentDomNode.nodeValue().string(); + _currentNode->tag->beginPos(curLine, curCol); + _currentNode->tag->endPos(endLine, endCol); + currentLine = m_currentDoc->editIf->textLine(curLine); + if(curLine < endLine) + currentLine += " ";//remplace the \n + + if(offset == -1) + { + if (m_currentDoc->selectionIf) + m_currentDoc->selectionIf->setSelection(curLine, curCol, endLine, endCol + 1); + line = endLine; + col = endCol + 1; + return; + } +#ifdef HEAVY_DEBUG +// kdDebug(25001)<< "KafkaDocument::getQuantaCursorPosition() - decodedText:"<< decodedText << ":" << endl; +#endif + if(_currentNode->tag->type == Tag::Text) + { + while(currentOffset > 0) + { + curChar = decodedText[offset - currentOffset]; +#ifdef HEAVY_DEBUG +// kdDebug(24000)<< "CurChar:" << QString(curChar) << ": oldChar:" << QString(oldChar) << endl; +#endif + encodedChar = getEncodedChar(QString(curChar), QString(oldChar)); + if(encodedChar == " ") + encodedChar = " "; + found = false; + waitForSpace = false; + while(!found) + { +#ifdef HEAVY_DEBUG +// kdDebug(25001)<< "look 4 :" << encodedChar << ": found :" << +// currentLine.mid(curCol, encodedChar.length()) << endl; +// kdDebug(25001)<< "pos " << curLine << ":" << curCol << endl; +// kdDebug(25001)<< "endPos " << endLine << ":" << endCol << endl; +#endif + if(encodedChar != " " && encodedChar == currentLine.mid(curCol, encodedChar.length())) + found = true; + else if(encodedChar == " " && currentLine.mid(curCol, 1).at(0).isSpace()) + waitForSpace = true; + else if(waitForSpace) + break;//no more spaces + else if(encodedChar == " " && currentLine.mid(curCol, 6) == " ") + { + encodedChar = " "; + found = true; + } + if((curCol > endCol && curLine == endLine) || curLine > endLine || + encodedChar.length() == 0) + { + //encodedChar.length() == 0 =>prevent infinite loop + curLine = endLine; + curCol = endCol + 1; + currentOffset = 0; + break; + } + else if((curCol + encodedChar.length()) >= currentLine.length()) + { + ++curLine; + curCol = 0; + currentLine = m_currentDoc->editIf->textLine(curLine); + if(curLine < endLine) + currentLine += " ";//remplace the \n + } + else + { + curCol += encodedChar.length(); + } + } + oldChar = curChar; + --currentOffset; + } + } + else if(_currentNode->tag->type == Tag::XmlTag) + { + //If we are in the special case + if(specialBehavior) + { + if(tagLeft) + _currentNode->tag->beginPos(curLine, curCol); + else if(tagRight) + { + closingNode = _currentNode->getClosingNode(); + if(closingNode) + closingNode->tag->endPos(curLine, curCol); + else + _currentNode->tag->endPos(curLine, curCol); + ++curCol; + } + else + { + _currentNode->tag->endPos(curLine, curCol); + ++curCol; + } + } + else + { + if(_currentNode->tag->single) + { + //The tag is single, there shouldn't be any (tag, x) location, but the old way + //was (tag,0) for left of the tag and (tag,1) for the right of the tag) + + if(offset == 1) + { + _currentNode->tag->endPos(curLine, curCol); + curCol++; + } + else + _currentNode->tag->beginPos(curLine, curCol); + } + else + { + //The new way to define cursor position. + node = _currentNode->SFirstChild(); + i = 1; + while(i < offset && node && node->SNext()) + { + node = node->SNext(); + ++i; + } + if(!node) + node = _currentNode; + if(offset == 0) + node->tag->beginPos(curLine, curCol); + else + { + closingNode = node->getClosingNode(); + if(closingNode) + closingNode->tag->endPos(curLine, curCol); + else + node->tag->endPos(curLine, curCol); + ++curCol; + } + } + } + } + + line = curLine; + col = curCol; +#ifdef LIGHT_DEBUG + kdDebug(25001)<<"KafkaDocument::getQuantaCursorPosition() - " << line << ":" << col << endl; +#endif + return; +} + +void KafkaDocument::translateNodeIntoKafkaCursorPosition(Node *node, int offset, DOM::Node &domNode, + long &domNodeOffset) +{ + QString textNode, curChar; + int col; + bool lookForEntity, lookForSpaces, found; + + if(node && node->rootNode() && node->rootNode()->nodeType() == DOM::Node::TEXT_NODE) + { + domNodeOffset = 0; + domNode = *node->rootNode(); + textNode = node->tag->tagStr(); + col = 0; + while(col < offset) + { + lookForEntity = false; + lookForSpaces = false; + curChar = textNode.mid(col, 1); + if(curChar == "&") + lookForEntity = true; + else if(curChar[0].isSpace()) + lookForSpaces = true; + found = false; + while(!found && col < offset) + { + if((lookForEntity && curChar == ";") || + !(lookForSpaces || lookForEntity)) + found = true; + else if(lookForSpaces && !curChar[0].isSpace())//curChar != " ") + break; + col++; + curChar = textNode.mid(col, 1); + } +#ifdef HEAVY_DEBUG + //kdDebug(25001)<< "endpos at " << line << ":" << col << endl; +#endif + domNodeOffset++; + } + } + else if(node && node->rootNode()) + { + domNode = *node->rootNode(); + domNodeOffset = 0;//shoud we select? + } + else + { + domNode = DOM::Node(); + domNodeOffset = 0; + } +} + +void KafkaDocument::translateNodeIntoQuantaCursorPosition(Node *node, int offset, uint &line, uint &col) +{ + int curCol, curLine, curOffset; + + node->tag->beginPos(curLine, curCol); + line = curLine; + col = curCol; + curOffset = offset; + while(curOffset > 0) + { + if(node->tag->tagStr()[offset - curOffset] == '\n') + line++; + else + col++; + curOffset--; + } +} + +bool KafkaDocument::insertDomNode(DOM::Node node, DOM::Node parent, + DOM::Node nextSibling, DOM::Node rootNode) +{ + DOM::Node siblingNSpecial; + + //First insert the node + if(!kafkaCommon::insertDomNode(node, parent, nextSibling, rootNode)) + return false; + + //Then unEnhance and reEnhance the nearest non special nodes so that everything's fine. + siblingNSpecial = getPrevSiblingNSpecial(node); + if(!siblingNSpecial.isNull()) + { + mainEnhancer->postUnenhanceNode(siblingNSpecial); + mainEnhancer->postEnhanceNode(siblingNSpecial); + } + siblingNSpecial = getNextSiblingNSpecial(node); + if(!siblingNSpecial.isNull()) + { + mainEnhancer->postUnenhanceNode(siblingNSpecial); + mainEnhancer->postEnhanceNode(siblingNSpecial); + } + mainEnhancer->postUnenhanceNode(node.parentNode()); + mainEnhancer->postEnhanceNode(node.parentNode()); + + mainEnhancer->postEnhanceNode(node); + return true; +} + +bool KafkaDocument::removeDomNode(DOM::Node node) +{ + DOM::Node nextSiblingNSpecial, prevSiblingNSpecial, parent; + + //First remove the node + prevSiblingNSpecial = getPrevSiblingNSpecial(node); + nextSiblingNSpecial = getNextSiblingNSpecial(node); + parent = node.parentNode(); + if(!kafkaCommon::removeDomNode(node)) + return false; + + //Then unEnhance and reEnhance the nearest non special nodes so that everything's fine. + if(!prevSiblingNSpecial.isNull()) + { + mainEnhancer->postUnenhanceNode(prevSiblingNSpecial); + mainEnhancer->postEnhanceNode(prevSiblingNSpecial); + } + if(!nextSiblingNSpecial.isNull()) + { + mainEnhancer->postUnenhanceNode(nextSiblingNSpecial); + mainEnhancer->postEnhanceNode(nextSiblingNSpecial); + } + mainEnhancer->postUnenhanceNode(parent); + mainEnhancer->postEnhanceNode(parent); + + return true; +} + +DOM::Node KafkaDocument::getPrevSiblingNSpecial(DOM::Node domNode) +{ + kNodeAttrs *attrs; + + if(domNode.isNull()) + return DOM::Node(); + + domNode = domNode.previousSibling(); + while(!domNode.isNull()) + { + attrs = getAttrs(domNode); + if(!attrs) + return DOM::Node(); + if(attrs->specialBehavior() == kNodeAttrs::none) + return domNode; + domNode = domNode.previousSibling(); + } + + return DOM::Node(); +} + +DOM::Node KafkaDocument::getNextSiblingNSpecial(DOM::Node domNode) +{ + kNodeAttrs *attrs; + + if(domNode.isNull()) + return DOM::Node(); + + domNode = domNode.nextSibling(); + while(!domNode.isNull()) + { + attrs = getAttrs(domNode); + if(!attrs) + return DOM::Node(); + if(attrs->specialBehavior() == kNodeAttrs::none) + return domNode; + domNode = domNode.nextSibling(); + } + + return DOM::Node(); +} + +void KafkaDocument::readConfig(KConfig *m_config) +{ +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::readConfig()" << endl; +#endif + //for each nodeEnhancer + if(mainEnhancer) + mainEnhancer->readConfig(m_config); + //reload the document + reloadDocument(); +} + +const DTDStruct* KafkaDocument::defaultDTD() +{ + return m_currentDoc->defaultDTD(); +} + +#ifdef HEAVY_DEBUG +void KafkaDocument::coutLinkTree(Node *node, int indent) +#else +void KafkaDocument::coutLinkTree(Node *, int) +#endif +{ +#ifdef HEAVY_DEBUG + QString output, dots; + DOM::Node domNode; + Node *n = 0L; + if(!node) + kdDebug(25001)<< "kafkaDocument::coutTree() - bad node!" << endl; + + while (node) + { + dots = ""; + dots.fill('*', indent); + output = dots; + if (node->tag->type != Tag::Text) + output += node->tag->name.replace('\n'," "); + else + output+= node->tag->tagStr().replace('\n'," "); + output += " ("; + output += node->tag->type; + output += ") "; + n = 0L; + if(node->rootNode()) + { + domNode = *node->rootNode(); + n = getNode(domNode); + } + + kdDebug(25001) << output <<" (" << node << ") " << domNode.handle() << " - " << n <child) + coutLinkTree(node->child, indent + 4); + + node = node->next; + } +#endif +} + +void KafkaDocument::slotDomNodeInserted(DOM::Node domNode, bool insertChilds, NodeModifsSet* modifs) +{ +#ifdef LIGHT_DEBUG + if(!domNode.isNull()) + kdDebug(25001)<< "KafkaDocument::slotDomNodeInserted() - DOM::Node: " << + domNode.nodeName().string() << endl; + else + kdDebug(25001)<< "KafkaDocument::slotDomNodeInserted() - DOM::Node: NULL" << endl; +#endif + Node *_nodeParent = 0L, *nodeNext = 0L, *_node = 0L; + DOM::Node tmpDomNode, nextDomNode; + bool b = false; + +#ifdef LIGHT_DEBUG + QTime t; + t.start(); +#endif + + _nodeParent = getNode(domNode.parentNode()); + + if(!_nodeParent) + {//DOM::Node not found, strange... + kdDebug(25001)<< "KafkaDocument::slotDomNodeInserted() - *ERROR* the" << + " corresponding DOM::Node is not found!" << endl; + return; + } + + nextDomNode = getNextSiblingNSpecial(domNode); + if(!nextDomNode.isNull()) + { + nodeNext = getNode(nextDomNode); + if(!nodeNext) + { + kdDebug(25001)<< "KafkaDocument::slotDomNodeInserted() - *ERROR2*" << + " the corresponding DOM::Node is not found!" << endl; + return; + } + } + + _node = buildNodeFromKafkaNode(domNode, _nodeParent, nodeNext, 0, 0L, 0, modifs); + + if(insertChilds && domNode.hasChildNodes()) + { + //TODO: check if it is working + tmpDomNode = domNode.firstChild(); + while(!tmpDomNode.isNull()) + { + buildNodeFromKafkaNode(tmpDomNode, + getNode(tmpDomNode.parentNode()), 0L, 0, 0L, 0, modifs); + tmpDomNode = kafkaCommon::getNextDomNode(tmpDomNode, b, false, domNode); + } + } + +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::slotDomNodeInserted() in " << t.elapsed() << + " ms only!" << endl; +#endif +#ifdef HEAVY_DEBUG + kafkaCommon::coutTree(baseNode, 2); +#endif + +} + +void KafkaDocument::slotDomNodeModified(DOM::Node domNode, NodeModifsSet* modifs) +{ +#ifdef LIGHT_DEBUG + if(!domNode.isNull()) + kdDebug(25001)<< "KafkaDocument::slotDomNodeModified() - DOM::Node: " << + domNode.nodeName().string() << endl; + else + kdDebug(25001)<< "KafkaDocument::slotDomNodeModfied() - DOM::Node: NULL" << endl; +#endif + Node *node = 0L; + NodeModif *modif; + kNodeAttrs *props, *newProps; + DOM::Node newDomNode, parentDomNode, nextSiblingDomNode; + DOM::Node *ptDomNode; + QTag *qTag; + +#ifdef LIGHT_DEBUG + QTime t; + t.start(); +#endif + + //gets the DOM::Node's kNodeAttrs + props = domNodeProps[domNode.handle()]; + if(!props) + { + kdDebug(25001)<< "KafkaDocument::slotDomNodeModified - *ERROR " << + " missing kNodeAttrs for a DOM::Node!!!" << endl; + return; + } + + //First look if domNode has a corresponding Node. + if(props->isLinkedToNode()) + { + + //Look which Node correspond to this DOM::Node + node = props->getNode(); + + if(!node) + {//DOM::Node not found, weird... + kdDebug(25001)<< "KafkaDocument::slotDomNodeModified() - *ERROR* the" << + " corresponding DOM::Node is not found!" << endl; + return; + } + + modif = new NodeModif(); + modif->setType(NodeModif::NodeModified); + modif->setTag(new Tag(*(node->tag))); + modif->setLocation(kafkaCommon::getLocation(node)); + + buildNodeFromKafkaNode(node, domNode); + if (!modifs) + modifs = new NodeModifsSet(); + modifs->addNodeModif(modif); + } + else + { + //no corresponding Node, we are in a special case with a special behavior. + qTag = QuantaCommon::tagFromDTD(getNode(domNode.parentNode())); + if(((!domNode.parentNode().isNull() && domNode.parentNode().nodeName() == "#document") || + qTag) && ( + props->specialBehavior() == kNodeAttrs::emptyTextSurroundingBlockElementAtTheLeft || + props->specialBehavior() == kNodeAttrs::emptyTextSurroundingBlockElementAtTheRight || + props->specialBehavior() == kNodeAttrs::emptyTextAsChildOfAChildlessElement)) + { + //let's create the corresponding Text Node and the P tag only if necessary + modifs = new NodeModifsSet(); + modif = new NodeModif(); + parentDomNode = domNode.parentNode(); + nextSiblingDomNode = domNode.nextSibling(); + + if(!qTag->isChild("#text", false)) + { + newDomNode = kafkaCommon::createDomNode("p", + getNode(domNode.parentNode())->tag->dtd(), m_kafkaPart->document()); + kafkaCommon::removeDomNode(domNode); + kafkaCommon::insertDomNode(newDomNode, parentDomNode, nextSiblingDomNode); + kafkaCommon::insertDomNode(domNode, newDomNode); + + node = kafkaCommon::createNode("p", "", Tag::XmlTag, m_currentDoc); + newProps = connectDomNodeToQuantaNode(newDomNode, node); + ptDomNode = new DOM::Node(newDomNode); + node->setRootNode(ptDomNode); + ptDomNode = new DOM::Node(newDomNode); + node->setLeafNode(ptDomNode); + node = kafkaCommon::insertNode(node, getNode(parentDomNode), + getNode(nextSiblingDomNode), getNode(nextSiblingDomNode), modifs); + newProps->setNode(node); + modifs->addNodeModif(modif); + + parentDomNode = newDomNode; + nextSiblingDomNode = DOM::Node(); + modif = new NodeModif(); + } + + node = kafkaCommon::createNode("", domNode.nodeValue().string(), Tag::Text, + m_currentDoc); + ptDomNode = new DOM::Node(domNode); + node->setRootNode(ptDomNode); + ptDomNode = new DOM::Node(domNode); + node->setLeafNode(ptDomNode); + //avoid the merging of Text Nodes + node = kafkaCommon::insertNode(node, getNode(parentDomNode), + getNode(nextSiblingDomNode), modifs, false); + props->setNode(node); + modifs->addNodeModif(modif); + //If there is a empty Node after of before the text, remove them + if(node->prev && node->prev->tag->type == Tag::Empty) + kafkaCommon::extractNode(node->prev, modifs); + if(node->next && node->next->tag->type == Tag::Empty) + kafkaCommon::extractNode(node->next, modifs); + + //Log the changes + m_currentDoc->docUndoRedo->addNewModifsSet(modifs, undoRedo::KafkaModif); + } + + props->setIsLinkedToNode(true); + props->setSpecialBehavior(kNodeAttrs::none); + } + + +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::slotDomNodeModified() in " << t.elapsed() << + " ms only!" << endl; +#endif + +#ifdef HEAVY_DEBUG + kafkaCommon::coutTree(baseNode, 2); +#endif +} + +void KafkaDocument::slotDomNodeAboutToBeRemoved(DOM::Node _domNode, bool deleteChilds, NodeModifsSet* modifs) +{ +#ifdef LIGHT_DEBUG + if(!_domNode.isNull()) + kdDebug(25001)<< "KafkaDocument::slotDomNodeAboutToBeRemoved() - DOM::Node: " << + _domNode.nodeName().string() << "(" << _domNode.handle() << ")"<< " bool :" << + deleteChilds << endl; + else + kdDebug(25001)<< "KafkaDocument::slotDomNodeAboutToBeRemoved() - DOM::Node: NULL bool :" << + deleteChilds << endl; +#endif + Node *_node = 0L, *_nodeNext = 0L, *_tmpNode = 0L, *n = 0L; + int i, bLine, bCol, eLine, eCol, bLine2, bCol2; + bool hasClosingNode = false, b; + NodeModif *modif; + +#ifdef LIGHT_DEBUG + QTime t; + t.start(); +#endif + + _node = getNode(_domNode); + if(!_node) + { + kdDebug(25001)<<"KafkaDocument::slotDomNodeAboutToBeRemoved() - *ERROR* the" << + " corresponding DOM::Node is not found!" << endl; + return; + } + + + //If we are deleting a PHP Node which is embedded into a tag e.g. > + //We must regenerate the tag string. + if(_node->tag->type == Tag::ScriptTag && _node->parent) + { + _node->parent->tag->beginPos(bLine, bCol); + _node->parent->tag->endPos(eLine, eCol); + _node->tag->beginPos(bLine2, bCol2); + if(QuantaCommon::isBetween(bLine2, bCol2, bLine, bCol, eLine,eCol) == 0) + _node->parent->tag->setCleanStrBuilt(false); + } + + if(_node->prev) + { + //delete the previous empty tag if present + _nodeNext = _node; + _node = _node->prev; + if(_node && _node->tag->type == Tag::Empty) + { + modif = new NodeModif(); + modif->setType(NodeModif::NodeRemoved); + modif->setLocation(kafkaCommon::getLocation(_node)); + if(_node->parent && _node->parent->child == _node) + _node->parent->child = _node->next; + if(_node->prev) + _node->prev->next = _node->next; + if(_node->next) + _node->next->prev = _node->prev; + if(_node == baseNode) + baseNode = _node->next; + _node->parent = 0L; + _node->prev = 0L; + _node->next = 0L; + _node->child = 0L; + modif->setNode(_node); + modifs->addNodeModif(modif); + } + _node = _nodeNext; + } + + //delete the Node + modif = new NodeModif(); + if(deleteChilds) + modif->setType(NodeModif::NodeAndChildsRemoved); + else + modif->setType(NodeModif::NodeRemoved); + modif->setLocation(kafkaCommon::getLocation(_node)); + + if(_node->getClosingNode()) + hasClosingNode = true; + else + hasClosingNode = false; + //_node->removeAll = false; + + if(_node->parent && _node->parent->child == _node) + _node->parent->child = _node->next; + if(_node->next) + _node->next->prev = _node->prev; + if(_node->prev) + _node->prev->next = _node->next; + + i = 0; + if(_node->child && deleteChilds) + { + _tmpNode = _node->child; + b = false; + while(_tmpNode) + { + if(_tmpNode->rootNode()) + disconnectDomNodeFromQuantaNode(*_tmpNode->rootNode()); + if(_tmpNode->leafNode()) + disconnectDomNodeFromQuantaNode(*_tmpNode->leafNode()); + _tmpNode = kafkaCommon::getNextNode(_tmpNode, b, _node); + } + //delete _node->child; + } + else if(_node->child)// && !deleteChilds + { + if(_node->parent && !_node->parent->child) + _node->parent->child = _node->child; + if(_node->prev) + _node->prev->next = _node->child; + _tmpNode = _node->child; + while(_tmpNode) + { + i++; + _tmpNode->parent = _node->parent; + n = _tmpNode; + _tmpNode = _tmpNode->next; + if(!_tmpNode) + { + n->next = _node->next; + if(_node->next) + _node->next->prev = n; + } + } + } + if(_node == baseNode) + baseNode = _node->next; + + if(_node->rootNode()) + disconnectDomNodeFromQuantaNode(*_node->rootNode()); + if(_node->leafNode()) + disconnectDomNodeFromQuantaNode(*_node->leafNode()); + _node->parent = 0L; + _nodeNext = _node->next; + _node->next = 0L; + _node->prev = 0L; + _node->child = 0L; + modif->setNode(_node); + //delete _node; + modif->setChildrenMovedUp(i); + modifs->addNodeModif(modif); + _node = _nodeNext; + + if(hasClosingNode) + { + //delete the closing Node if present + if(_node->parent && _node->parent->child == _node) + _node->parent->child = _node->next; + if(_node->prev) + _node->prev->next = _node->next; + if(_node->next) + _node->next->prev = _node->prev; + _node->parent = 0L; + _nodeNext = _node->next; + _node->next = 0L; + _node->prev = 0L; + _node->child = 0L; + modif = new NodeModif(); + modif->setType(NodeModif::NodeRemoved); + modif->setLocation(kafkaCommon::getLocation(_node)); + modif->setNode(_node); + modifs->addNodeModif(modif); + //delete _node; + _node = _nodeNext; + } + + if(_node && _node->tag->type == Tag::Empty) + { + //delete the next empty tag if present + modif = new NodeModif(); + modif->setType(NodeModif::NodeRemoved); + modif->setLocation(kafkaCommon::getLocation(_node)); + if(_node->parent && _node->parent->child == _node) + _node->parent->child = _node->next; + if(_node->prev) + _node->prev->next = _node->next; + if(_node->next) + _node->next->prev = _node->prev; + _node->parent = 0L; + _nodeNext = _node->next; + _node->prev = 0L; + _node->next = 0L; + _node->child = 0L; + modif->setNode(_node); + modifs->addNodeModif(modif); + _node = _nodeNext; + } + + //NO NORMALIZATION!! It is KafkaWidget::normalize()'s job! + +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::slotDomNodeDeleted() in " << t.elapsed() << + " ms only!" << endl; +#endif +#ifdef HEAVY_DEBUG + kafkaCommon::coutTree(baseNode, 2); +#endif + +} + +void KafkaDocument::slotDomNodeIsAboutToBeMoved(DOM::Node domNode, DOM::Node newParent, DOM::Node before, NodeModifsSet* modifs) +{ + Node *node, *parent, *nextSibling, *closingNode; + + if(domNode.isNull()) + return; + + node = getNode(domNode); + parent = getNode(newParent); + nextSibling = getNode(before); + + if(!node) + return; + + closingNode = node->getClosingNode(); + + kafkaCommon::moveNode(node, parent, nextSibling, modifs, false); + + if(closingNode) + kafkaCommon::moveNode(closingNode, parent, nextSibling, modifs, false); + +} + +void KafkaDocument::slotdomNodeNewCursorPos(DOM::Node, int) +{ +#ifdef LIGHT_DEBUG + kdDebug(25001)<< "KafkaDocument::slotdomNodeNewCursorPos()" << endl; +#endif + //int line, col; + //dont calculate cursor pos until the next view update + //getQuantaCursorPosition(line, col); + //emit newCursorPosition(line, col); +} + +void KafkaDocument::slotCut() +{ + QString text = m_kafkaPart->selectedText(); + + NodeSelectionInd selection_ind; + selection_ind.fillWithVPLCursorSelection(); + + int startOffset = selection_ind.cursorOffset(); + int endOffset = selection_ind.cursorOffsetEndSel(); + Node* startNode = kafkaCommon::getNodeFromLocation(selection_ind.cursorNode()); + Node* endNode = kafkaCommon::getNodeFromLocation(selection_ind.cursorNodeEndSel()); + + DOM::Node cursorDomNode; + long cursorOffset; + + m_kafkaPart->getCurrentNode(cursorDomNode, cursorOffset); + Node* cursorNode = getNode(cursorDomNode); + + slotCut(startNode, startOffset, endNode, endOffset, &cursorNode, cursorOffset, text); +} + +void KafkaDocument::slotCut(Node* startNode, int startOffset, Node* endNode, int endOffset, + Node** cursorNode, long cursorOffset, QString const& text) +{ + if(!startNode || !endNode) + return; + + NodeModifsSet *modifs = new NodeModifsSet(); + + Node* subtree_root = kafkaCommon::DTDExtractNodeSubtree(startNode, startOffset, endNode, endOffset, + cursorNode, cursorOffset, modifs); + + m_currentDoc->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif); + + //Now update the VPL cursor position + kafkaWidget->setCurrentNode(startNode, startOffset); + + if(subtree_root) + { + KafkaDragObject* node_drag = new KafkaDragObject(subtree_root); + QTextDrag* text_drag = new QTextDrag(text); + KMultipleDrag* drag_object = new KMultipleDrag(); + drag_object->addDragObject(node_drag); + drag_object->addDragObject(text_drag); + + QApplication::clipboard()->setData(drag_object); +#ifdef LIGHT_DEBUG + kafkaCommon::coutTree(subtree_root, 3); +#endif + } +} + +void KafkaDocument::slotCopy() +{ + QString text = m_kafkaPart->selectedText(); + + NodeSelectionInd selection_ind; + selection_ind.fillWithVPLCursorSelection(); + + int startOffset = selection_ind.cursorOffset(); + int endOffset = selection_ind.cursorOffsetEndSel(); + Node* startNode = kafkaCommon::getNodeFromLocation(selection_ind.cursorNode()); + Node* endNode = kafkaCommon::getNodeFromLocation(selection_ind.cursorNodeEndSel()); + + slotCopy(startNode, startOffset, endNode, endOffset, text); +} + +void KafkaDocument::slotCopy(Node* startNode, int startOffset, Node* endNode, int endOffset, QString const& text) +{ + if(!startNode || !endNode) + return; + + Node* subtree_root = kafkaCommon::getNodeSubtree(startNode, startOffset, endNode, endOffset); + + if(subtree_root) + { + KafkaDragObject* node_drag = new KafkaDragObject(subtree_root); + QTextDrag* text_drag = new QTextDrag(text); + KMultipleDrag* drag_object = new KMultipleDrag(); + drag_object->addDragObject(node_drag); + drag_object->addDragObject(text_drag); + + QApplication::clipboard()->setData(drag_object); + // FIXME delete the subtree +#ifdef LIGHT_DEBUG + kafkaCommon::coutTree(subtree_root, 3); +#endif + } +} + +void KafkaDocument::slotPaste() +{ + QClipboard *cb = QApplication::clipboard(); + QMimeSource* e = cb->data(); + Node* node = new Node(0); + + if(KafkaDragObject::decode(e, node)) + { + bool go_up = false; + for(Node* aux = node; aux; aux = kafkaCommon::getNextNode(aux, go_up)) + kafkaCommon::restorePastedNode(aux, getCurrentDoc()); + + NodeSelectionInd selection_ind; + selection_ind.fillWithVPLCursorSelection(); + + Node* cursorNode = kafkaCommon::getNodeFromLocation(selection_ind.cursorNode()); + long cursorOffset = selection_ind.cursorOffset(); + + NodeModifsSet *modifs = new NodeModifsSet(); + + if(selection_ind.hasSelection()) + kafkaCommon::DTDRemoveSelection(selection_ind, &cursorNode, cursorOffset, modifs); + else + cursorNode = 0; // use selection_ind + kafkaCommon::DTDInsertNodeSubtree(node, selection_ind, &cursorNode, cursorOffset, modifs); + + m_currentDoc->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif, 0, false); + + //Now update the VPL cursor position + kafkaWidget->setCurrentNode(cursorNode, cursorOffset); + } +} -- cgit v1.2.1