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.
2275 lines
80 KiB
2275 lines
80 KiB
/***************************************************************************
|
|
kafkahtmlpart.cpp
|
|
-------------------
|
|
|
|
copyright : (C) 2001 - The Kafka Team
|
|
(C) 2003, 2004 - Nicolas Deschildre
|
|
email : kde-kafka@master.kde.org && ndeschildre@kdewebdev.org
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include <tqfile.h>
|
|
#include <tqpainter.h>
|
|
#include <tqtextstream.h>
|
|
#include <tqstringlist.h>
|
|
#include <tqlayout.h>
|
|
#include <tqmainwindow.h>
|
|
#include <tqtimer.h>
|
|
#include <tqtooltip.h>
|
|
#include <tqpopupmenu.h>
|
|
|
|
#include <kdebug.h>
|
|
#include <tdelocale.h>
|
|
#include <tdehtmlview.h>
|
|
#include <tdemessagebox.h>
|
|
#include <ktrader.h>
|
|
#include <klibloader.h>
|
|
#include <tdeparts/factory.h>
|
|
#include <dom/dom_node.h>
|
|
#include <dom/dom_text.h>
|
|
#include <dom/dom_exception.h>
|
|
#include <dom/dom_string.h>
|
|
#include <dom/dom2_range.h>
|
|
#include <tdehtml_events.h>
|
|
//#include <tdehtml_part.h>
|
|
|
|
#include "kafkacommon.h"
|
|
#ifdef HEAVY_DEBUG
|
|
#include "domtreeview.h"
|
|
#include <tqdialog.h>
|
|
#endif
|
|
#include "wkafkapart.h"
|
|
#include "undoredo.h"
|
|
#include "nodeproperties.h"
|
|
#include "tagaction.h"
|
|
#include "tagactionset.h"
|
|
#include "document.h"
|
|
#include "resource.h"
|
|
#include "quantacommon.h"
|
|
#include "quanta.h"
|
|
#include "quantaview.h"
|
|
#include "tagattributetree.h"
|
|
#include "tagactionmanager.h"
|
|
#include "tagactionset.h"
|
|
#include "cursors.h"
|
|
|
|
#include "viewmanager.h"
|
|
|
|
class KafkaWidgetPrivate
|
|
{
|
|
public:
|
|
KafkaWidgetPrivate()
|
|
{}
|
|
~KafkaWidgetPrivate()
|
|
{}
|
|
int m_cursorOffset;
|
|
int m_pressOffset;
|
|
int m_releaseOffset;
|
|
/** when going up and down, trying to be as close as possible from the
|
|
original node X pos like a good text editor :=) */
|
|
bool stuckCursorHorizontalPos;
|
|
int stuckedCursorPosX;
|
|
|
|
#ifdef HEAVY_DEBUG
|
|
KafkaDOMTreeDialog *domdialog;
|
|
#endif
|
|
};
|
|
|
|
KafkaWidget::KafkaWidget(TQWidget *parent, TQWidget *widgetParent, KafkaDocument *part,
|
|
const char *name)
|
|
: TDEHTMLPart(widgetParent, name, TQT_TQOBJECT(parent), name),
|
|
w(part)
|
|
{
|
|
m_contextPopupMenu = new TQPopupMenu();
|
|
|
|
d = new KafkaWidgetPrivate();
|
|
|
|
d->m_cursorOffset = 0;
|
|
d->m_pressOffset = 0;
|
|
d->m_releaseOffset = 0;
|
|
d->stuckCursorHorizontalPos = false;
|
|
|
|
m_modifs = 0L;
|
|
|
|
view()->setInputMethodEnabled(true);
|
|
|
|
// With the mix of Leo Savernik's caret Mode and the current editing
|
|
// functions, it will be kind of VERY messy
|
|
setCaretMode(true);
|
|
connect(this, TQT_SIGNAL(caretPositionChanged(const DOM::Node &, long)),
|
|
this, TQT_SLOT(slotNewCursorPos(const DOM::Node &, long)));
|
|
setCaretDisplayPolicyNonFocused(TDEHTMLPart::CaretVisible);
|
|
|
|
connect(this, TQT_SIGNAL(popupMenu(const TQString&, const TQPoint&)),
|
|
this, TQT_SLOT(slotContextMenuRequested(const TQString&, const TQPoint&)));
|
|
|
|
view()->setMouseTracking(true);
|
|
view()->installEventFilter(this);
|
|
|
|
//for debug purposes, we add a DOM tree view
|
|
#ifdef HEAVY_DEBUG
|
|
//d->domdialog = new KafkaDOMTreeDialog(view(), this);
|
|
//d->domdialog->show();
|
|
#endif
|
|
//IMPORTANT:without him, no document() is created in tdehtmlPart
|
|
begin();
|
|
write("<html></html>");
|
|
end();
|
|
}
|
|
|
|
KafkaWidget::~KafkaWidget()
|
|
{}
|
|
|
|
void KafkaWidget::newDocument()
|
|
{
|
|
//FIXME: Somehow we should get it from Quanta settings: qConfig.attrValueQuotation
|
|
//-->No need for that: Quotations aren't stored in the DOM::Nodes
|
|
TQString newPageHTMLCode = "<html>\n"
|
|
"<head>\n"
|
|
"</head>\n"
|
|
"<body>\n"
|
|
"</body>\n"
|
|
"</html>\n";
|
|
|
|
begin();
|
|
write(newPageHTMLCode);
|
|
end();
|
|
|
|
}
|
|
|
|
void KafkaWidget::insertText(DOM::Node node, const TQString &text, int position)
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::insertText text " << text << " pos " << position << endl;
|
|
#endif
|
|
|
|
int focus;
|
|
kNodeAttrs *attrs = w->getAttrs(node);
|
|
|
|
if(!attrs)
|
|
return;
|
|
|
|
focus = attrs->chCurFoc();
|
|
|
|
if(position < 0)
|
|
return;//nothing to do if something is selected
|
|
//if(focus == kNodeAttrs::no || !cbModified) return;//can't add text in this Node.
|
|
if(position == 0 && node.nodeName().string().lower() == "body")
|
|
{
|
|
//SPECIFIC HTML code!!!
|
|
//doesn't work!
|
|
//putCursorAtFirstAvailableLocation();
|
|
if(!node.firstChild().isNull() && node.firstChild().nodeType() == DOM::Node::TEXT_NODE)
|
|
{
|
|
node = m_currentNode = node.firstChild();
|
|
position = 0;
|
|
}
|
|
|
|
if(position == 0 && node.nodeName().string().lower() == "body")
|
|
{
|
|
//We shouldn't go here...
|
|
DOM::Text textNode = document().createTextNode(text);
|
|
node.appendChild(textNode);
|
|
m_currentNode = textNode;
|
|
d->m_cursorOffset = text.length();
|
|
emit domNodeInserted(textNode, false, m_modifs);
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001) << "KafkaWidget::insertText() - added text - 1" << endl;
|
|
#endif
|
|
|
|
TQTimer::singleShot(0, this, TQT_SLOT(slotDelayedSetCaretPosition()));
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(focus == kNodeAttrs::textNode && node.nodeType() == DOM::Node::TEXT_NODE)
|
|
{
|
|
DOM::DOMString textNode = node.nodeValue();
|
|
DOM::DOMString textSplitted = textNode.split(position);
|
|
node.setNodeValue(textNode + text + textSplitted);
|
|
d->m_cursorOffset += text.length();
|
|
emit domNodeModified(node, m_modifs);
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001) << "KafkaWidget::insertText() - added text" << endl;
|
|
#endif
|
|
|
|
}
|
|
else if(position == 0)
|
|
{
|
|
DOM::Text textNode = document().createTextNode(text);
|
|
DOM::Node parent = node.parentNode();
|
|
//FIXME: Andras: safety checks, as parent can be null. Maybe it just hides the error...
|
|
if (!parent.isNull())
|
|
parent.insertBefore(textNode, node);
|
|
else
|
|
node.appendChild(textNode);
|
|
m_currentNode = textNode;
|
|
d->m_cursorOffset = text.length();
|
|
emit domNodeInserted(textNode, false, m_modifs);
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001) << "KafkaWidget::insertText() - added text - 2" << endl;
|
|
#endif
|
|
|
|
}
|
|
else if(position == 3 || (position == 1 && (focus == kNodeAttrs::singleNodeAndItself)))
|
|
{
|
|
DOM::Text textNode = document().createTextNode(text);
|
|
DOM::Node parent = node.parentNode();
|
|
//FIXME: Andras: safety checks, as parent and node.nextSibling can be null. Maybe it just hides the error...
|
|
//Also it seems that position can be 3 and node is "body". See bug 112733.
|
|
if (node.nodeName().string().lower() != "body" && !parent.isNull())
|
|
{
|
|
if (!node.nextSibling().isNull())
|
|
parent.insertBefore(textNode, node.nextSibling());
|
|
else
|
|
parent.insertBefore(textNode, node);
|
|
}
|
|
else
|
|
node.appendChild(textNode);
|
|
m_currentNode = textNode;
|
|
d->m_cursorOffset = text.length();
|
|
emit domNodeInserted(textNode, false, m_modifs);
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001) << "KafkaWidget::insertText() - added text - 3" << endl;
|
|
#endif
|
|
|
|
}
|
|
else if(position == 1)
|
|
{
|
|
DOM::Text textNode = document().createTextNode(text);
|
|
if(!node.firstChild().isNull())
|
|
node.insertBefore(textNode, node.firstChild());
|
|
else
|
|
node.appendChild(textNode);
|
|
m_currentNode = textNode;
|
|
d->m_cursorOffset = text.length();
|
|
emit domNodeInserted(textNode, false, m_modifs);
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001) << "KafkaWidget::insertText() - added text - 4" << endl;
|
|
#endif
|
|
|
|
}
|
|
//document().updateRendering();
|
|
TQTimer::singleShot(0, this, TQT_SLOT(slotDelayedSetCaretPosition()));
|
|
}
|
|
|
|
void KafkaWidget::slotDelayedSetCaretPosition()
|
|
{
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
|
|
}
|
|
|
|
void KafkaWidget::insertText(const TQString &text, int position)
|
|
{
|
|
insertText(m_currentNode, text, (position == -1 ? d->m_cursorOffset : position));
|
|
}
|
|
|
|
|
|
void KafkaWidget::normalize(DOM::Node _node)
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::normalize()" << endl;
|
|
#endif
|
|
|
|
//FIXME: Andras: getAttrs() can sometimes return NULL and causes a crash. No idea why and what it means though.
|
|
DOM::Node childNode = _node.firstChild();
|
|
while(!childNode.isNull())
|
|
{
|
|
if(w->getAttrs(childNode) && w->getAttrs(childNode)->chCurFoc() == kNodeAttrs::textNode)
|
|
{
|
|
while(!childNode.nextSibling().isNull() &&
|
|
w->getAttrs(childNode.nextSibling()) && w->getAttrs(childNode.nextSibling())->chCurFoc() ==
|
|
kNodeAttrs::textNode )
|
|
{
|
|
childNode.setNodeValue(childNode.nodeValue() +
|
|
childNode.nextSibling().nodeValue());
|
|
emit domNodeModified(childNode, m_modifs);
|
|
emit domNodeIsAboutToBeRemoved(childNode.nextSibling(), true, m_modifs);
|
|
_node.removeChild(childNode.nextSibling());
|
|
}
|
|
}
|
|
childNode = childNode.nextSibling();
|
|
}
|
|
}
|
|
|
|
void KafkaWidget::keyReturn(bool specialPressed)
|
|
{
|
|
//WARNING : HTML-specific function
|
|
DOM::Node text, text2, pDomNode, pDomNode2, brDomNode, brDomNode2, tmp, PNode, emptyText;
|
|
int focus;
|
|
// TQTag *qTag;
|
|
bool childOfP;
|
|
//kNodeAttrs *props;
|
|
|
|
if(m_currentNode.isNull())
|
|
return;
|
|
if(!w->getAttrs(m_currentNode))
|
|
return;
|
|
|
|
focus = w->getAttrs(m_currentNode)->chCurFoc();
|
|
if (focus == kNodeAttrs::textNode)
|
|
{
|
|
//First determine if the current Node is a child of a P
|
|
childOfP = false;
|
|
tmp = m_currentNode;
|
|
while(!tmp.isNull())
|
|
{
|
|
if(tmp.nodeName().string().lower() == "p")
|
|
{
|
|
PNode = tmp;
|
|
childOfP = true;
|
|
break;
|
|
}
|
|
tmp = tmp.parentNode();
|
|
}
|
|
|
|
//Then split if necessary the text
|
|
if((static_cast<DOM::CharacterData>(m_currentNode)).length() == 0)
|
|
text = m_currentNode;
|
|
else if(d->m_cursorOffset <= 0)
|
|
text2 = m_currentNode;
|
|
else if((unsigned)d->m_cursorOffset >=
|
|
(static_cast<DOM::CharacterData>(m_currentNode)).length())
|
|
text = m_currentNode;
|
|
else
|
|
{
|
|
text = m_currentNode;
|
|
text2 = (static_cast<DOM::Text>(m_currentNode)).splitText(d->m_cursorOffset);
|
|
emit domNodeModified(m_currentNode, m_modifs);
|
|
emit domNodeInserted(text2, false, m_modifs);
|
|
}
|
|
|
|
if(!specialPressed)
|
|
{
|
|
if(childOfP)
|
|
{}
|
|
else
|
|
{}
|
|
}
|
|
else
|
|
{
|
|
if(childOfP)
|
|
{}
|
|
else
|
|
{}
|
|
}
|
|
|
|
|
|
//Then look if we are in a area which can handle a P
|
|
//and if it is ok and necessary, insert the current text in a P
|
|
//TODO: Change a bit for the p so that it handle every case
|
|
/**qTag = QuantaCommon::tagFromDTD(w->getCurrentDoc()->defaultDTD(),
|
|
m_currentNode.parentNode().nodeName().string());
|
|
pDomNode = kafkaCommon::hasParent(m_currentNode, "p");
|
|
if(pDomNode.isNull() && qTag && qTag->isChild("p"))
|
|
{
|
|
if(!text.isNull())
|
|
{
|
|
emit domNodeIsAboutToBeRemoved(text, false);
|
|
w->removeDomNode(text);
|
|
}
|
|
|
|
pDomNode = kafkaCommon::createDomNode("p", w->getCurrentDoc()->defaultDTD(),
|
|
document());
|
|
w->insertDomNode(pDomNode, m_currentNode.parentNode(),
|
|
m_currentNode.nextSibling());
|
|
emit domNodeInserted(pDomNode, false);
|
|
|
|
if(!text.isNull())
|
|
{
|
|
w->::insertDomNode(text, pDomNode);
|
|
emit domNodeInserted(text, false);
|
|
}
|
|
}
|
|
|
|
//Then we insert either a P or a BR tag.
|
|
if(qTag && qTag->isChild("p") && !pDomNode.isNull())
|
|
{
|
|
if(!text2.isNull())
|
|
{
|
|
emit domNodeIsAboutToBeRemoved(text2, false);
|
|
w->::removeDomNode(text2);
|
|
}
|
|
|
|
pDomNode2 = kafkaCommon::createDomNode("p", w->getCurrentDoc()->defaultDTD(),
|
|
document());
|
|
w->insertDomNode(pDomNode2, pDomNode.parentNode(),
|
|
pDomNode.nextSibling());
|
|
emit domNodeInserted(pDomNode2, false);
|
|
|
|
if(!text2.isNull())
|
|
{
|
|
w->insertDomNode(text2, pDomNode2);
|
|
emit domNodeInserted(text2, false);
|
|
}
|
|
m_currentNode = pDomNode2.firstChild();
|
|
d->m_cursorOffset = 0;
|
|
}
|
|
else
|
|
{*/
|
|
brDomNode = kafkaCommon::createDomNode("br", w->getCurrentDoc()->defaultDTD(),
|
|
document());
|
|
if(!text.isNull())
|
|
w->insertDomNode(brDomNode, m_currentNode.parentNode(),
|
|
text.nextSibling());
|
|
else
|
|
w->insertDomNode(brDomNode, m_currentNode.parentNode(),
|
|
text2);
|
|
emit domNodeInserted(brDomNode, false, m_modifs);
|
|
if(!text2.isNull())
|
|
m_currentNode = text2;
|
|
else
|
|
{
|
|
if(!brDomNode.nextSibling().isNull())
|
|
m_currentNode = brDomNode.nextSibling();
|
|
if(!brDomNode.nextSibling().isNull() && brDomNode.nextSibling().nextSibling().isNull())
|
|
{
|
|
//TEMP before the webcore caret.
|
|
brDomNode2 = kafkaCommon::createDomNode("br", w->getCurrentDoc()->defaultDTD(),
|
|
document());
|
|
if(!brDomNode.nextSibling().isNull())
|
|
w->insertDomNode(brDomNode2, m_currentNode.parentNode(),
|
|
DOM::Node());
|
|
|
|
emit domNodeInserted(brDomNode2, false, m_modifs);
|
|
m_currentNode = brDomNode;
|
|
}
|
|
|
|
}
|
|
d->m_cursorOffset = 0;
|
|
|
|
}
|
|
else if( m_currentNode.nodeName().string().lower() == "br")
|
|
{
|
|
brDomNode = kafkaCommon::createDomNode("br", w->getCurrentDoc()->defaultDTD(),
|
|
document());
|
|
w->insertDomNode(brDomNode, m_currentNode.parentNode(),
|
|
brDomNode.nextSibling());
|
|
emit domNodeInserted(brDomNode, false, m_modifs);
|
|
m_currentNode = brDomNode;
|
|
d->m_cursorOffset = 0;
|
|
}
|
|
|
|
#ifdef HEAVY_DEBUG
|
|
|
|
kdDebug(25001)<< "CURNODE : " << m_currentNode.nodeName().string() << ":"
|
|
<< m_currentNode.nodeValue().string() << " : " << d->m_cursorOffset << endl;
|
|
TQTimer::singleShot(0, this, TQT_SLOT(slotDelayedSetCaretPosition()));
|
|
kdDebug(25001)<< "CURNODE : " << m_currentNode.nodeName().string() << ":"
|
|
<< m_currentNode.nodeValue().string() << " : " << d->m_cursorOffset << endl;
|
|
//emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
|
|
// kdDebug(25001)<< "CURNODE : " << m_currentNode.nodeName().string() << ":"
|
|
// << m_currentNode.nodeValue().string() << " : " << d->m_cursorOffset << endl;
|
|
//postprocessCursorPosition();
|
|
kdDebug(25001)<< "CURNODE : " << m_currentNode.nodeName().string() << ":"
|
|
<< m_currentNode.nodeValue().string() << " : " << d->m_cursorOffset << endl;
|
|
#endif
|
|
|
|
TQTimer::singleShot(0, this, TQT_SLOT(slotDelayedSetCaretPosition()));
|
|
}
|
|
|
|
bool KafkaWidget::eventFilter(TQObject *, TQEvent *event)
|
|
{
|
|
bool forgetEvent = false;
|
|
//tmp
|
|
//DOM::Node attr, tmpNode;
|
|
//end tmp
|
|
|
|
if(event->type() == TQEvent::FocusIn)
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001) << "KafkaWidget::eventFilter() FocusIn" << endl;
|
|
#endif
|
|
|
|
emit hasFocus(true);
|
|
}
|
|
|
|
if(event->type() == TQEvent::FocusOut)
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001) << "KafkaWidget::eventFilter() FocusOut" << endl;
|
|
#endif
|
|
|
|
emit hasFocus(false);
|
|
}
|
|
|
|
if(event->type() == TQEvent::KeyPress || event->type() == TQEvent::IMEnd)
|
|
{
|
|
TQKeyEvent *keyevent = TQT_TQKEYEVENT(event);
|
|
|
|
//Create a new NodeModifsSet where the changes will be logged.
|
|
m_modifs = new NodeModifsSet();
|
|
|
|
switch(keyevent->key())
|
|
{
|
|
case Key_Left:
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001) << "KafkaWidget::eventFilter() Left" << endl;
|
|
#endif
|
|
//previousOffset(1);
|
|
d->stuckCursorHorizontalPos = false;
|
|
//forgetEvent = true;//to avoid the scrolling of the page
|
|
break;
|
|
|
|
case Key_Right:
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001) << "KafkaWidget::eventFilter() Right" << endl;
|
|
#endif
|
|
//nextOffset(1);
|
|
d->stuckCursorHorizontalPos = false;
|
|
//forgetEvent = true;
|
|
break;
|
|
|
|
case Key_Backspace:
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<< "KafkaWidget::eventFilter() Backspace" << endl;
|
|
#endif
|
|
|
|
keyBackspace();
|
|
d->stuckCursorHorizontalPos = false;
|
|
break;
|
|
|
|
case Key_Delete:
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<< "KafkaWidget::eventFilter() Delete" << endl;
|
|
#endif
|
|
|
|
keyDelete();
|
|
d->stuckCursorHorizontalPos = false;
|
|
break;
|
|
|
|
case Key_Up:
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<< "KafkaWidget::eventFilter() Up" << endl;
|
|
#endif
|
|
//keyUp();
|
|
//forgetEvent = true;
|
|
break;
|
|
case Key_Down:
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<< "KafkaWidget::eventFilter() Down" << endl;
|
|
#endif
|
|
//keyDown();
|
|
//forgetEvent = true;
|
|
break;
|
|
case Key_Escape:
|
|
break;
|
|
case Key_Tab:
|
|
if(!m_currentNode.isNull() && w->getAttrs(m_currentNode) &&
|
|
w->getAttrs(m_currentNode)->chCurFoc() != kNodeAttrs::no)
|
|
{
|
|
// @todo check tab settings in Quanta
|
|
if(hasSelection())
|
|
removeSelection();
|
|
insertText(" ", -1);
|
|
makeCursorVisible();
|
|
}
|
|
forgetEvent = true;
|
|
d->stuckCursorHorizontalPos = false;
|
|
break;
|
|
case Key_BackTab:
|
|
break;
|
|
case Key_Return:
|
|
case Key_Enter:
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<< "KafkaWidget::eventFilter() Return" << endl;
|
|
#endif
|
|
if(hasSelection())
|
|
removeSelection();
|
|
|
|
applyQueuedToggableTagActions();
|
|
|
|
keyReturn(keyevent->state() & ControlButton);
|
|
d->stuckCursorHorizontalPos = false;
|
|
break;
|
|
case Key_Insert:
|
|
break;
|
|
case Key_Pause:
|
|
#ifdef HEAVY_DEBUG
|
|
|
|
kafkaCommon::coutTree(baseNode, 2);
|
|
kafkaCommon::coutDomTree(document(), 2);
|
|
w->coutLinkTree(baseNode, 2);
|
|
#endif
|
|
|
|
break;
|
|
case Key_Print:
|
|
break;
|
|
case Key_SysReq:
|
|
break;
|
|
case Key_Home:
|
|
d->stuckCursorHorizontalPos = false;
|
|
break;
|
|
case Key_End:
|
|
d->stuckCursorHorizontalPos = false;
|
|
break;
|
|
case Key_Next:
|
|
break;
|
|
case Key_Shift:
|
|
break;
|
|
case Key_Control:
|
|
break;
|
|
case Key_Meta:
|
|
break;
|
|
case Key_Alt:
|
|
break;
|
|
case Key_CapsLock:
|
|
break;
|
|
case Key_NumLock:
|
|
break;
|
|
case Key_ScrollLock:
|
|
break;
|
|
|
|
default:
|
|
if(m_currentNode.isNull())
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::eventFilter() - DOM::Node NULL" << endl;
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
else if(w->getAttrs(m_currentNode) &&
|
|
w->getAttrs(m_currentNode)->chCurFoc() != kNodeAttrs::no ||
|
|
m_currentNode.nodeName().string().lower() == "body")
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001) << "KafkaWidget::eventFilter() Text - " <<
|
|
keyevent->text() << endl;
|
|
#endif
|
|
//if(( keyevent->state() & TQt::ShiftButton) || ( keyevent->state() == Qt::NoButton))
|
|
if( keyevent->text().length() &&
|
|
( !( keyevent->state() & ControlButton ) &&
|
|
!( keyevent->state() & AltButton ) &&
|
|
!( keyevent->state() & MetaButton ) ||
|
|
( ( (keyevent->state()&ControlButton) | AltButton ) == (ControlButton|AltButton) ) ) &&
|
|
( !keyevent->ascii() || keyevent->ascii() >= 32 || keyevent->text() == "\t" ) || event->type() == TQEvent::IMEnd )
|
|
{
|
|
if(hasSelection())
|
|
removeSelection();
|
|
|
|
applyQueuedToggableTagActions();
|
|
|
|
insertText(keyevent->text(), -1);
|
|
}
|
|
makeCursorVisible();
|
|
#ifdef HEAVY_DEBUG
|
|
//w->coutLinkTree(baseNode, 2);
|
|
#endif
|
|
|
|
}
|
|
forgetEvent = true;
|
|
d->stuckCursorHorizontalPos = false;
|
|
break;
|
|
}
|
|
|
|
//Submit the modifs to the undoRedo system.
|
|
ViewManager::ref()->activeDocument()->docUndoRedo->addNewModifsSet(m_modifs, undoRedo::KafkaModif, 0, qConfig.replaceAccented);
|
|
m_modifs = 0L;
|
|
}
|
|
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "Current Offset : " << m_currentNode.nodeName().string() << ":" <<
|
|
d->m_cursorOffset << " (" << event->type() << ")" << endl;
|
|
#endif
|
|
|
|
return forgetEvent;
|
|
}
|
|
|
|
void KafkaWidget::slotContextMenuRequested(const TQString& /*url*/, const TQPoint& point)
|
|
{
|
|
TagActionManager::self()->fillWithTagActions(m_contextPopupMenu, nodeUnderMouse());
|
|
|
|
if(m_contextPopupMenu->count() != 0)
|
|
m_contextPopupMenu->popup(point);
|
|
}
|
|
|
|
|
|
#if 0
|
|
void KafkaWidget::keyDeleteNodes(DOM::Node &startNode, long &offset, bool backspace)
|
|
{
|
|
DOM::Node domNode = startNode, nextNode;
|
|
kNodeAttrs *attrs;
|
|
long nextOffset;
|
|
DOM::DOMString nodeText, textSplitted;
|
|
|
|
while(!domNode.isNull())
|
|
{
|
|
//Start by getting the attributes of the Node
|
|
attrs = w->getAttrs(domNode);
|
|
if(!attrs)
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<<"KafkaWidget::keyDeleteNodes() - ERROR KNodeAttrs not found!"
|
|
<< endl;
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
//Get the next Location
|
|
nextNode = domNode;
|
|
nextOffset = offset;
|
|
if(backspace)
|
|
getPrevNodeRangeSpecs(nextNode, offset, blok! );
|
|
else
|
|
getNextNodeRangeSpecs(nextNode, offset);
|
|
|
|
//Nodes that can't be deleted stop the cursor (e.g. TBODY)
|
|
if(!attrs->cbDel())
|
|
break;
|
|
|
|
//If we are in some text, and a letter can be deleted, delete it.
|
|
if(domNode.nodeType() == DOM::Node::TEXT_NODE && ((backspace && offset != 0)) ||
|
|
(!backspace && offset != (static_cast<DOM::CharacterData>(domNode)).length()))
|
|
)
|
|
{
|
|
nodeText = domNode.nodeValue();
|
|
textSplitted = nodeText.split(backspace?offset:offset + 1);
|
|
nodeText.split(backspace?offset - 1:offset);
|
|
domNode.setNodeValue(nodeText + textSplitted);
|
|
//m_currentNode.parentNode().applyChanges();
|
|
emit domNodeModified(domNode);
|
|
//postprocessCursorPosition();
|
|
break;
|
|
}
|
|
|
|
//If we are in an empty text (shoudn't occur), delete it
|
|
if(domNode.nodeType()
|
|
== DOM::Node::TEXT_NODE &&
|
|
(static_cast<DOM::CharacterData>(domNode)).length() == 0)
|
|
{
|
|
emit domNodeIsAboutToBeRemoved(domNode, true);
|
|
domNode.parentNode().removeChild(domNode);
|
|
domNode = nextNode;
|
|
continue;
|
|
}
|
|
|
|
//If we are in an empty Node (Inline), delete it
|
|
if(domNode.nodeType()
|
|
== DOM::Node::ELEMENT_NODE && offset == 0 && !domNode.hasChildNodes())
|
|
{
|
|
|
|
continue;
|
|
}
|
|
|
|
//If the current Node is an empty Text, delete it
|
|
if()
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//If the current Node is an empty Node (kNodeAttrs::singleNodeAndItself)), delete it
|
|
if()
|
|
{
|
|
return;
|
|
}
|
|
|
|
//If the current Node is an empty Node (Inline) delete it
|
|
if()
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
void KafkaWidget::keyDelete()
|
|
{
|
|
kNodeAttrs *attrs, *attrsTmp;
|
|
int focus, childPosition;
|
|
DOM::Node _nodeParent, _node, _nodeNext, temp, tempParent, nextSibling, nodeNextNext;
|
|
DOM::Node toplevelBlock, toplevelBlock2, startNode, endNode, startNode2, endNode2;
|
|
DOM::Node childOfCommonParent, childOfCommonParent2, commonParent;
|
|
bool _goingTowardsRootNode, isParent, singleNodeDeleted, nextIsBlock, startNode2IsNotInline;
|
|
|
|
if(hasSelection())
|
|
{
|
|
removeSelection();
|
|
return;
|
|
}
|
|
|
|
if(m_currentNode.isNull())
|
|
return;
|
|
attrs = w->getAttrs(m_currentNode);
|
|
if(!attrs)
|
|
return;
|
|
|
|
//OLD PART, TO BE REMOVED or #ifdef'ed
|
|
if(attrs->chCurFoc() == kNodeAttrs::textNode && (unsigned)d->m_cursorOffset !=
|
|
(static_cast<DOM::CharacterData>(m_currentNode)).length())
|
|
{//if we are in the middle of some text, we remove one letter
|
|
if(!attrs->cbMod())
|
|
return;
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<< "KafkaWidget::keyDelete() - one letter removed - 1" << endl;
|
|
#endif
|
|
|
|
DOM::DOMString nodeText = m_currentNode.nodeValue();
|
|
DOM::DOMString textSplitted = nodeText.split(d->m_cursorOffset + 1);
|
|
nodeText.split(d->m_cursorOffset);
|
|
m_currentNode.setNodeValue(nodeText + textSplitted);
|
|
m_currentNode.parentNode().applyChanges();
|
|
emit domNodeModified(m_currentNode, m_modifs);
|
|
postprocessCursorPosition();
|
|
return;
|
|
}
|
|
|
|
if(attrs->chCurFoc() != kNodeAttrs::no && attrs->chCurFoc() != kNodeAttrs::textNode &&
|
|
d->m_cursorOffset < 0)
|
|
{//if we delete ourselves, which node will be m_currentNode??
|
|
if(!attrs->cbDel())
|
|
return;
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<< "KafkaWidget::keyDelete() - deleting a Node - 2" << endl;
|
|
#endif
|
|
|
|
DOM::Node _node = m_currentNode;
|
|
bool b = false;
|
|
while(1)
|
|
{//try to find a prev node from which we can delete the node
|
|
_node = getPrevNode(_node, b);
|
|
if(_node == 0)
|
|
break;
|
|
attrs = w->getAttrs(_node);
|
|
if(attrs && attrs->chCurFoc() == kNodeAttrs::textNode)
|
|
{
|
|
m_currentNode = _node;
|
|
d->m_cursorOffset =
|
|
(static_cast<DOM::CharacterData>(_node)).length();
|
|
keyDelete();
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
|
|
return;
|
|
}
|
|
if(attrs && attrs->chCurFoc() != kNodeAttrs::no &&
|
|
attrs->chCurFoc() != kNodeAttrs::textNode)
|
|
{
|
|
m_currentNode = _node;
|
|
d->m_cursorOffset = 1;
|
|
keyDelete();
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
|
|
return;
|
|
}
|
|
}
|
|
b = false;
|
|
while(1)
|
|
{//try to find a next node from which we can delete the node
|
|
_node = getNextNode(_node, b);
|
|
if(_node == 0)
|
|
break;
|
|
attrs = w->getAttrs(_node);
|
|
if(attrs && attrs->chCurFoc() != kNodeAttrs::no)
|
|
{
|
|
m_currentNode = _node;
|
|
d->m_cursorOffset = 0;
|
|
keyBackspace();
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
|
|
return;
|
|
}
|
|
}
|
|
//here, there is no node right and left that can have the cursor focus
|
|
_node = m_currentNode.parentNode();
|
|
emit domNodeIsAboutToBeRemoved(m_currentNode, true, m_modifs);
|
|
_node.removeChild(m_currentNode);
|
|
m_currentNode = document().createTextNode("");
|
|
_node.appendChild(m_currentNode);
|
|
emit domNodeInserted(m_currentNode, false, m_modifs);
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
|
|
}
|
|
|
|
//Beginning of the actual keyDelete
|
|
_node = m_currentNode;
|
|
_goingTowardsRootNode = false;
|
|
singleNodeDeleted = false;
|
|
_nodeNext = getNextNode(_node, _goingTowardsRootNode);
|
|
while(!_nodeNext.isNull())
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::keyDelete() - currentNode: " <<
|
|
_nodeNext.nodeName().string() << endl;
|
|
#endif
|
|
|
|
attrs = w->getAttrs(_nodeNext);
|
|
|
|
//If this Node can't be deleted, we stop here.
|
|
if(!attrs || !attrs->cbDel())
|
|
return;
|
|
|
|
//If we are in a TEXT node, we remove a letter
|
|
if(attrs->chCurFoc() == kNodeAttrs::textNode)
|
|
{
|
|
if((static_cast<DOM::CharacterData>(_nodeNext)).length() != 0)
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::keyDelete() - one letter" <<
|
|
" removed - 2" << endl;
|
|
#endif
|
|
|
|
DOM::DOMString nodeText = _nodeNext.nodeValue();
|
|
DOM::DOMString textSplitted = nodeText.split(1);
|
|
_nodeNext.setNodeValue(textSplitted);
|
|
emit domNodeModified(_nodeNext, m_modifs);
|
|
postprocessCursorPosition();
|
|
normalize(_nodeNext.parentNode());
|
|
break;
|
|
}
|
|
else
|
|
{//if we are in an empty text, delete it
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::keyDelete() - deleting" <<
|
|
"empty #text" << endl;
|
|
#endif
|
|
|
|
_nodeParent = _nodeNext.parentNode();
|
|
//If this empty text contains the cursor, change node to its parent.
|
|
if(_nodeNext == _node && _nodeParent.firstChild() == _nodeNext &&
|
|
_nodeNext.nextSibling().isNull())
|
|
{
|
|
_node = _nodeParent;
|
|
//d->m_cursorOffset = -2;
|
|
}
|
|
emit domNodeIsAboutToBeRemoved(_nodeNext, true, m_modifs);
|
|
_nodeParent.removeChild(_nodeNext);
|
|
singleNodeDeleted = true;
|
|
_nodeParent.applyChanges();
|
|
_nodeNext = _node;
|
|
}
|
|
}
|
|
//Else if the current Node is a BLOCK which can be entered/leaved e.g. H1
|
|
else if(attrs->chCurFoc() == kNodeAttrs::blockNode)
|
|
{
|
|
//First look if it is one of _node's parent
|
|
isParent = false;
|
|
temp = _node;
|
|
while(!temp.isNull())
|
|
{
|
|
if(_nodeNext == temp)
|
|
isParent = true;
|
|
temp = temp.parentNode();
|
|
}
|
|
|
|
//1 - Locate the toplevel blocks
|
|
temp = _nodeNext;
|
|
if(isParent)
|
|
{
|
|
toplevelBlock = temp;
|
|
while(temp.parentNode().lastChild() == temp && w->getAttrs(temp.parentNode()) &&
|
|
w->getAttrs(temp.parentNode())->chCurFoc() == kNodeAttrs::blockNode)
|
|
temp = temp.parentNode();
|
|
childOfCommonParent = temp;
|
|
temp = temp.nextSibling();
|
|
}
|
|
if(temp.isNull())
|
|
break;
|
|
childOfCommonParent2 = temp;
|
|
commonParent = temp.parentNode();
|
|
attrsTmp = w->getAttrs(temp);
|
|
nextIsBlock = (attrsTmp && attrsTmp->chCurFoc() == kNodeAttrs::blockNode);
|
|
while(!temp.isNull() && temp.hasChildNodes() && w->getAttrs(temp.firstChild()) &&
|
|
w->getAttrs(temp.firstChild())->chCurFoc() == kNodeAttrs::blockNode)
|
|
temp = temp.firstChild();
|
|
toplevelBlock2 = temp;
|
|
|
|
//2 - Determine the Nodes which could be moved
|
|
if(!toplevelBlock.isNull() && toplevelBlock.hasChildNodes())
|
|
endNode = toplevelBlock.lastChild();
|
|
else if(!childOfCommonParent2.isNull() && !childOfCommonParent2.previousSibling().isNull())
|
|
endNode = childOfCommonParent2.previousSibling();
|
|
temp = endNode;
|
|
while(!temp.isNull() && !temp.previousSibling().isNull() &&
|
|
((kafkaCommon::isInline(temp) && (temp.previousSibling().isNull() ||
|
|
kafkaCommon::isInline(temp.previousSibling()))) /**||
|
|
(!isInline(temp) && temp.previousSibling().isNull())*/))
|
|
temp = temp.previousSibling();
|
|
startNode = temp;
|
|
|
|
if(!toplevelBlock2.isNull() && toplevelBlock2.hasChildNodes())
|
|
startNode2 = toplevelBlock2.firstChild();
|
|
else if(!childOfCommonParent.isNull() && !childOfCommonParent.nextSibling().isNull())
|
|
startNode2 = childOfCommonParent.nextSibling();
|
|
startNode2IsNotInline = false;
|
|
temp = startNode2;
|
|
attrsTmp = w->getAttrs(temp);
|
|
if(attrsTmp && (attrsTmp->chCurFoc() == kNodeAttrs::singleNodeAndItself ||
|
|
attrsTmp->chCurFoc() == kNodeAttrs::no))
|
|
startNode2IsNotInline = true;
|
|
while(!temp.isNull() && !temp.nextSibling().isNull() &&
|
|
((kafkaCommon::isInline(temp) && (temp.nextSibling().isNull() ||
|
|
kafkaCommon::isInline(temp.nextSibling())))/** ||
|
|
(!isInline(temp) && temp.nextSibling().isNull())*/))
|
|
temp = temp.nextSibling();
|
|
endNode2 = temp;
|
|
|
|
//3 - Move Nodes.
|
|
if(!startNode2.isNull() && startNode2IsNotInline)
|
|
{
|
|
emit domNodeIsAboutToBeRemoved(startNode2, true, m_modifs);
|
|
startNode2.parentNode().removeChild(startNode2);
|
|
}
|
|
else if(isParent && !nextIsBlock)
|
|
{
|
|
if(kafkaCommon::parentSupports(toplevelBlock, startNode2, endNode2,
|
|
w->getCurrentDoc()->defaultDTD()))
|
|
moveDomNodes(toplevelBlock, startNode2, endNode2, DOM::Node(), false);
|
|
else
|
|
{
|
|
if(kafkaCommon::parentSupports(commonParent, startNode, endNode,
|
|
w->getCurrentDoc()->defaultDTD()))
|
|
moveDomNodes(commonParent, startNode, endNode, childOfCommonParent2,
|
|
true);
|
|
else
|
|
{
|
|
//Damn it! What to do??
|
|
}
|
|
}
|
|
}
|
|
else if(isParent && nextIsBlock)
|
|
{
|
|
if(kafkaCommon::parentSupports(toplevelBlock, startNode2, endNode2,
|
|
w->getCurrentDoc()->defaultDTD()))
|
|
moveDomNodes(toplevelBlock, startNode2, endNode2, DOM::Node(), false);
|
|
else
|
|
{
|
|
if(kafkaCommon::parentSupports(commonParent, startNode, endNode,
|
|
w->getCurrentDoc()->defaultDTD()) && kafkaCommon::parentSupports(
|
|
commonParent, startNode2, endNode2, w->getCurrentDoc()->defaultDTD()))
|
|
{
|
|
moveDomNodes(commonParent, startNode, endNode, childOfCommonParent,
|
|
false);
|
|
moveDomNodes(commonParent, startNode2, endNode2, childOfCommonParent2,
|
|
true);
|
|
}
|
|
else
|
|
{
|
|
//Damn it! What to do??
|
|
}
|
|
}
|
|
}
|
|
else if(!isParent && nextIsBlock)
|
|
{
|
|
if(kafkaCommon::parentSupports(commonParent, startNode2, endNode2,
|
|
w->getCurrentDoc()->defaultDTD()))
|
|
moveDomNodes(commonParent, startNode2, endNode2, childOfCommonParent2, true);
|
|
else
|
|
{
|
|
//Damn it! What to do??
|
|
}
|
|
}
|
|
if(!endNode.isNull())
|
|
normalize(endNode.parentNode());
|
|
|
|
//4 - Delete empty Block Nodes.
|
|
if(!toplevelBlock.isNull())
|
|
{
|
|
temp = toplevelBlock;
|
|
attrsTmp = w->getAttrs(temp);
|
|
while(attrsTmp && attrsTmp->chCurFoc() == kNodeAttrs::blockNode &&
|
|
!temp.hasChildNodes())
|
|
{
|
|
tempParent = temp.parentNode();
|
|
emit domNodeIsAboutToBeRemoved(temp, true, m_modifs);
|
|
tempParent.removeChild(temp);
|
|
temp = tempParent;
|
|
attrsTmp = w->getAttrs(temp);
|
|
}
|
|
}
|
|
if(!toplevelBlock2.isNull())
|
|
{
|
|
temp = toplevelBlock2;
|
|
attrsTmp = w->getAttrs(temp);
|
|
while(attrsTmp && attrsTmp->chCurFoc() == kNodeAttrs::blockNode &&
|
|
!temp.hasChildNodes())
|
|
{
|
|
tempParent = temp.parentNode();
|
|
emit domNodeIsAboutToBeRemoved(temp, true, m_modifs);
|
|
tempParent.removeChild(temp);
|
|
temp = tempParent;
|
|
attrsTmp = w->getAttrs(temp);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
//Else if the nextNode is a BLOCK, or an invisible Node, Inline Node
|
|
//which can be deleted, delete it!
|
|
else if(attrs->chCurFoc() == kNodeAttrs::singleNodeAndItself || ((attrs->chCurFoc() ==
|
|
kNodeAttrs::no || attrs->chCurFoc() == kNodeAttrs::inlineNode) &&
|
|
!_nodeNext.hasChildNodes()))
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::keyDelete() - deleting" <<
|
|
" a Node" << endl;
|
|
#endif
|
|
|
|
_nodeParent = _nodeNext.parentNode();
|
|
//If this block is used to define the cursor pos, change node to its parent.
|
|
if(_nodeNext == _node && _nodeParent.firstChild() == _nodeNext &&
|
|
_nodeNext.nextSibling().isNull())
|
|
{
|
|
_node = _nodeParent;
|
|
//d->m_cursorOffset = -2;
|
|
}
|
|
focus = w->getAttrs(_nodeNext)->chCurFoc();
|
|
emit domNodeIsAboutToBeRemoved(_nodeNext, true, m_modifs);
|
|
_nodeParent.removeChild(_nodeNext);
|
|
singleNodeDeleted = true;
|
|
_nodeNext = _node;
|
|
if(focus == kNodeAttrs::singleNodeAndItself)
|
|
{
|
|
normalize(_nodeParent);
|
|
break;
|
|
}
|
|
}
|
|
_nodeNext = getNextNode(_nodeNext, _goingTowardsRootNode);
|
|
}
|
|
|
|
//If the node which is defining the cursor position has been deleted (thus changed)
|
|
if(false && singleNodeDeleted)
|
|
{
|
|
//Now that we have deleted something, the cursor may end up in something weird, e.g.
|
|
//in an empty text or empty Inline. So delete them.
|
|
_nodeNext = _nodeParent;//<== !!!!
|
|
_nodeParent = _node.parentNode();
|
|
childPosition = -1;
|
|
while(!_nodeNext.isNull())
|
|
{
|
|
attrs = w->getAttrs(_nodeNext);
|
|
|
|
//If this Node can't be deleted, we stop here.
|
|
if(!attrs || !attrs->cbDel())
|
|
break;
|
|
|
|
//Let's delete useless Nodes
|
|
if((_nodeNext.nodeType() == DOM::Node::TEXT_NODE &&
|
|
(static_cast<DOM::CharacterData>(_nodeNext)).length() == 0) ||
|
|
(attrs->chCurFoc() == kNodeAttrs::inlineNode && _nodeNext.hasChildNodes())
|
|
)
|
|
{
|
|
childPosition = kafkaCommon::childPosition(_node);
|
|
_node = _nodeParent;
|
|
emit domNodeIsAboutToBeRemoved(_nodeNext, true, m_modifs);
|
|
_nodeParent.removeChild(_nodeNext);
|
|
normalize(_nodeParent);
|
|
}
|
|
else
|
|
break;
|
|
|
|
_nodeNext = _nodeParent;
|
|
}
|
|
|
|
//And finally, if the cursor is at a bad place (e.g. inside a Inline with childs), move it
|
|
attrs = w->getAttrs(_node);
|
|
while(attrs && attrs->chCurFoc() == kNodeAttrs::inlineNode && _node.hasChildNodes())
|
|
{
|
|
_node = kafkaCommon::getChildNode(_node, childPosition, true);
|
|
childPosition = 1;
|
|
}
|
|
}
|
|
|
|
/**m_currentNode = _node;
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset, m_modifs);*/
|
|
}
|
|
|
|
void KafkaWidget::keyBackspace()
|
|
{
|
|
kNodeAttrs *attrs, *attrsTmp;
|
|
int focus, m_currentNodeType;
|
|
DOM::Node _nodeParent, _node, _nodePrev, oldCurrentNode, temp, tempParent, prevSibling, nodePrevPrev;
|
|
DOM::Node toplevelBlock, toplevelBlock2, startNode, endNode, startNode2, endNode2;
|
|
DOM::Node childOfCommonParent, childOfCommonParent2, commonParent;
|
|
bool _goingTowardsRootNode, singleNodeDeleted, isParent, prevIsBlock, endNodeIsNotInline, boolTmp;
|
|
TQString text;
|
|
|
|
if(hasSelection())
|
|
{
|
|
removeSelection();
|
|
return;
|
|
}
|
|
|
|
if(m_currentNode.isNull())
|
|
return;
|
|
|
|
attrs = w->getAttrs(m_currentNode);
|
|
if(!attrs)
|
|
return;
|
|
m_currentNodeType = m_currentNode.nodeType();
|
|
|
|
#ifdef HEAVY_DEBUG
|
|
|
|
kdDebug(25001)<< "m_currentNode(" << m_currentNode.handle() << ") : " << m_currentNode.nodeName() <<
|
|
endl;
|
|
#endif
|
|
|
|
//OLD PART, to be removed or #ifdef'ed
|
|
if(attrs->chCurFoc() == kNodeAttrs::textNode && d->m_cursorOffset != 0)
|
|
{//if we are in the middle of some text, we remove one letter
|
|
if(!attrs->cbMod())
|
|
return;
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<< "KafkaWidget::keyBackspace() - one letter removed - 1" << endl;
|
|
#endif
|
|
|
|
DOM::DOMString nodeText = m_currentNode.nodeValue();
|
|
DOM::DOMString textSplitted = nodeText.split(d->m_cursorOffset);
|
|
nodeText.split(d->m_cursorOffset - 1);
|
|
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001) << nodeText.string() << textSplitted.string() << endl;
|
|
#endif
|
|
|
|
m_currentNode.setNodeValue(nodeText + textSplitted);
|
|
m_currentNode.parentNode().applyChanges();
|
|
--(d->m_cursorOffset);
|
|
emit domNodeModified(m_currentNode, m_modifs);
|
|
postprocessCursorPosition();
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
|
|
return;
|
|
}
|
|
if(attrs->chCurFoc() == kNodeAttrs::singleNodeAndItself &&
|
|
d->m_cursorOffset != 0)
|
|
{//if we delete ourselves, which node will be m_currentNode??
|
|
if(!attrs->cbDel())
|
|
return;
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<< "KafkaWidget::keyBackspace() - deleting a TagDeletable - 2" << endl;
|
|
#endif
|
|
|
|
DOM::Node _node = m_currentNode;
|
|
bool b = false;
|
|
while(1)
|
|
{//try to find a previous node from which we can delete the node
|
|
_node = getPrevNode(_node, b);
|
|
if(_node == 0)
|
|
break;
|
|
attrs = w->getAttrs(_node);
|
|
if(attrs && attrs->chCurFoc() == kNodeAttrs::textNode)
|
|
{
|
|
m_currentNode = _node;
|
|
d->m_cursorOffset = (static_cast<DOM::CharacterData>(_node)).length();
|
|
keyDelete();
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
|
|
return;
|
|
}
|
|
if(attrs && attrs->chCurFoc() != kNodeAttrs::no && attrs->chCurFoc() !=
|
|
kNodeAttrs::textNode)
|
|
{
|
|
m_currentNode = _node;
|
|
d->m_cursorOffset = 1;
|
|
keyDelete();
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
|
|
return;
|
|
}
|
|
}
|
|
_node = m_currentNode;
|
|
b = false;
|
|
while(1)
|
|
{//try to find a next node from which we can delete the node
|
|
_node = getNextNode(_node, b);
|
|
if(_node == 0)
|
|
break;
|
|
attrs = w->getAttrs(_node);
|
|
if(attrs && attrs->chCurFoc() != kNodeAttrs::no)
|
|
{
|
|
m_currentNode = _node;
|
|
d->m_cursorOffset = 0;
|
|
keyBackspace();
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
|
|
return;
|
|
}
|
|
}
|
|
//here, there is no node right and left that can have the cursor focus
|
|
_node = m_currentNode.parentNode();
|
|
emit domNodeIsAboutToBeRemoved(m_currentNode, true, m_modifs);
|
|
_node.removeChild(m_currentNode);
|
|
m_currentNode = document().createTextNode("");
|
|
_node.appendChild(m_currentNode);
|
|
emit domNodeInserted(m_currentNode, false, m_modifs);
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
|
|
|
|
}
|
|
|
|
//Beginning of the actual keyBackspace
|
|
_node = m_currentNode;
|
|
_goingTowardsRootNode = false;
|
|
singleNodeDeleted = false;
|
|
_nodePrev = getPrevNode(_node, _goingTowardsRootNode);
|
|
oldCurrentNode = m_currentNode;
|
|
|
|
while(!_nodePrev.isNull())
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::keyBackspace() - currentNode: " <<
|
|
_nodePrev.nodeName().string() << endl;
|
|
#endif
|
|
|
|
attrs = w->getAttrs(_nodePrev);
|
|
if(!attrs)
|
|
{
|
|
kdError(25001) << "NULL kNodeAttrs instance: attrs = w->getAttrs(_nodePrev);" << endl;
|
|
kafkaCommon::coutDomTree(_nodePrev, 3);
|
|
return;
|
|
// FIXME Understand why this happen.
|
|
// Test case:
|
|
// 1. Write two words in a new VPL document and make the first one a link;
|
|
// 2. Put the cursor at most right and then press backspace until it crashes
|
|
// When you get to the link the cursor stays in the same plave and you have press it several times until it crashes.
|
|
}
|
|
|
|
//If this Node can't be deleted, we stop here.
|
|
if(!attrs->cbDel())
|
|
return;
|
|
|
|
//If we are in a TEXT node, we remove a letter
|
|
if(attrs->chCurFoc() == kNodeAttrs::textNode)
|
|
{
|
|
if((static_cast<DOM::CharacterData>(_nodePrev)).length() != 0)
|
|
{//if we are in text, remove a letter
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::keyBackspace() - one" <<
|
|
" letter removed - 2" << endl;
|
|
#endif
|
|
|
|
DOM::DOMString nodeText = _nodePrev.nodeValue();
|
|
nodeText.split((static_cast<DOM::CharacterData>(_nodePrev)).length() - 1);
|
|
_nodePrev.setNodeValue(nodeText);
|
|
_nodePrev.parentNode().applyChanges();
|
|
|
|
m_currentNode = _nodePrev;
|
|
d->m_cursorOffset = (static_cast<DOM::CharacterData>(_nodePrev)).length();
|
|
|
|
postprocessCursorPosition();
|
|
emit domNodeModified(_nodePrev, m_modifs);
|
|
return;
|
|
}
|
|
else
|
|
{//if we are in an empty text
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::keyBackspace() - deleting" <<
|
|
" empty #text" << endl;
|
|
#endif
|
|
|
|
_nodeParent = _nodePrev.parentNode();
|
|
emit domNodeIsAboutToBeRemoved(_nodePrev, true, m_modifs);
|
|
_nodeParent.removeChild(_nodePrev);
|
|
_nodeParent.applyChanges();
|
|
_nodePrev = _node;
|
|
continue;
|
|
}
|
|
}
|
|
//Else if the current Node if a BLOCK which can be entered/leaved e.g. H1, P
|
|
else if(attrs->chCurFoc() == kNodeAttrs::blockNode)
|
|
{
|
|
//First look if it is one of _node's parent
|
|
isParent = false;
|
|
temp = _node;
|
|
while(!temp.isNull())
|
|
{
|
|
if(_nodePrev == temp)
|
|
isParent = true;
|
|
temp = temp.parentNode();
|
|
}
|
|
|
|
//1 - Locate the toplevel blocks
|
|
temp = _nodePrev;
|
|
if(isParent)
|
|
{
|
|
toplevelBlock2 = temp;
|
|
while(temp.parentNode().firstChild() == temp && w->getAttrs(temp.parentNode()) &&
|
|
w->getAttrs(temp.parentNode())->chCurFoc() == kNodeAttrs::blockNode)
|
|
temp = temp.parentNode();
|
|
childOfCommonParent2 = temp;
|
|
temp = temp.previousSibling();
|
|
}
|
|
if(temp.isNull())
|
|
break;
|
|
childOfCommonParent = temp;
|
|
commonParent = temp.parentNode();
|
|
attrsTmp = w->getAttrs(temp);
|
|
prevIsBlock = (attrsTmp && attrsTmp->chCurFoc() == kNodeAttrs::blockNode);
|
|
while(!temp.isNull() && temp.hasChildNodes() && w->getAttrs(temp.lastChild()) &&
|
|
w->getAttrs(temp.lastChild())->chCurFoc() == kNodeAttrs::blockNode)
|
|
temp = temp.lastChild();
|
|
toplevelBlock = temp;
|
|
|
|
//2 - Determine the Nodes which could be moved
|
|
if(!toplevelBlock.isNull() && toplevelBlock.hasChildNodes())
|
|
endNode = toplevelBlock.lastChild();
|
|
else if(!childOfCommonParent2.isNull() && !childOfCommonParent2.previousSibling().isNull())
|
|
endNode = childOfCommonParent2.previousSibling();
|
|
endNodeIsNotInline = false;
|
|
temp = endNode;
|
|
attrsTmp = w->getAttrs(temp);
|
|
if(attrsTmp && (attrsTmp->chCurFoc() == kNodeAttrs::singleNodeAndItself ||
|
|
attrs->chCurFoc() == kNodeAttrs::no))
|
|
endNodeIsNotInline = true;
|
|
while(!temp.isNull() && !temp.previousSibling().isNull() &&
|
|
((kafkaCommon::isInline(temp) && (temp.previousSibling().isNull() ||
|
|
kafkaCommon::isInline(temp.previousSibling())))))
|
|
temp = temp.previousSibling();
|
|
startNode = temp;
|
|
|
|
if(!toplevelBlock2.isNull() && toplevelBlock2.hasChildNodes())
|
|
startNode2 = toplevelBlock2.firstChild();
|
|
else if(!childOfCommonParent.isNull() && !childOfCommonParent.nextSibling().isNull())
|
|
startNode2 = childOfCommonParent.nextSibling();
|
|
temp = startNode2;
|
|
while(!temp.isNull() && !temp.nextSibling().isNull() &&
|
|
((kafkaCommon::isInline(temp) && (temp.nextSibling().isNull() ||
|
|
kafkaCommon::isInline(temp.nextSibling())))))
|
|
temp = temp.nextSibling();
|
|
endNode2 = temp;
|
|
|
|
//3 - Move Nodes.
|
|
if(!endNode.isNull() && endNodeIsNotInline)
|
|
{
|
|
emit domNodeIsAboutToBeRemoved(endNode, true, m_modifs);
|
|
endNode.parentNode().removeChild(endNode);
|
|
}
|
|
else if(isParent && !prevIsBlock)
|
|
{
|
|
if(kafkaCommon::parentSupports(toplevelBlock2, startNode, endNode,
|
|
w->getCurrentDoc()->defaultDTD()))
|
|
moveDomNodes(toplevelBlock2, startNode, endNode, toplevelBlock2.firstChild(),
|
|
true);
|
|
else
|
|
{
|
|
if(kafkaCommon::parentSupports(commonParent, startNode2, endNode2,
|
|
w->getCurrentDoc()->defaultDTD()))
|
|
moveDomNodes(commonParent, startNode2, endNode2,
|
|
childOfCommonParent2, true);
|
|
else
|
|
{
|
|
//Damn it! What to do??
|
|
}
|
|
}
|
|
}
|
|
else if(isParent && prevIsBlock)
|
|
{
|
|
if(kafkaCommon::parentSupports(toplevelBlock2, startNode, endNode,
|
|
w->getCurrentDoc()->defaultDTD()))
|
|
moveDomNodes(toplevelBlock2, startNode, endNode, toplevelBlock2.firstChild(),
|
|
true);
|
|
else
|
|
{
|
|
if(kafkaCommon::parentSupports(commonParent, startNode, endNode,
|
|
w->getCurrentDoc()->defaultDTD()) && kafkaCommon::parentSupports(
|
|
commonParent, startNode2, endNode2, w->getCurrentDoc()->defaultDTD()))
|
|
{
|
|
moveDomNodes(commonParent, startNode, endNode, childOfCommonParent,
|
|
false);
|
|
moveDomNodes(commonParent, startNode2, endNode2, childOfCommonParent2,
|
|
true);
|
|
}
|
|
else
|
|
{
|
|
//Damn it! What to do??
|
|
}
|
|
}
|
|
}
|
|
else if(!isParent && prevIsBlock)
|
|
{
|
|
if(kafkaCommon::parentSupports(commonParent, startNode, endNode,
|
|
w->getCurrentDoc()->defaultDTD()))
|
|
moveDomNodes(commonParent, startNode, endNode, childOfCommonParent, false);
|
|
else
|
|
{
|
|
//Damn it! What to do??
|
|
}
|
|
}
|
|
if(!startNode2.isNull() && startNode2.nodeType() == DOM::Node::TEXT_NODE)
|
|
{
|
|
//normalize(startNode2.parentNode());
|
|
temp = startNode2.previousSibling();
|
|
if(!temp.isNull() && temp.nodeType() == DOM::Node::TEXT_NODE)
|
|
{
|
|
boolTmp = false;
|
|
if(m_currentNode == startNode2)
|
|
{
|
|
m_currentNode = temp;
|
|
d->m_cursorOffset += temp.nodeValue().length();
|
|
boolTmp = true;
|
|
}
|
|
text = temp.nodeValue().string() + startNode2.nodeValue().string();
|
|
tempParent = temp.parentNode();
|
|
emit domNodeIsAboutToBeRemoved(startNode2, true, m_modifs);
|
|
tempParent.removeChild(startNode2);
|
|
|
|
temp.setNodeValue(text);
|
|
emit domNodeModified(temp, m_modifs);
|
|
|
|
if(boolTmp)
|
|
TQTimer::singleShot(0, this, TQT_SLOT(slotDelayedSetCaretPosition()));
|
|
}
|
|
|
|
}
|
|
|
|
//4 - Delete empty Block Nodes.
|
|
if(!toplevelBlock.isNull())
|
|
{
|
|
temp = toplevelBlock;
|
|
attrsTmp = w->getAttrs(temp);
|
|
while(attrsTmp && attrsTmp->chCurFoc() == kNodeAttrs::blockNode &&
|
|
!temp.hasChildNodes())
|
|
{
|
|
tempParent = temp.parentNode();
|
|
emit domNodeIsAboutToBeRemoved(temp, true, m_modifs);
|
|
tempParent.removeChild(temp);
|
|
temp = tempParent;
|
|
attrsTmp = w->getAttrs(temp);
|
|
}
|
|
}
|
|
if(!toplevelBlock2.isNull())
|
|
{
|
|
temp = toplevelBlock2;
|
|
attrsTmp = w->getAttrs(temp);
|
|
while(attrsTmp && attrsTmp->chCurFoc() == kNodeAttrs::blockNode &&
|
|
!temp.hasChildNodes())
|
|
{
|
|
tempParent = temp.parentNode();
|
|
emit domNodeIsAboutToBeRemoved(temp, true, m_modifs);
|
|
tempParent.removeChild(temp);
|
|
temp = tempParent;
|
|
attrsTmp = w->getAttrs(temp);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
//Else if the prevNode is a BLOCK or an invisible Node, Inline Node
|
|
//which can be deleted, delete it!
|
|
else if(attrs->chCurFoc() == kNodeAttrs::singleNodeAndItself || ((attrs->chCurFoc() ==
|
|
kNodeAttrs::no || attrs->chCurFoc() == kNodeAttrs::inlineNode) &&
|
|
!_nodePrev.hasChildNodes()))
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::keyBackspace() - deleting" <<
|
|
" a Node" << endl;
|
|
#endif
|
|
|
|
_nodeParent = _nodePrev.parentNode();
|
|
focus = w->getAttrs(_nodePrev)->chCurFoc();
|
|
emit domNodeIsAboutToBeRemoved(_nodePrev, true, m_modifs);
|
|
_nodeParent.removeChild(_nodePrev);
|
|
//normalize(_nodeParent);
|
|
if(focus == kNodeAttrs::singleNodeAndItself)
|
|
{
|
|
postprocessCursorPosition();
|
|
//merge the previous DOM::Node if it is a text.
|
|
//domNodeIsAboutToBeRemoved() already do it in the Node tree.
|
|
//=> It seems it was removed from it.
|
|
_nodePrev = _node.previousSibling();
|
|
if(!_nodePrev.isNull() && _nodePrev.nodeType() == DOM::Node::TEXT_NODE &&
|
|
m_currentNodeType == DOM::Node::TEXT_NODE)
|
|
{
|
|
if(_node == m_currentNode)
|
|
{
|
|
m_currentNode = _nodePrev;
|
|
d->m_cursorOffset += (static_cast<DOM::CharacterData>(_nodePrev)).length();
|
|
TQTimer::singleShot(0, this, TQT_SLOT(slotDelayedSetCaretPosition()));
|
|
}
|
|
_nodePrev.setNodeValue(_nodePrev.nodeValue() + _node.nodeValue());
|
|
emit domNodeModified(_nodePrev, m_modifs);
|
|
//_nodeParent = _nodePrev.parentNode();
|
|
emit domNodeIsAboutToBeRemoved(_node, true, m_modifs);
|
|
_nodeParent.removeChild(_node);
|
|
}
|
|
//dirty workaround when after having deleted a br, there is only one br left
|
|
//Anyway webcore will override this
|
|
if(m_currentNode.nodeName().string().lower() == "br" &&
|
|
(m_currentNode.previousSibling().isNull() || (m_currentNode.previousSibling().nodeType() ==
|
|
DOM::Node::TEXT_NODE && m_currentNode.previousSibling().previousSibling().isNull())) &&
|
|
(m_currentNode.nextSibling().isNull() || (m_currentNode.nextSibling().nodeType() ==
|
|
DOM::Node::TEXT_NODE && m_currentNode.nextSibling().nextSibling().isNull())))
|
|
{
|
|
if(!m_currentNode.previousSibling().isNull())
|
|
{
|
|
m_currentNode = m_currentNode.previousSibling();
|
|
d->m_cursorOffset = 0;
|
|
|
|
TQTimer::singleShot(0, this, TQT_SLOT(slotDelayedSetCaretPosition()));
|
|
}
|
|
else if(!m_currentNode.nextSibling().isNull())
|
|
{
|
|
m_currentNode = m_currentNode.nextSibling();
|
|
d->m_cursorOffset = 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
_nodePrev = _node;
|
|
}
|
|
_nodePrev = getPrevNode(_nodePrev, _goingTowardsRootNode);
|
|
}
|
|
}
|
|
|
|
DOM::Node KafkaWidget::getNextNode(DOM::Node _node, bool &goingTowardsRootNode, bool skipParentNodes, bool dontBlock, DOM::Node _endNode)
|
|
{
|
|
kNodeAttrs *attrs = 0L;
|
|
|
|
if(_node == 0)
|
|
return 0;
|
|
attrs = w->getAttrs(_node);
|
|
if(!attrs)
|
|
{
|
|
kdDebug(25001)<< "KafkaWidget::getNextNode() Attrs not found!"<< endl;
|
|
return 0;
|
|
}
|
|
if(_node.hasChildNodes() && goingTowardsRootNode == false &&
|
|
(attrs->ccanEnter() || dontBlock))
|
|
{//if we can descend to a child node, we do it
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::getNextNode() - descending from node : " <<
|
|
_node.nodeName().string() << " to " <<
|
|
_node.firstChild().nodeName().string() << endl;
|
|
#endif
|
|
|
|
if(_endNode == _node.firstChild())
|
|
return 0;
|
|
return _node.firstChild();
|
|
}
|
|
if(_node.nextSibling() != 0)
|
|
{//else if there is a sibling, we move to it
|
|
goingTowardsRootNode = false;
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<< "KafkaWidget::getNextNode() - going from node : " <<
|
|
_node.nodeName().string() <<
|
|
" to " << _node.nextSibling().nodeName().string() << endl;
|
|
#endif
|
|
|
|
if(_endNode == _node.nextSibling())
|
|
return 0;
|
|
return _node.nextSibling();
|
|
}
|
|
if(_node.nextSibling() == 0)
|
|
{//else if there is no sibling, we go up if we can
|
|
goingTowardsRootNode = true;
|
|
if(_node.parentNode().isNull())
|
|
return 0;
|
|
if(w->getAttrs(_node.parentNode()) &&
|
|
w->getAttrs(_node.parentNode())->ccanEnter() || dontBlock)
|
|
{
|
|
if(!_node.parentNode().isNull())
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::getNextNode() - going" <<
|
|
" up from node : " << _node.nodeName().string() <<
|
|
" to " << _node.parentNode().nodeName().string() << endl;
|
|
#endif
|
|
|
|
}
|
|
else
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::getNextNode() - going" <<
|
|
" up from node : " << _node.nodeName().string() <<
|
|
" to an empty Node" << endl;
|
|
#endif
|
|
|
|
}
|
|
if(skipParentNodes)
|
|
{
|
|
if(_endNode == _node.parentNode())
|
|
return 0;
|
|
return getNextNode(_node.parentNode(), goingTowardsRootNode,
|
|
skipParentNodes, dontBlock);
|
|
}
|
|
else
|
|
{
|
|
if(_endNode == _node.parentNode())
|
|
return 0;
|
|
return _node.parentNode();
|
|
}
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
kdError()<< "KafkaWidget::getNextNode() ERROR" << endl;
|
|
return 0;
|
|
}
|
|
|
|
DOM::Node KafkaWidget::getPrevNode(DOM::Node _node, bool &goingTowardsRootNode, bool skipParentNodes, bool dontBlock, DOM::Node _endNode)
|
|
{
|
|
kNodeAttrs *attrs = 0L;
|
|
|
|
if(_node == 0)
|
|
return 0;
|
|
attrs = w->getAttrs(_node);
|
|
if(!attrs)
|
|
{
|
|
kdDebug(25001)<< "KafkaWidget::getPrevNode() Attrs not found!"<< endl;
|
|
return 0;
|
|
}
|
|
if(_node.hasChildNodes() && goingTowardsRootNode == false &&
|
|
(attrs->ccanEnter() || dontBlock))
|
|
{//if we can descend to a child node, we do it
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::getPrevNode() - descending from node : " <<
|
|
_node.nodeName().string() << " to " <<
|
|
_node.lastChild().nodeName().string() << endl;
|
|
#endif
|
|
|
|
if(_endNode == _node.lastChild())
|
|
return DOM::Node();
|
|
return _node.lastChild();
|
|
}
|
|
if(_node.previousSibling() != 0)
|
|
{//else if there is a sibling, we move to it
|
|
goingTowardsRootNode = false;
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<< "KafkaWidget::getPrevNode() - going from node : " <<
|
|
_node.nodeName().string() <<
|
|
" to " << _node.previousSibling().nodeName().string() << endl;
|
|
#endif
|
|
|
|
if(_endNode == _node.previousSibling())
|
|
return DOM::Node();
|
|
return _node.previousSibling();
|
|
}
|
|
if(_node.previousSibling() == 0)
|
|
{//else if there is no sibling, we go up if we can
|
|
goingTowardsRootNode = true;
|
|
if(_node.parentNode().isNull())
|
|
return DOM::Node();
|
|
if(w->getAttrs(_node.parentNode()) &&
|
|
w->getAttrs(_node.parentNode())->ccanEnter() || dontBlock)
|
|
{
|
|
if(!_node.parentNode().isNull())
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::getPrevNode() - going up from" <<
|
|
" node : " << _node.nodeName().string() << " to " <<
|
|
_node.parentNode().nodeName().string() << endl;
|
|
#endif
|
|
|
|
}
|
|
else
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::getPrevNode() - going up from" <<
|
|
" node : " << _node.nodeName().string() << " to an " <<
|
|
"empty Node" << endl;
|
|
#endif
|
|
|
|
}
|
|
if (skipParentNodes)
|
|
{
|
|
if(_endNode == _node.parentNode())
|
|
return DOM::Node();
|
|
return getPrevNode(_node.parentNode(), goingTowardsRootNode,
|
|
skipParentNodes, dontBlock);
|
|
}
|
|
else
|
|
{
|
|
if(_endNode == _node.parentNode())
|
|
return DOM::Node();
|
|
return _node.parentNode();
|
|
}
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
kdError()<< "KafkaWidget::getPrevNode() ERROR" << endl;
|
|
return 0;
|
|
}
|
|
|
|
void KafkaWidget::updateToggableTagActions(/*const DOM::Node &domNode, long offset*/) const
|
|
{
|
|
//Andras: Disable toggle behavior. It is just too broken.
|
|
return;
|
|
|
|
quantaApp->removeAllTagActionPoolItems();
|
|
|
|
NodeSelectionInd selection;
|
|
selection.fillWithVPLCursorSelection();
|
|
|
|
Node* start_node = 0, *end_node = 0;
|
|
// int start_offset = 0, end_offset = 0;
|
|
|
|
start_node = kafkaCommon::getNodeFromLocation(selection.cursorNode());
|
|
// start_offset = selection.cursorOffset();
|
|
|
|
if(!start_node)
|
|
return;
|
|
|
|
if(selection.hasSelection())
|
|
{
|
|
end_node = kafkaCommon::getNodeFromLocation(selection.cursorNodeEndSel());
|
|
// end_offset = selection.cursorOffsetEndSel();
|
|
}
|
|
else
|
|
{
|
|
end_node = start_node;
|
|
// end_offset = start_offset;
|
|
}
|
|
|
|
// Iterate all toggable toolbar actions and toggle them on or off
|
|
// Look if there is a selection
|
|
TagAction* tag_action = 0;
|
|
TQPtrList<TagAction> tag_actions = quantaApp->tagActions();
|
|
for (tag_action = tag_actions.first(); tag_action; tag_action = tag_actions.next())
|
|
{
|
|
if(tag_action->toggable())
|
|
{
|
|
TQString tag_name = tag_action->XMLTagName();
|
|
if(tag_name.isEmpty())
|
|
break;
|
|
|
|
TQDomElement data(tag_action->data());
|
|
TQString attribute_name(data.attribute("attribute_name", TQString()));
|
|
TQString attribute_value(data.attribute("attribute_value", TQString()));
|
|
|
|
int inside_tag;
|
|
if(!attribute_name.isEmpty() && !attribute_value.isEmpty())
|
|
inside_tag = kafkaCommon::isInsideTag(start_node, end_node, tag_name, attribute_name, attribute_value);
|
|
else
|
|
inside_tag = kafkaCommon::isInsideTag(start_node, end_node, tag_name);
|
|
|
|
tag_action->setChecked(inside_tag == 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void KafkaWidget::makeCursorVisible(int , int )
|
|
{
|
|
/**DOM::Range range;
|
|
if(m_currentNode == 0)
|
|
return;
|
|
kdDebug(25001)<< "KafkaWidget::makeCursorVisible()" << endl;
|
|
int X, Y, dummy;
|
|
getCursor(m_currentNode, d->m_cursorOffset, X, Y, dummy);
|
|
view()->ensureVisible (X, Y, xMargin, yMargin);*/
|
|
//does not work... ???
|
|
/**range = selection();
|
|
//try{
|
|
range.setStart(m_currentNode, d->m_cursorOffset);
|
|
}
|
|
catch(DOM::RangeException e)
|
|
{
|
|
//ignore
|
|
kdDebug(25001)<< "KafkaWidget::makeCursorVisible() - ERROR " << e.code << endl;
|
|
return;
|
|
}
|
|
catch(DOM::DOMException e)
|
|
{
|
|
kdDebug(25001)<< "KafkaWidget::makeCursorVisible() - ERROR " << e.code << endl;
|
|
}*/
|
|
//range.setEnd(m_currentNode, d->m_cursorOffset);
|
|
}
|
|
|
|
void KafkaWidget::postprocessCursorPosition()
|
|
{
|
|
kNodeAttrs *attrs, *attrs2;
|
|
if(m_currentNode == 0)
|
|
return;
|
|
attrs = w->getAttrs(m_currentNode);
|
|
DOM::Node _prevNextNode;
|
|
DOM::Node _nextNode = m_currentNode;
|
|
bool b = false;
|
|
|
|
if(!attrs)
|
|
{
|
|
#ifdef LIGHT_DEBUG
|
|
kdDebug(25001)<< "KafkaWidget::postprocessCursorPosition() - WARNING no Attrs!! " << endl;
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
if(attrs->chCurFoc() == kNodeAttrs::textNode &&
|
|
d->m_cursorOffset == 0)
|
|
{
|
|
/** while(1)
|
|
{
|
|
_prevNextNode = _nextNode;
|
|
_nextNode = kafkaCommon::getPrevDomNode(_nextNode);
|
|
if(_nextNode.isNull())
|
|
break;
|
|
attrs2 = w->getAttrs(_nextNode);
|
|
if(attrs2 && attrs2->chCurFoc() == kNodeAttrs::textNode &&
|
|
(static_cast<DOM::CharacterData>(_nextNode)).length() != 0)
|
|
{
|
|
m_currentNode = _nextNode;
|
|
d->m_cursorOffset = (static_cast<DOM::CharacterData>(_nextNode)).length();
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<< "KafkaWidget::postprocessCursorPosition()" <<
|
|
" - new currentNode :" <<
|
|
m_currentNode.nodeName().string() << endl;
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
else if(attrs2->chCurFoc() == kNodeAttrs::singleNodeAndItself ||
|
|
attrs2->chCurFoc() == kNodeAttrs::inlineNode ||
|
|
attrs2->chCurFoc() == kNodeAttrs::blockNode)
|
|
break;
|
|
else
|
|
continue;
|
|
}*/
|
|
}
|
|
else if(attrs->chCurFoc() == kNodeAttrs::singleNodeAndItself)
|
|
{
|
|
if(d->m_cursorOffset == 0 && !m_currentNode.isNull() &&
|
|
(m_currentNode.nodeName().string().lower() != "br" ||
|
|
(m_currentNode.nodeName().string().lower() == "br" && /**!m_currentNode.nextSibling().isNull() &&
|
|
m_currentNode.nextSibling().nodeType() == DOM::Node::TEXT_NODE &&
|
|
m_currentNode.nextSibling().nodeValue().string().isEmpty() &&
|
|
m_currentNode.nextSibling().nextSibling().isNull() &&*/
|
|
!m_currentNode.previousSibling().isNull() &&
|
|
m_currentNode.previousSibling().nodeType() == DOM::Node::TEXT_NODE &&
|
|
!m_currentNode.previousSibling().nodeValue().string().isEmpty())))
|
|
{
|
|
while(1)
|
|
{
|
|
_prevNextNode = _nextNode;
|
|
_nextNode = getPrevNode(_nextNode, b);
|
|
if(_nextNode == 0)
|
|
break;
|
|
attrs2 = w->getAttrs(_nextNode);
|
|
if(attrs2 && attrs2->chCurFoc() == kNodeAttrs::textNode &&
|
|
(static_cast<DOM::CharacterData>(_nextNode)).length()
|
|
!= 0)
|
|
{
|
|
m_currentNode = _nextNode;
|
|
d->m_cursorOffset = (static_cast<DOM::CharacterData>(_nextNode)).length();
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<< "KafkaWidget::postprocessCursorPosition()" <<
|
|
" - new currentNode :" << m_currentNode.nodeName().string() << endl;
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
else if(attrs2 && attrs2->chCurFoc() == kNodeAttrs::singleNodeAndItself)
|
|
{
|
|
m_currentNode = _nextNode;
|
|
d->m_cursorOffset = 1;
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<< "KafkaWidget::postprocessCursorPosition()" <<
|
|
" - new currentNode :" << m_currentNode.nodeName().string() << endl;
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
else
|
|
continue;
|
|
}
|
|
}
|
|
else if(d->m_cursorOffset == 1)
|
|
{
|
|
while(1)
|
|
{
|
|
_prevNextNode = _nextNode;
|
|
_nextNode = getNextNode(_nextNode, b);
|
|
if(_nextNode == 0)
|
|
break;
|
|
attrs2 = w->getAttrs(_nextNode);
|
|
if(attrs2 && attrs2->chCurFoc() == kNodeAttrs::singleNodeAndItself)
|
|
break;
|
|
else if(attrs2 && attrs2->chCurFoc() == kNodeAttrs::textNode &&
|
|
(static_cast<DOM::CharacterData>(_nextNode)).length() != 0)
|
|
{
|
|
m_currentNode = _nextNode;
|
|
d->m_cursorOffset = 0;
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<< "KafkaWidget::postprocessCursorPosition() " <<
|
|
"- new currentNode :" << m_currentNode.nodeName().string() << endl;
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
else
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
makeCursorVisible();
|
|
}
|
|
|
|
void KafkaWidget::tdehtmlMouseMoveEvent(tdehtml::MouseMoveEvent *event)
|
|
{
|
|
DOM::Node mouseNode = event->innerNode();
|
|
|
|
if(mouseNode == 0)
|
|
{
|
|
return;
|
|
}
|
|
if(mouseNode.nodeType() == DOM::Node::TEXT_NODE)
|
|
view()->setCursor(TQt::ibeamCursor);
|
|
else
|
|
view()->setCursor(TQt::arrowCursor);
|
|
|
|
TDEHTMLPart::tdehtmlMouseMoveEvent(event);
|
|
}
|
|
|
|
void KafkaWidget::tdehtmlMouseReleaseEvent(tdehtml::MouseReleaseEvent *event)
|
|
{
|
|
TDEHTMLPart::tdehtmlMouseReleaseEvent(event);
|
|
if(m_currentNode.isNull() || m_currentNode.nodeName().string().lower() == "#document")
|
|
{
|
|
m_currentNode = w->body;
|
|
d->m_cursorOffset = 0;
|
|
setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
}
|
|
if(quantaApp->aTab)
|
|
quantaApp->aTab->setCurrentNode(w->getNode(event->innerNode()));
|
|
}
|
|
|
|
void KafkaWidget::tdehtmlMousePressEvent(tdehtml::MousePressEvent *event)
|
|
{
|
|
TDEHTMLPart::tdehtmlMousePressEvent(event);
|
|
if(d->m_cursorOffset == 0 && !m_currentNode.isNull() &&
|
|
m_currentNode.nodeName().string().lower() == "body")
|
|
putCursorAtFirstAvailableLocation();
|
|
#ifdef HEAVY_DEBUG
|
|
//d->domdialog->domview->showTree(document());
|
|
#endif
|
|
|
|
}
|
|
|
|
void KafkaWidget::tdehtmlDrawContentsEvent(tdehtml::DrawContentsEvent *event)
|
|
{
|
|
TDEHTMLPart::tdehtmlDrawContentsEvent(event);
|
|
}
|
|
|
|
void KafkaWidget::getCurrentNode(DOM::Node &_currentNode, long &offset)
|
|
{
|
|
_currentNode = m_currentNode;
|
|
offset = d->m_cursorOffset;
|
|
}
|
|
|
|
void KafkaWidget::setCurrentNode(DOM::Node node, int offset)
|
|
{
|
|
m_currentNode = node;
|
|
d->m_cursorOffset = offset;
|
|
makeCursorVisible();
|
|
if(!m_currentNode.isNull() && m_currentNode.nodeName().string() != "#document")
|
|
TQTimer::singleShot(0, this, TQT_SLOT(slotDelayedSetCaretPosition()));
|
|
//setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
|
|
}
|
|
|
|
void KafkaWidget::setCurrentNode(Node* cursorNode, int cursorOffset)
|
|
{
|
|
DOM::Node domNode;
|
|
long longDomNodeOffset;
|
|
KafkaDocument::ref()->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())
|
|
setCurrentNode(domNode, (int)longDomNodeOffset);
|
|
}
|
|
|
|
void KafkaWidget::putCursorAtFirstAvailableLocation()
|
|
{
|
|
kNodeAttrs *attrs = 0L;
|
|
DOM::Node node = w->body;
|
|
bool b = false;
|
|
|
|
#ifdef HEAVY_DEBUG
|
|
|
|
w->coutLinkTree(baseNode, 2);
|
|
kafkaCommon::coutTree(baseNode, 2);
|
|
kafkaCommon::coutDomTree(document(), 2);
|
|
#endif
|
|
|
|
while(!node.isNull())
|
|
{
|
|
node = kafkaCommon::getNextDomNode(node, b);
|
|
if(node.isNull())
|
|
{
|
|
if(!w->body.isNull())
|
|
node = w->body;
|
|
else
|
|
node = DOM::Node();
|
|
break;
|
|
}
|
|
attrs = w->getAttrs(node);
|
|
if(!attrs)
|
|
{
|
|
node = w->body;
|
|
break;
|
|
}
|
|
if(node.nodeType() == DOM::Node::TEXT_NODE)
|
|
break;
|
|
}
|
|
m_currentNode = node;
|
|
d->m_cursorOffset = 0;
|
|
TQTimer::singleShot(0, this, TQT_SLOT(slotDelayedSetCaretPosition()));
|
|
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
if(!m_currentNode.isNull())
|
|
kdDebug(25001)<< "KafkaWidget::putCursorAtFirstAvailableLocation() - " <<
|
|
m_currentNode.nodeName().string() << endl;
|
|
#endif
|
|
|
|
}
|
|
|
|
void KafkaWidget::slotNewCursorPos(const DOM::Node &domNode, long offset)
|
|
{
|
|
if(!w->isLoaded())
|
|
return;
|
|
|
|
m_currentNode = domNode;
|
|
d->m_cursorOffset = (int)offset;
|
|
#ifdef LIGHT_DEBUG
|
|
|
|
kdDebug(25001)<<"KafkaWidget::slotNewCursorPos() offset : " << d->m_cursorOffset << endl;
|
|
#endif
|
|
|
|
if(quantaApp->aTab && ViewManager::ref()->activeView()->hadLastFocus() == QuantaView::VPLFocus)
|
|
quantaApp->aTab->setCurrentNode(w->getNode(domNode));
|
|
|
|
updateToggableTagActions(/*domNode, offset*/);
|
|
}
|
|
|
|
void KafkaWidget::moveDomNodes(DOM::Node newParent, DOM::Node startNode, DOM::Node endNode,
|
|
DOM::Node refNode, bool before)
|
|
{
|
|
DOM::Node domNode, domNodeNext;
|
|
|
|
if(newParent.isNull())
|
|
return;
|
|
|
|
if(before)
|
|
{
|
|
domNode = endNode;
|
|
while(!domNode.isNull())
|
|
{
|
|
domNodeNext = domNode.previousSibling();
|
|
emit domNodeIsAboutToBeMoved(domNode, newParent, refNode, m_modifs);
|
|
//emit domNodeIsAboutToBeRemoved(domNode, true);
|
|
domNode = domNode.parentNode().removeChild(domNode);
|
|
if(!refNode.isNull())
|
|
newParent.insertBefore(domNode, refNode);
|
|
else
|
|
newParent.insertBefore(domNode, DOM::Node());
|
|
//emit domNodeInserted(domNode, true);
|
|
if(domNode == startNode)
|
|
break;
|
|
domNode = domNodeNext;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
domNode = startNode;
|
|
while(!domNode.isNull())
|
|
{
|
|
domNodeNext = domNode.nextSibling();
|
|
//emit domNodeIsAboutToBeRemoved(domNode, true);
|
|
if(!refNode.isNull())
|
|
emit domNodeIsAboutToBeMoved(domNode, newParent, refNode.nextSibling(), m_modifs);
|
|
else
|
|
emit domNodeIsAboutToBeMoved(domNode, newParent, DOM::Node(), m_modifs);
|
|
domNode = domNode.parentNode().removeChild(domNode);
|
|
if(!refNode.isNull())
|
|
newParent.insertBefore(domNode, refNode.nextSibling());
|
|
else
|
|
newParent.insertBefore(domNode, DOM::Node());
|
|
//emit domNodeInserted(domNode, true);
|
|
if(domNode == endNode)
|
|
break;
|
|
domNode = domNodeNext;
|
|
}
|
|
}
|
|
}
|
|
|
|
void KafkaWidget::removeSelection()
|
|
{
|
|
Q_ASSERT(hasSelection());
|
|
|
|
NodeSelectionInd selection;
|
|
selection.fillWithVPLCursorSelection();
|
|
Node* cursorNode = kafkaCommon::getNodeFromLocation(selection.cursorNode());
|
|
long cursorOffset = 0;
|
|
long domNodeCursorOffset = 0;
|
|
|
|
kafkaCommon::DTDRemoveSelection(selection, &cursorNode, cursorOffset, m_modifs);
|
|
|
|
KafkaDocument::ref()->translateNodeIntoKafkaCursorPosition(cursorNode, cursorOffset, m_currentNode, domNodeCursorOffset);
|
|
d->m_cursorOffset = domNodeCursorOffset;
|
|
|
|
setCurrentNode(m_currentNode, domNodeCursorOffset);
|
|
|
|
TQTimer::singleShot(0, this, TQT_SLOT(slotDelayedSetCaretPosition()));
|
|
|
|
NodeSelection* cursorPos = new NodeSelection();
|
|
cursorPos->setCursorNode(cursorNode);
|
|
cursorPos->setCursorOffset(cursorOffset);
|
|
|
|
ViewManager::ref()->activeDocument()->docUndoRedo->addNewModifsSet(m_modifs, undoRedo::NodeTreeModif, cursorPos);
|
|
m_modifs = 0;
|
|
|
|
delete cursorPos;
|
|
|
|
makeCursorVisible();
|
|
}
|
|
|
|
void KafkaWidget::applyQueuedToggableTagActions()
|
|
{
|
|
TQStringList queued_actions = quantaApp->tagActionPool();
|
|
TQPtrList<TagAction> action_list = quantaApp->tagActions();
|
|
for(TQStringList::Iterator it = queued_actions.begin(); it != queued_actions.end(); ++it)
|
|
{
|
|
TagAction* tag_action = 0;
|
|
for (tag_action = action_list.first(); tag_action; tag_action = action_list.next())
|
|
{
|
|
if(tag_action->name() == *it)
|
|
{
|
|
tag_action->slotActionActivated(TDEAction::EmulatedActivation, Qt::NoButton);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
quantaApp->removeAllTagActionPoolItems();
|
|
}
|
|
|
|
#include "kafkahtmlpart.moc"
|