Logo Search packages:      
Sourcecode: kdewebdev version File versions

kafkahtmlpart.cpp

/***************************************************************************
                              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 <qfile.h>
#include <qpainter.h>
#include <qtextstream.h>
#include <qstringlist.h>
#include <qlayout.h>
#include <qmainwindow.h>
#include <qtimer.h>
#include <qtooltip.h>

#include <kapplication.h>
#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <ktrader.h>
#include <klibloader.h>
#include <kparts/factory.h>
#include <dom/dom_text.h>
#include <dom/dom_exception.h>
#include <dom/dom_string.h>
#include <dom/dom2_range.h>
#include <khtml_events.h>

#include "kafkacommon.h"
#ifdef HEAVY_DEBUG
#include "domtreeview.h"
#include <qdialog.h>
#endif
#include "wkafkapart.h"
#include "nodeproperties.h"
#include "document.h"
#include "resource.h"
#include "quanta.h"
#include "quantaview.h"
#include "tagattributetree.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(QWidget *parent, QWidget *widgetParent, KafkaDocument *part,
                         const char *name)
        : KHTMLPart(new KafkaHTMLView(this, widgetParent, name), parent, name),
        w(part)
{
    d = new KafkaWidgetPrivate();
 
    d->m_cursorOffset = 0;
    d->m_pressOffset = 0;
    d->m_releaseOffset = 0;
    d->stuckCursorHorizontalPos = false;

    // 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, SIGNAL(caretPositionChanged(const DOM::Node &, long)),
            this, SLOT(slotNewCursorPos(const DOM::Node &, long)));
    setCaretDisplayPolicyNonFocused(KHTMLPart::CaretVisible);

    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 khtmlPart
    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
    QString newPageHTMLCode = "<html>\n"
                              "<head>\n"
                              "</head>\n"
                              "<body>\n"
                              "</body>\n"
                              "</html>\n";

    begin();
    write(newPageHTMLCode);
    end();

}

void KafkaWidget::insertText(DOM::Node node, const QString &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);
#ifdef LIGHT_DEBUG

            kdDebug(25001) << "KafkaWidget::insertText() - added text - 1" << endl;
#endif

            QTimer::singleShot(0, this, 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);
#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();
        parent.insertBefore(textNode, node);
        m_currentNode = textNode;
        d->m_cursorOffset = text.length();
        emit domNodeInserted(textNode, false);
#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();
        parent.insertBefore(textNode, node.nextSibling());
        m_currentNode = textNode;
        d->m_cursorOffset = text.length();
        emit domNodeInserted(textNode, false);
#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);
#ifdef LIGHT_DEBUG

        kdDebug(25001) << "KafkaWidget::insertText() - added text - 4" << endl;
#endif

    }
    //document().updateRendering();
    QTimer::singleShot(0, this, SLOT(slotDelayedSetCaretPosition()));
}

void KafkaWidget::slotDelayedSetCaretPosition()
{
    setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
    emit domNodeNewCursorPos(m_currentNode, d->m_cursorOffset);
}

void KafkaWidget::insertText(const QString &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

    DOM::Node childNode = _node.firstChild();
    while(!childNode.isNull())
    {
        if(w->getAttrs(childNode)->chCurFoc() == kNodeAttrs::textNode)
        {
            while(!childNode.nextSibling().isNull() &&
                    w->getAttrs(childNode.nextSibling())->chCurFoc() ==
                    kNodeAttrs::textNode )
            {
                childNode.setNodeValue(childNode.nodeValue() +
                                       childNode.nextSibling().nodeValue());
                emit domNodeModified(childNode);
                emit domNodeIsAboutToBeRemoved(childNode.nextSibling(), true);
                _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;
    //      QTag *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);
            emit domNodeInserted(text2, false);
        }

        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);
        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_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_currentNode = brDomNode;
      d->m_cursorOffset = 0;
    }

#ifdef HEAVY_DEBUG

    kdDebug(25001)<< "CURNODE : " << m_currentNode.nodeName().string() << ":"
    << m_currentNode.nodeValue().string() << " : " << d->m_cursorOffset << endl;
    QTimer::singleShot(0, this, 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

    QTimer::singleShot(0, this, SLOT(slotDelayedSetCaretPosition()));
}

bool KafkaWidget::eventFilter(QObject *, QEvent *event)
{
    bool forgetEvent = false;
    //tmp
    //DOM::Node attr, tmpNode;
    //end tmp

    if(event->type() == QEvent::FocusIn)
    {
#ifdef LIGHT_DEBUG
        kdDebug(25001) << "KafkaWidget::eventFilter() FocusIn" << endl;
#endif

        emit hasFocus(true);
    }

    if(event->type() == QEvent::FocusOut)
    {
#ifdef LIGHT_DEBUG
        kdDebug(25001) << "KafkaWidget::eventFilter() FocusOut" << endl;
#endif

        emit hasFocus(false);
    }

    if(event->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyevent = static_cast<QKeyEvent *>(event);

        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)->chCurFoc() != kNodeAttrs::no)
            {
                // @todo check tab settings in Quanta
                insertText("    ", -1);
                makeCursorVisible();
            }
            forgetEvent = true;
            d->stuckCursorHorizontalPos = false;
            break;
        case Key_BackTab:
            break;
        case Key_Return:
#ifdef LIGHT_DEBUG

            kdDebug(25001)<< "KafkaWidget::eventFilter() Return" << endl;
#endif

            keyReturn(keyevent->state() & ControlButton);
            d->stuckCursorHorizontalPos = false;
            break;
        case Key_Enter:
            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() & Qt::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" ) )
                    insertText(keyevent->text(), -1);
                makeCursorVisible();
#ifdef HEAVY_DEBUG
                //w->coutLinkTree(baseNode, 2);
#endif

            }
            forgetEvent = true;
            d->stuckCursorHorizontalPos = false;
            break;
        }
    }

#ifdef LIGHT_DEBUG
    kdDebug(25001)<< "Current Offset : " << m_currentNode.nodeName().string()  << ":" <<
    d->m_cursorOffset << " (" << event->type() << ")" << endl;
#endif

    return forgetEvent;
}

#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(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);
        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->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->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->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);
        _node.removeChild(m_currentNode);
        m_currentNode = document().createTextNode("");
        _node.appendChild(m_currentNode);
        emit domNodeInserted(m_currentNode, false);
        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->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);
                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);
                _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);
                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);
                    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);
                    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);
            _nodeParent.removeChild(_nodeNext);
            singleNodeDeleted = true;
            _nodeNext = _node;
            if(focus == kNodeAttrs::singleNodeAndItself)
            {
                normalize(_nodeParent);
                break;
            }
        }
        _nodeNext = getNextNode(_nodeNext, _goingTowardsRootNode);
    }

#if KDE_VERSION >= KDE_MAKE_VERSION(3,2,1)
    //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->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);
                _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->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);*/
#endif
}

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;
    QString text;

    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);
        m_currentNode.setNodeValue(nodeText + textSplitted);
        m_currentNode.parentNode().applyChanges();
        --(d->m_cursorOffset);
        emit domNodeModified(m_currentNode);
        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->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->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->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);
        _node.removeChild(m_currentNode);
        m_currentNode = document().createTextNode("");
        _node.appendChild(m_currentNode);
        emit domNodeInserted(m_currentNode, false);
        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();
                postprocessCursorPosition();
                emit domNodeModified(_nodePrev);
                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);
                _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);
                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);
                    tempParent.removeChild(startNode2);

                    temp.setNodeValue(text);
                    emit domNodeModified(temp);

                    if(boolTmp)
                        QTimer::singleShot(0, this, 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);
                    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);
                    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);
            _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();
                      QTimer::singleShot(0, this, SLOT(slotDelayedSetCaretPosition()));
                    }
                    _nodePrev.setNodeValue(_nodePrev.nodeValue() + _node.nodeValue());
                    emit domNodeModified(_nodePrev);
                    //_nodeParent = _nodePrev.parentNode();
                    emit domNodeIsAboutToBeRemoved(_node, true);
                    _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;
                    
                    QTimer::singleShot(0, this, 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::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->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() == "" &&
          m_currentNode.nextSibling().nextSibling().isNull() &&*/
          !m_currentNode.previousSibling().isNull() && 
          m_currentNode.previousSibling().nodeType() == DOM::Node::TEXT_NODE &&
          m_currentNode.previousSibling().nodeValue().string() != "")))
        {
            while(1)
            {
                _prevNextNode = _nextNode;
                _nextNode = getPrevNode(_nextNode, b);
                if(_nextNode == 0)
                    break;
                attrs2 = w->getAttrs(_nextNode);
                if(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)
                {
                    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->chCurFoc() == kNodeAttrs::singleNodeAndItself)
                    break;
                else if(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::khtmlMouseMoveEvent(khtml::MouseMoveEvent *event)
{
    DOM::Node mouseNode = event->innerNode();
    
    if(mouseNode == 0)
        return;
    if(mouseNode.nodeType() == DOM::Node::TEXT_NODE)
        KApplication::setOverrideCursor(Qt::ibeamCursor);
    else
        KApplication::setOverrideCursor(Qt::arrowCursor);
    
    KHTMLPart::khtmlMouseMoveEvent(event);
}

void KafkaWidget::khtmlMouseReleaseEvent(khtml::MouseReleaseEvent *event)
{
    KHTMLPart::khtmlMouseReleaseEvent(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::khtmlMousePressEvent(khtml::MousePressEvent *event)
{
    KHTMLPart::khtmlMousePressEvent(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::khtmlDrawContentsEvent(khtml::DrawContentsEvent *event)
{
    KHTMLPart::khtmlDrawContentsEvent(event);
}

void KafkaWidget::getCurrentNode(DOM::Node &_currentNode, int &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")
        QTimer::singleShot(0, this, SLOT(slotDelayedSetCaretPosition()));
    //setCaretPosition(m_currentNode, (long)d->m_cursorOffset);
}

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;
    QTimer::singleShot(0, this, 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));
}

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);
            //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());
            else
                emit domNodeIsAboutToBeMoved(domNode, newParent, DOM::Node());
            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;
        }
    }
}

#include "kafkahtmlpart.moc"

Generated by  Doxygen 1.6.0   Back to index