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

910 lines
27 KiB

/***************************************************************************
kxe_treeview.cpp - description
-------------------
begin : Thu Sep 20 2001
copyright : (C) 2001, 2002, 2003 by The KXMLEditor Team
email : OleBowle@gmx.de
***************************************************************************/
/***************************************************************************
* *
* 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);
}