summaryrefslogtreecommitdiffstats
path: root/part/kxe_treeview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'part/kxe_treeview.cpp')
-rw-r--r--part/kxe_treeview.cpp909
1 files changed, 909 insertions, 0 deletions
diff --git a/part/kxe_treeview.cpp b/part/kxe_treeview.cpp
new file mode 100644
index 0000000..f5bd08c
--- /dev/null
+++ b/part/kxe_treeview.cpp
@@ -0,0 +1,909 @@
+/***************************************************************************
+ kxe_treeview.cpp - description
+ -------------------
+ begin : Thu Sep 20 2001
+ copyright : (C) 2001, 2002, 2003 by The KXMLEditor Team
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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 "kxe_treeview.h"
+#include "kxe_treeviewitem.h"
+#include "kxesearchdialog.h"
+#include "kxmleditorpart.h"
+
+#include "kxmleditorfactory.h"
+#include "kxeconfiguration.h"
+#include "kxetreeviewsettings.h"
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kxmlgui.h>
+#include <kxmlguiclient.h>
+#include <kpopupmenu.h>
+#include <kglobalsettings.h>
+#include <kmessagebox.h>
+
+// include files for Qt
+#include "qdom_add.h"
+#include <qheader.h>
+#include <qdragobject.h>
+#include <qtimer.h>
+#include <qdom.h>
+#include <qcursor.h>
+#include <qevent.h>
+
+static const int autoOpenTimeout = 750;
+
+
+KXE_TreeView::KXE_TreeView( KXMLGUIClient * pGUIClient, QWidget * pParent, const char * pszName )
+ : KListView(pParent,pszName),
+ m_pGUIClient(pGUIClient),
+ m_nBookmarkedItems(0)
+{
+ setSorting(-1); // no sorting
+
+ addColumn(i18n("Qualified name"));
+
+ setSelectionMode(QListView::Single);
+
+ connect( this, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()) );
+ connect( this, SIGNAL(expanded(QListViewItem*)), this, SLOT(slotItemExpanded(QListViewItem*)) );
+
+ setReadWrite(false);
+
+ m_bDrag = false;
+ m_pCurrentBeforeDropItem = 0;
+ m_pDropItem = 0;
+
+ m_autoOpenTimer = new QTimer(this);
+ connect(m_autoOpenTimer, SIGNAL(timeout()), this, SLOT(slotAutoOpenFolder()));
+
+ // Apply current configuration
+ slotTreeViewSettingsChanged();
+ // and make sure to be informed about its changes.
+ connect( KXMLEditorFactory::configuration()->treeview(), SIGNAL(sigChanged()), this, SLOT(slotTreeViewSettingsChanged()) );
+}
+
+void KXE_TreeView::setReadWrite( bool fReadWrite )
+{
+ setItemsRenameable( fReadWrite );
+ setRenameable( 0, fReadWrite );
+
+ if ( fReadWrite ) // If the widget enters read/write mode, then enable/disable
+ { // dropping (according to the configuration data).
+ setAcceptDrops( KXMLEditorFactory::configuration()->treeview()->enableDropping() );
+ viewport()->setAcceptDrops( KXMLEditorFactory::configuration()->treeview()->enableDropping() );
+ }
+ else // If the widget enter read only mode,
+ { // then disable dropping.
+ setAcceptDrops( false );
+ viewport()->setAcceptDrops( false );
+ }
+}
+
+//////////////////////////////////////////////////////////////
+// configuration slots
+//////////////////////////////////////////////////////////////
+
+void KXE_TreeView::slotTreeViewSettingsChanged()
+{
+ setRootIsDecorated( KXMLEditorFactory::configuration()->treeview()->decorateRoot() );
+
+ if ( KXMLEditorFactory::configuration()->treeview()->elemDisplMode() == KXETreeViewSettings::NoAttributes )
+ {
+ if ( columns() > 1 )
+ removeColumn(1);
+ }
+ else
+ {
+ if ( columns() < 2 )
+ addColumn( i18n("Attributes") );
+ }
+
+ KXE_TreeViewItem * pItem = static_cast<KXE_TreeViewItem*> (firstChild());
+ while (pItem)
+ {
+ pItem->setTexts();
+ pItem = pItem->nextItem();
+ }
+
+ if ( itemsRenameable() ) // If the widget is in read/write mode, then enable/disable
+ { // dropping (according to the configuration data).
+ setAcceptDrops( KXMLEditorFactory::configuration()->treeview()->enableDropping() );
+ viewport()->setAcceptDrops( KXMLEditorFactory::configuration()->treeview()->enableDropping() );
+ }
+
+}
+
+//////////////////////////////////////////////////////////////
+// action slots
+//////////////////////////////////////////////////////////////
+
+void KXE_TreeView::editDeselect()
+{
+ clearSelection();
+}
+
+void KXE_TreeView::viewNodeUp()
+{
+ // get selected item from tree view
+ QListViewItem * pSelItem = selectedItem();
+ if ( ! pSelItem )
+ {
+ kdDebug() << "KXE_TreeView::slotViewNodeUp no item selected" << endl;
+ return;
+ }
+
+ // get parent item
+ QListViewItem * pParentItem = pSelItem->parent();
+
+ // select parent item in tree view
+ if (pParentItem)
+ {
+ setCurrentItem(pParentItem);
+ ensureItemVisible(pParentItem);
+ }
+}
+
+void KXE_TreeView::viewExpNode( int nLevel )
+{
+ // get selected item from tree view (if any)
+ QListViewItem * pSelItem = selectedItem();
+ if ( ! pSelItem )
+ {
+ kdDebug() << "KXE_TreeView::slotViewExpNode no item selected" << endl;
+ return;
+ }
+
+ // expand node
+ KXE_TreeViewItem * pSelTreeItem = static_cast <KXE_TreeViewItem*> (pSelItem);
+ pSelTreeItem->expandSubTree(nLevel);
+}
+
+void KXE_TreeView::viewColNode( int nLevel )
+{
+ // get selected item from tree view (if any)
+ QListViewItem * pSelItem = selectedItem();
+ if ( ! pSelItem )
+ {
+ kdDebug() << "KXE_TreeView::slotViewColNode no item selected" << endl;
+ return;
+ }
+
+ // expand node
+ KXE_TreeViewItem * pSelTreeItem = static_cast <KXE_TreeViewItem*> (pSelItem);
+ pSelTreeItem->collapseSubTree(nLevel);
+}
+
+void KXE_TreeView::bookmarksToggle()
+{
+ // get selected item from tree view
+ KXE_TreeViewItem * pSelItem = static_cast <KXE_TreeViewItem*> (selectedItem());
+ if ( ! pSelItem )
+ {
+ kdDebug() << "KXE_TreeView::bookmarksToggle: no item selected" << endl;
+ return;
+ }
+
+ // toggle bookmark on selected item
+ if(pSelItem->toggleBookmark())
+ m_nBookmarkedItems++;
+ else
+ m_nBookmarkedItems--;
+}
+
+void KXE_TreeView::bookmarksPrev()
+{
+ if ( childCount() < 1 )
+ {
+ kdDebug() << "KXE_TreeView::bookmarksPrev: internal error - this tree view is empty" << endl;
+ return;
+ }
+
+ // get selected item from tree view
+ KXE_TreeViewItem * pSelItem = static_cast <KXE_TreeViewItem*> (selectedItem());
+ if ( ! pSelItem ) // If there is no item selected we take
+ { // the last root items last grand child.
+ QListViewItem * pTmpItem = firstChild(); // Take first child and
+ while ( pTmpItem->nextSibling() ) // find last child by
+ pTmpItem = pTmpItem->nextSibling(); // traversing all childs
+
+ pSelItem = static_cast <KXE_TreeViewItem*> (pTmpItem); // this is the last root item
+ while ( pSelItem->lastChild() ) // find its last
+ pSelItem = pSelItem->lastChild(); // grand child
+
+ if ( pSelItem->isBookmarked() ) // We have to check its
+ { // bookmarked-status
+ selectItem(pSelItem); // and select it, in case
+ return; // it is bookmarked.
+ }
+ }
+
+ // Search items above the selected one
+ while ( (pSelItem = pSelItem->prevItem()) != 0 )
+ {
+ if ( pSelItem->isBookmarked() )
+ {
+ selectItem(pSelItem);
+ return;
+ }
+ }
+}
+
+void KXE_TreeView::bookmarksNext()
+{
+ if ( childCount() < 1 )
+ {
+ kdDebug() << "KXE_TreeView::bookmarksNext: internal error - this tree view is empty" << endl;
+ return;
+ }
+
+ // get selected item from tree view
+ KXE_TreeViewItem * pSelItem = static_cast <KXE_TreeViewItem*> (selectedItem());
+ if ( ! pSelItem )
+ { // If there is no item selected
+ pSelItem = static_cast <KXE_TreeViewItem*> (firstChild()); // we take the first root item,
+ if ( pSelItem->isBookmarked() ) // but we have to check its
+ { // bookmarked-status
+ selectItem(pSelItem); // and select it, in case
+ return; // it is bookmarked.
+ }
+ }
+
+ // Search items below the selected one
+ while ( (pSelItem = pSelItem->nextItem()) != 0 )
+ {
+ if ( pSelItem->isBookmarked() )
+ {
+ selectItem(pSelItem);
+ return;
+ }
+ }
+}
+
+void KXE_TreeView::selectItem( KXE_TreeViewItem * const pItem )
+{
+ if ( ! pItem )
+ {
+ kdDebug() << "KXE_TreeView::selectItem: the given pointer is a null pointer" << endl;
+ return;
+ }
+
+ setSelected( pItem, true );
+ setCurrentItem( pItem );
+ ensureItemVisible( pItem );
+}
+
+bool KXE_TreeView::selectNode( const QDomNode & node )
+{
+ if ( node.isNull() )
+ {
+ kdError() << "KXE_TreeView::selectNode: the given node is an empty one" << endl;
+ return false;
+ }
+
+ KXE_TreeViewItem * pItem = findCorrespondingItem(node);
+
+ if ( ! pItem ) // can't find the corresponding item
+ {
+ kdError() << "KXE_TreeView::selectNode can't find an item to the given node." << endl;
+ return false;
+ }
+
+ selectItem(pItem);
+ return true;
+}
+
+QDomNode * KXE_TreeView::getSelectedNode() const
+{
+ // get selected item from tree view
+ QListViewItem * pSelItem = selectedItem();
+ if ( ! pSelItem )
+ return 0;
+
+ KXE_TreeViewItem * pSelTreeItem = static_cast <KXE_TreeViewItem *> (pSelItem);
+ return pSelTreeItem->xmlNode();
+}
+
+QDomNode * KXE_TreeView::getSpecProcInstrNode(const QString& target) const
+{
+ KXE_TreeViewItem * pTreeItem = static_cast<KXE_TreeViewItem*> (firstChild());
+ while ( pTreeItem )
+ {
+ if (pTreeItem->xmlNode()->isProcessingInstruction())
+ {
+ QDomProcessingInstruction domProcInstr = pTreeItem->xmlNode()->toProcessingInstruction();
+ if(domProcInstr.target() == target)
+ return pTreeItem->xmlNode();
+ }
+
+ pTreeItem = pTreeItem->nextItem();
+ }
+
+ return 0;
+}
+
+// Return info, is root element is already created
+bool KXE_TreeView::hasRootNode()
+{
+ KXE_TreeViewItem * pTreeItem = static_cast<KXE_TreeViewItem*> (firstChild());
+ while ( pTreeItem )
+ {
+ if (pTreeItem->xmlNode()->isElement())
+ {
+ return true;
+ }
+
+ pTreeItem = pTreeItem->nextItem();
+ }
+
+ return false;
+}
+
+
+QString KXE_TreeView::getSelectedPath() const
+{
+ // get selected item from tree view
+ QListViewItem * pSelItem = selectedItem();
+ if ( ! pSelItem )
+ return QString();
+
+ KXE_TreeViewItem * pSelTreeItem = static_cast <KXE_TreeViewItem *> (pSelItem);
+ return domTool_getPath( * pSelTreeItem->xmlNode() );
+}
+
+void KXE_TreeView::contentsMousePressEvent( QMouseEvent * pEvent )
+{
+ KListView::contentsMousePressEvent(pEvent);
+
+ if ( pEvent->button() == RightButton )
+ {
+ QString szMenuName;
+
+ QListViewItem * pItem = itemAt( contentsToViewport(pEvent->pos()) );
+ if (pItem)
+ {
+ KXE_TreeViewItem * pTreeItem = static_cast <KXE_TreeViewItem*> (pItem);
+ switch( pTreeItem->xmlNode()->nodeType() )
+ {
+ case QDomNode::ElementNode:
+ szMenuName = "popupXmlElement";
+ break;
+ case QDomNode::TextNode:
+ case QDomNode::CDATASectionNode:
+ case QDomNode::CommentNode:
+ szMenuName = "popupXmlContent";
+ break;
+ case QDomNode::ProcessingInstructionNode:
+ szMenuName = "popupXmlProcInstr";
+ break;
+ default:
+ kdDebug() << "KXE_TreeView::contentsMousePressEvent unknown item type" << endl;
+ return;
+ }
+ }
+ else
+ szMenuName = "popupXmlTree";
+
+ emit sigContextMenuRequested( szMenuName, QCursor::pos() );
+ return;
+ }
+
+ //--- Drag & Drop ------------------------------------------------------
+ QPoint p(contentsToViewport(pEvent->pos()));
+ QListViewItem *i = itemAt(p);
+
+ if(pEvent->button() == LeftButton && i)
+ { // if the user clicked into the root decoration of the item, don't try to start a drag!
+ if(p.x() > header()->cellPos(header()->mapToActual(0)) +
+ treeStepSize() * ( i->depth() + (rootIsDecorated() ? 1 : 0)) + itemMargin() ||
+ p.x() < header()->cellPos(header()->mapToActual(0)))
+ {
+ m_dragPos = pEvent->pos();
+ m_bDrag = true;
+ }
+ }
+}
+
+void KXE_TreeView::slotSelectionChanged()
+{
+ KXE_TreeViewItem * pItem = static_cast <KXE_TreeViewItem*> (selectedItem());
+
+ if ( ! pItem )
+ emit sigSelectionCleared(hasRootNode());
+ else
+ {
+ QDomNode selectedNode = * ( pItem->xmlNode() ); // uses QDomNode copy constructor
+
+ // choose appropriate object kind
+ switch ( selectedNode.nodeType() )
+ {
+ case QDomNode::ElementNode:
+ emit sigSelectionChanged( selectedNode.toElement());
+ break;
+
+ case QDomNode::TextNode:
+ case QDomNode::CDATASectionNode:
+ case QDomNode::CommentNode:
+ emit sigSelectionChanged( selectedNode.toCharacterData());
+ break;
+
+ case QDomNode::ProcessingInstructionNode:
+ emit sigSelectionChanged( selectedNode.toProcessingInstruction());
+ break;
+
+ default:
+ kdDebug() << "KXE_TreeView::slotSelectionChanged unknown object type selected" << endl;
+ return;
+ }
+ }
+}
+
+
+void KXE_TreeView::slotItemExpanded( QListViewItem * pItem )
+{
+ KXE_TreeViewItem * pTreeViewItem = static_cast<KXE_TreeViewItem*> (pItem);
+ pTreeViewItem->ensureGrandChildItemsCreated();
+}
+
+
+//////////////////////////////////////////////////////////////
+// update slots
+//////////////////////////////////////////////////////////////
+
+void KXE_TreeView::updateNodeCreated( const QDomNode & node )
+{
+ if ( node.isNull() )
+ {
+ kdError() << "KXE_TreeView::slotUpdateNodeCreated the given node is an empty one." << endl;
+ return;
+ }
+
+ KXE_TreeViewItem * pNewItem;
+ if ( node.parentNode().isDocument() ) // the new nodes parent is the document itself,
+ {
+ // so we have to create a root item.
+ // Now it depends: either it's a processing instruction, or element
+ if (node.isProcessingInstruction())
+ // Tree looks much nicer if root processing instructions are ont the top...
+ {
+ QDomNode *pNode = getSpecProcInstrNode("xml");
+ if (pNode)
+ pNewItem = new KXE_TreeViewItem( node, this,findCorrespondingItem(*pNode));
+ else
+ pNewItem = new KXE_TreeViewItem( node, this);
+ }
+ else
+ // ...and root element is placed at the bottom.
+ pNewItem = new KXE_TreeViewItem( node, this,lastChild());
+// pNewItem = new KXE_TreeViewItem( node, this);
+
+ if ( ! rootIsDecorated() )
+ pNewItem->setOpen(true);
+ }
+ else
+ {
+ if ( node.parentNode().isNull() )
+ {
+ kdError() << "KXE_TreeView::slotUpdateNodeCreated the given node has no parent node (but should)." << endl;
+ return;
+ }
+
+ // To create the new item, we need (1st) the item corresponding to the parent node of the given one.
+ QDomNode parentNode = node.parentNode();
+ // Because the currently selected item is very likely (in many cases) the correct one, try it first.
+ KXE_TreeViewItem * pParentItem = static_cast<KXE_TreeViewItem*> (selectedItem());
+ if ( (!pParentItem) || ( *(pParentItem->xmlNode()) != parentNode ) )
+ { // no strike :-(
+ pParentItem = findCorrespondingItem(parentNode); // do it the "long" way
+ }
+
+ if ( ! pParentItem ) // can't find the corresponding item
+ {
+ kdError() << "KXE_TreeView::slotUpdateNodeCreated can't find an item to the given nodes parent node." << endl;
+ return;
+ }
+
+ // Now we need (2nd) the item corresponding to the previous sibling of the given one,
+ // because, the new item has to be inserted behind the given one.
+ QDomNode prevNode = node.previousSibling();
+ if ( prevNode.isNull() )
+ { // it seems to be the first child node, so create a first child item
+ pNewItem = new KXE_TreeViewItem( node, pParentItem );
+ }
+ else
+ {
+ KXE_TreeViewItem * pPrevItem = findCorrespondingItem(prevNode);
+ if ( ! pParentItem ) // can't find the corresponding item :-(
+ {
+ kdError() << "KXE_TreeView::slotUpdateNodeCreated can't find an item to the given nodes previous sibling." << endl;
+ return;
+ }
+ // everything's alright, let's create the new item
+ pNewItem = new KXE_TreeViewItem( node, pParentItem, pPrevItem );
+ }
+
+ }
+
+ setSelected( pNewItem, true );
+ ensureItemVisible( pNewItem );
+}
+
+void KXE_TreeView::updateNodeChanged( const QDomNode & node )
+{
+ if ( node.isNull() )
+ {
+ kdError() << "KXE_TreeView::slotUpdateNodeChanged the given node is an empty one." << endl;
+ return;
+ }
+
+ // To change the item, we have to find it.
+ // Because the currently selected item is very likely (in many cases) the correct one, try it first.
+ KXE_TreeViewItem * pItem = static_cast<KXE_TreeViewItem*> (selectedItem());
+ if ( (!pItem) || ( *(pItem->xmlNode()) != node ) ) // no strike :-(
+ pItem = findCorrespondingItem(node); // do it the "long" way
+
+ if ( ! pItem ) // can't find the corresponding item
+ {
+ kdError() << "KXE_TreeView::slotUpdateNodeChanged can't find an item to the given node." << endl;
+ return;
+ }
+
+ pItem->setTexts(); // update the item
+
+ setSelected( pItem, true );
+ ensureItemVisible( pItem );
+}
+
+void KXE_TreeView::updateNodeDeleted( const QDomNode & node )
+{
+ if ( node.isNull() )
+ {
+ kdError() << "KXE_TreeView::slotUpdateNodeDeleted the given node is an empty one." << endl;
+ return;
+ }
+
+ // To remove the item, we have to find it.
+ // Because the currently selected item is very likely (in many cases) the correct one, try it first.
+ KXE_TreeViewItem * pItem = static_cast<KXE_TreeViewItem*> (selectedItem());
+ if ( (!pItem) || ( *(pItem->xmlNode()) != node ) ) // no strike :-(
+ pItem = findCorrespondingItem(node); // do it the "long" way
+
+ if ( ! pItem ) // can't find the corresponding item
+ {
+ kdError() << "KXE_TreeView::slotUpdateNodeDeleted can't find an item to the given node." << endl;
+ return;
+ }
+
+ clearSelection();
+
+ delete pItem;
+
+ emit sigSelectionCleared(hasRootNode());
+}
+
+void KXE_TreeView::updateNodeMoved( const QDomNode & node )
+{
+ if ( node.isNull() )
+ {
+ kdError() << "KXE_TreeView::slotUpdateNodeMoved the given node is an empty one." << endl;
+ return;
+ }
+
+ // To move the item, we have to find it.
+ // Because the currently selected item is very likely (in many cases) the correct one, try it first.
+ KXE_TreeViewItem * pItem = static_cast<KXE_TreeViewItem*> (selectedItem());
+ if ( (!pItem) || ( *(pItem->xmlNode()) != node ) ) // no strike :-(
+ pItem = findCorrespondingItem(node); // do it the "long" way
+
+ if ( ! pItem ) // can't find the corresponding item
+ {
+ kdError() << "KXE_TreeView::slotUpdateNodeMoved can't find an item to the given node." << endl;
+ return;
+ }
+
+ // Now we can move the item (of the moved node).
+ // We have to differenciate between the following 2 cases.
+ if ( node.previousSibling().isNull() )
+ {
+ // The node does not has a previous sibling. This means, it has been moved
+ // to be its parent first child. In this case, we have to find the tree
+ // view item of the node's next sibling to swap them.
+ // It's very likely the previous sibling of the item corresponding to the
+ // moved node.
+ KXE_TreeViewItem * pOldPrevItem = pItem->prevSibling();
+ // Was it really?
+ if ( ! pOldPrevItem || ( *(pOldPrevItem->xmlNode()) != node.nextSibling() ) )
+ // It wasn't (how can it be?) - we have to find it using the "long" way.
+ pOldPrevItem = findCorrespondingItem( node.nextSibling() );
+
+ if ( ! pOldPrevItem ) // something went wrong
+ {
+ kdError() << "KXE_TreeView::slotUpdateNodeMoved can't find the item to the given node's next sibling." << endl;
+ return;
+ }
+
+ // Now we can swap them (make the old previous item the new next item of
+ // the moved node's item).
+ pOldPrevItem->moveItem( pItem );
+ }
+ else
+ {
+ // The node has a previous sibling. In this case we have to find the
+ // corresponding tree view item to swap it with the item corresponding to
+ // the moved node.
+ KXE_TreeViewItem * pNewPrevItem = findCorrespondingItem( node.previousSibling() );
+ if ( ! pNewPrevItem )
+ {
+ kdError() << "KXE_TreeView::slotUpdateNodeMoved can't find the new prev.item to the given nodes prev.node." << endl;
+ return;
+ }
+
+ // swap them (move the moved node's item after the previous sibling's item)
+ pItem->moveItem( pNewPrevItem );
+ }
+
+ setSelected( pItem, true );
+ ensureItemVisible( pItem );
+}
+
+void KXE_TreeView::updateClear()
+{
+ clear();
+}
+
+void KXE_TreeView::rename( QListViewItem * pItem, int nColumn )
+{
+ if ( nColumn != 0 ) // inplace editing only
+ return; // for the first column
+
+ KXE_TreeViewItem * pXMLItem = static_cast <KXE_TreeViewItem*> (pItem);
+ if ( pXMLItem->xmlNode()->isElement() ) // inplace-renaming only for items representing XML elements
+ KListView::rename( pItem, nColumn ); // inplace-renaming via base class functionality
+
+ else if(pXMLItem->xmlNode()->isCharacterData()) // launch dialog for editing text nodes
+ (dynamic_cast <KXMLEditorPart *> (m_pGUIClient))->slotXmlCharDataEdit();
+
+ else if(pXMLItem->xmlNode()->isProcessingInstruction()) // launch dialog for editing proc.instr.
+ (dynamic_cast <KXMLEditorPart *> (m_pGUIClient))->slotXmlProcInstrEdit();
+}
+
+//////////////////////////////////////////////////////////////
+// misc functions
+//////////////////////////////////////////////////////////////
+
+KXE_TreeViewItem * KXE_TreeView::findCorrespondingItem( const QDomNode & node )
+{
+ KXE_TreeViewItem * pItem = static_cast<KXE_TreeViewItem*> (firstChild());
+ while ( pItem )
+ {
+ if ( *(pItem->xmlNode()) == node )
+ return pItem;
+ pItem = pItem->nextItem();
+ }
+
+ return 0;
+}
+
+//////////////////////////////////////////////////////////////
+// Drag & Drop
+//////////////////////////////////////////////////////////////
+
+/** Overrides KListView::contentsMouseMoveEvent */
+void KXE_TreeView::contentsMouseMoveEvent(QMouseEvent *e)
+{
+ KListView::contentsMouseMoveEvent(e);
+
+ // exit, if dragging is disabled
+ if ( ! KXMLEditorFactory::configuration()->treeview()->enableDragging() )
+ return;
+
+ if(!m_bDrag || (e->pos() - m_dragPos).manhattanLength() <= KGlobalSettings::dndEventDelay())
+ return;
+
+ m_bDrag = false;
+
+ QListViewItem *item = itemAt(contentsToViewport(m_dragPos));
+
+ if(!item || !item->isSelectable())
+ return;
+
+ // copy item into clipboard
+ KXE_TreeViewItem *pXmlTreeItem = static_cast <KXE_TreeViewItem *> (item);
+ QTextDrag *pDrag = (dynamic_cast <KXMLEditorPart *> (m_pGUIClient))->copyNode(pXmlTreeItem->xmlNode());
+
+
+ // Start a drag
+ const QPixmap *pix = item->pixmap(0);
+ if(pix && pDrag->pixmap().isNull())
+ { QPoint hotspot(pix->width() / 2, pix->height() / 2);
+ pDrag->setPixmap(*pix, hotspot);
+ }
+
+ pDrag->drag();
+}
+
+/** Overrides KListView::contentsMouseReleaseEvent */
+void KXE_TreeView::contentsMouseReleaseEvent(QMouseEvent *e)
+{
+ KListView::contentsMouseReleaseEvent(e);
+ m_bDrag = false;
+}
+
+/** Overrides QScrollView::contentsDragEnterEvent */
+void KXE_TreeView::contentsDragEnterEvent(QDragEnterEvent *e)
+{
+ m_pDropItem = 0;
+ m_pCurrentBeforeDropItem = selectedItem();
+
+ // Save the available formats
+ m_lstDropFormats.clear();
+ for(int i = 0; e->format(i); i++)
+ { if(*(e->format(i)))
+ { m_lstDropFormats.append(e->format(i));
+ }
+ }
+}
+
+/** Overrides QScrollView::contentsDragMoveEvent */
+void KXE_TreeView::contentsDragMoveEvent(QDragMoveEvent *e)
+{
+ QListViewItem *item = itemAt(contentsToViewport(e->pos()));
+
+ // Accept drops on the background, if Texts
+ if(!item && (m_lstDropFormats.contains("text/")))
+ { m_pDropItem = 0;
+ e->acceptAction();
+ if(selectedItem())
+ setSelected(selectedItem(), false); // no item selected
+ return;
+ }
+
+ if(!item || !item->isSelectable())
+ { m_pDropItem = 0;
+ m_autoOpenTimer->stop();
+ e->ignore();
+ return;
+ }
+
+ e->acceptAction();
+
+ setSelected(item, true);
+
+ if(item != m_pDropItem )
+ { m_autoOpenTimer->stop();
+ m_pDropItem = item;
+ m_autoOpenTimer->start(autoOpenTimeout);
+ }
+}
+
+/** Overrides QScrollView::contentsDragLeaveEvent */
+void KXE_TreeView::contentsDragLeaveEvent(QDragLeaveEvent *e)
+{
+ e=e;
+ // Restore the current item to what it was before the dragging (#17070)
+ if(m_pCurrentBeforeDropItem)
+ setSelected(m_pCurrentBeforeDropItem, true);
+ else
+ setSelected(m_pDropItem, false); // no item selected
+
+ m_pCurrentBeforeDropItem = 0;
+ m_pDropItem = 0;
+ m_lstDropFormats.clear();
+}
+
+/** Overrides QScrollView::contentsDropEvent */
+void KXE_TreeView::contentsDropEvent(QDropEvent *pDropEvent)
+{
+ m_autoOpenTimer->stop();
+
+ drop(selectedItem(), pDropEvent);
+}
+
+/** Called, when m_autoOpenTimer timeout occured */
+void KXE_TreeView::slotAutoOpenFolder()
+{
+ m_autoOpenTimer->stop();
+
+ if(!m_pDropItem || m_pDropItem->isOpen())
+ return;
+
+ m_pDropItem->setOpen( true );
+ m_pDropItem->repaint();
+}
+
+/** Drop or paste text into item */
+bool KXE_TreeView::drop(QListViewItem *pItem, QDropEvent *pDropEvent)
+{
+ KXE_TreeViewItem* pTreeItem = 0;
+ if(pItem)
+ pTreeItem = static_cast <KXE_TreeViewItem *> (pItem);
+
+ QDomNode *pTargetNode = pTreeItem->xmlNode();
+
+ // First, make check, if moved item is not moved to their children
+ if((pDropEvent->source() == this) && (pDropEvent->action() == QDropEvent::Move))
+ { // make check, if moved item is not moved to itself
+ if(m_pCurrentBeforeDropItem && pTreeItem && (m_pCurrentBeforeDropItem == pTreeItem))
+ { return false;
+ }
+
+ if(m_pCurrentBeforeDropItem && pTreeItem &&
+ static_cast <KXE_TreeViewItem*> (m_pCurrentBeforeDropItem)->isMyChildren(pTreeItem))
+ { KMessageBox::sorry(0, i18n("An XML element can't be moved to its own subtree."));
+ return false;
+ }
+
+ if (pTreeItem->xmlNode()->isProcessingInstruction())
+ {
+ KMessageBox::sorry(0, i18n("An XML node can't be moved in a processing instruction."));
+ return false;
+ }
+
+ QDomNode * pNode = static_cast <KXE_TreeViewItem*> (m_pCurrentBeforeDropItem)->xmlNode();
+ if (pNode->isProcessingInstruction())
+ {
+ QDomProcessingInstruction domProcInstr = pNode->toProcessingInstruction();
+
+ if(domProcInstr.target() == "xml")
+ { KMessageBox::sorry(0, i18n("This processing instruction cannot be moved !"));
+ return false;
+ }
+ }
+ }
+
+ //-- If Move from same instance of this widget
+ if((pDropEvent->source() == this) && (pDropEvent->action() == QDropEvent::Move) && (m_pCurrentBeforeDropItem) && pTargetNode->isElement())
+ {
+ // remove source item
+ QDomNode * pSourceNode = static_cast <KXE_TreeViewItem*> (m_pCurrentBeforeDropItem)->xmlNode();
+ QDomElement domTargetElement = pTargetNode->toElement();
+
+ if((dynamic_cast <KXMLEditorPart *> (m_pGUIClient))->dropMoveNode(domTargetElement, *pSourceNode))
+ {
+ pDropEvent->acceptAction();
+ return true;
+ }
+ }
+ else
+ {
+ //-- If Copy, do standart Paste function
+ if((dynamic_cast <KXMLEditorPart *> (m_pGUIClient))->pasteNode(pTargetNode, pDropEvent))
+ {
+ pDropEvent->acceptAction();
+ return true;
+ }
+ }
+ return false;
+}
+
+
+//
+// returns last child on the tree (top-level)
+//
+KXE_TreeViewItem* KXE_TreeView::lastChild()
+{
+ QListViewItem* pItem = firstChild();
+ if (pItem && pItem->nextSibling())
+ do
+ pItem = pItem->nextSibling();
+ while (pItem->nextSibling());
+
+ // here we have it...
+ return (KXE_TreeViewItem*) pItem;
+}
+
+void KXE_TreeView::keyPressEvent(QKeyEvent *e)
+{
+ KListView::keyPressEvent(e);
+ emit sigKeyPressed(e);
+}