diff options
Diffstat (limited to 'part/kxe_treeview.cpp')
-rw-r--r-- | part/kxe_treeview.cpp | 909 |
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 + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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); +} |