You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdewebdev/quanta/parts/kafka/wkafkapart.cpp

2408 lines
68 KiB

/***************************************************************************
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 <dom/dom_node.h>
#include <dom/dom_exception.h>
#include <dom/dom_string.h>
#include <dom/css_stylesheet.h>
#include <kdebug.h>
#include <khtmlview.h>
#include <kstandarddirs.h>
#include <ktexteditor/editinterface.h>
#include <ktexteditor/selectioninterface.h>
#include <kstandarddirs.h>
#include <klocale.h>
#include <kmultipledrag.h>
#include <kglobal.h>
#include <kcharsets.h>
#include <tqregexp.h>
#include <tqfile.h>
#include <tqtextstream.h>
#include <tqdatetime.h>
#include <tqclipboard.h>
#include <tqptrvector.h>
#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(TQWidget *parent, TQWidget *widgetParent, const char *name)
:domNodeProps(1021), _docLoaded(false)
{
// i18n reserve
TQString a = i18n("Selector");TQString b = i18n("Attribute");TQString c = i18n("Class");
TQString d = i18n("Pseudo-class");TQString e = i18n("CSS rules");TQString f = i18n("Universal selector");
TQString g = i18n("Linked stylesheets");TQString h = i18n("Embedded stylesheets");TQString i = i18n("Inline style attribute");
TQString j = i18n("Link");TQString k = i18n("Priority");TQString l = i18n("ID");
TQString m = i18n("Browser support");TQString n = i18n("Pseudo-element");TQString o = i18n("Imported");
TQString p = i18n("Inheritance");TQString q = i18n("Inherited");TQString r = "";
TQString s = i18n("Name");TQString tt = i18n("Undo");TQString u = i18n("Redo");
TQString v = i18n("Undo/Redo history");TQString w = i18n("CSS styles");
TQString x = i18n("Sorry, VPL does not support this functionality yet.");
TQString y = i18n("Merge cells");
TQString z = i18n("Split cells");
TQString aa = i18n("Edit CSS style of this Tag");
TQString 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();
TQFile file( m_stddirs->findResource("data", "kafkapart/entities" )/**locate("appdata","chars") */);
delete m_stddirs;
TQString tmp;
if ( file.open(IO_ReadOnly) )
{
TQTextStream t( &file ); // use a text stream
t.setEncoding(TQTextStream::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, TQT_SIGNAL(domNodeInserted(DOM::Node, bool, NodeModifsSet*)),
this, TQT_SLOT(slotDomNodeInserted(DOM::Node, bool, NodeModifsSet*)));
connect(m_kafkaPart, TQT_SIGNAL(domNodeModified(DOM::Node, NodeModifsSet*)),
this, TQT_SLOT(slotDomNodeModified(DOM::Node, NodeModifsSet*)));
connect(m_kafkaPart, TQT_SIGNAL(domNodeIsAboutToBeRemoved(DOM::Node, bool, NodeModifsSet*)),
this, TQT_SLOT(slotDomNodeAboutToBeRemoved(DOM::Node, bool, NodeModifsSet*)));
connect(m_kafkaPart, TQT_SIGNAL(domNodeIsAboutToBeMoved(DOM::Node, DOM::Node, DOM::Node, NodeModifsSet*)),
this, TQT_SLOT(slotDomNodeIsAboutToBeMoved(DOM::Node, DOM::Node, DOM::Node, NodeModifsSet*)));
connect(m_kafkaPart, TQT_SIGNAL(domNodeNewCursorPos(DOM::Node, int)),
this, TQT_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
TQTime t;
t.start();
#endif
m_currentDoc = doc;
(static_cast<HTMLEnhancer *>(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::BrowserExtension *>(((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)
{
TQString 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 TQTag 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;
TQString 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;
TQTag* 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 TQString)
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);
TQTag* 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)
{
TQString text = domNode.nodeValue().string();
text.replace("<", "&lt;");
text.replace(">", "&gt;");
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;
}
TQString KafkaDocument::getDecodedChar(const TQString &encodedChar)
{
TQMap<TQString, TQString>::Iterator it = encodedChars.find(encodedChar);
if(it == encodedChars.end())
{
//try this
return KGlobal::charsets()->resolveEntities(encodedChar);;
}
return it.data();
}
TQString KafkaDocument::getDecodedText(const TQString &a_encodedText, bool translateWhiteSpacesAndLineBreaks,
bool removeLeftWhitespaces, bool removeRightWhitespaces)
{
TQString encodedText = a_encodedText;
if (encodedText.isEmpty())
encodedText = " ";
TQString decodedChar;
int i, j;
#ifdef LIGHT_DEBUG
TQString 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(TQString(encodedText[i]) == "&")
{
j = i;
while((unsigned)++i < encodedText.length() &&
TQString(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
}
TQString KafkaDocument::getEncodedChar(const TQString &decodedChar, const TQString &previousDecodedChar)
{
if(decodedChar[0].isSpace() && !previousDecodedChar[0].isSpace())
return " ";
else if(decodedChar[0].isSpace())
//FIXME:for an unknown reason, by default it return &iquest; instead of &nbsp;
return "&nbsp;";
TQMap<TQString, TQString>::Iterator it = decodedChars.find(decodedChar);
if(it == decodedChars.end())
return decodedChar;
return it.data();
}
TQString KafkaDocument::getEncodedText(const TQString &a_decodedText, int bLine, int bCol, int &eLine, int &eCol,
bool translateWhiteSpaces)
{
TQString decodedText = a_decodedText;
TQString Encodedchar;
TQString decodedChar, previousDecodedChar;
#ifdef LIGHT_DEBUG
TQString oldDecodedText = decodedText;
#endif
int i;
#ifdef LIGHT_DEBUG
int _bLine = bLine, _bCol = bCol;
#endif
i = -1;
while((unsigned)++i < decodedText.length())
{
previousDecodedChar = decodedChar;
decodedChar = TQString(decodedText[i]);
if(translateWhiteSpaces || !decodedText[i].isSpace())
Encodedchar = getEncodedChar(TQString(decodedText[i]),
(i>=1)?previousDecodedChar:TQString(""));
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;
}
TQString KafkaDocument::getEncodedText(const TQString& decodedText)
{
int a = 0, b = 0, c, d;
return getEncodedText(decodedText, a, b, c, d);
}
TQString KafkaDocument::generateCodeFromNode(Node *node, int bLine, int bCol, int &eLine, int &eCol, bool encodeText)
{
TQString 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(TQRegExp("\\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 = "<!";
}
else if(node->tag->name.contains("XML PI", false))
{
text = "<?xml";
}
else if(node->tag->name.contains("PHP", false))
{
text = "<?php";
}
bCol += text.length();
eCol = bCol - 1;
eLine = bLine;
}
else
{
//default behavior : return node->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;
TQString 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;
TQString 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)
{
TQString decodedText, encodedChar, encodedText, currentChar;
TQChar 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:" << TQString(curChar) << ": oldChar:" <<
// TQString(oldChar) << endl;
#endif
encodedChar = getEncodedChar(TQString(curChar), TQString(oldChar));
if(encodedChar == "&nbsp;")
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) == "&nbsp;")
{
encodedChar = "&nbsp;";
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;
TQString decodedText, encodedChar, currentLine, currentChar;
TQChar 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:" << TQString(curChar) << ": oldChar:" << TQString(oldChar) << endl;
#endif
encodedChar = getEncodedChar(TQString(curChar), TQString(oldChar));
if(encodedChar == "&nbsp;")
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) == "&nbsp;")
{
encodedChar = "&nbsp;";
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)
{
TQString 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
TQString 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 <<endl;
if (node->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
TQTime 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;
TQTag *qTag;
#ifdef LIGHT_DEBUG
TQTime 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
TQTime 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. <a <? echo boo; ?> >
//We must regenerate the <a> 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()
{
TQString 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, TQString 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);
TQTextDrag* text_drag = new TQTextDrag(text);
KMultipleDrag* drag_object = new KMultipleDrag();
drag_object->addDragObject(node_drag);
drag_object->addDragObject(text_drag);
TQApplication::tqclipboard()->setData(drag_object);
#ifdef LIGHT_DEBUG
kafkaCommon::coutTree(subtree_root, 3);
#endif
}
}
void KafkaDocument::slotCopy()
{
TQString 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, TQString 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);
TQTextDrag* text_drag = new TQTextDrag(text);
KMultipleDrag* drag_object = new KMultipleDrag();
drag_object->addDragObject(node_drag);
drag_object->addDragObject(text_drag);
TQApplication::tqclipboard()->setData(drag_object);
// FIXME delete the subtree
#ifdef LIGHT_DEBUG
kafkaCommon::coutTree(subtree_root, 3);
#endif
}
}
void KafkaDocument::slotPaste()
{
TQClipboard *cb = TQApplication::tqclipboard();
TQMimeSource* 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);
}
}