summaryrefslogtreecommitdiffstats
path: root/kpovmodeler/pmtreeview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kpovmodeler/pmtreeview.cpp')
-rw-r--r--kpovmodeler/pmtreeview.cpp820
1 files changed, 820 insertions, 0 deletions
diff --git a/kpovmodeler/pmtreeview.cpp b/kpovmodeler/pmtreeview.cpp
new file mode 100644
index 00000000..66ec18a0
--- /dev/null
+++ b/kpovmodeler/pmtreeview.cpp
@@ -0,0 +1,820 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+**************************************************************************
+
+**************************************************************************
+* *
+* 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 <stdlib.h>
+
+#include <qlistview.h>
+#include <qheader.h>
+#include <qlayout.h>
+#include <qpopupmenu.h>
+#include <qcursor.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <kxmlguifactory.h>
+
+#include "pmtreeview.h"
+#include "pmtreeviewitem.h"
+#include "pmcommand.h"
+#include "pmpart.h"
+#include "pmscene.h"
+#include "pmobjectdrag.h"
+
+
+PMTreeViewWidget::PMTreeViewWidget( PMPart* part, QWidget* parent /*= 0*/,
+ const char* name /*=0*/ )
+ : PMViewBase( parent, name )
+{
+ QHBoxLayout* hl = new QHBoxLayout( this );
+ PMTreeView* tv = new PMTreeView( part, this );
+ hl->addWidget( tv );
+}
+
+QString PMTreeViewWidget::description( ) const
+{
+ return i18n( "Object Tree" );
+}
+
+PMTreeView::PMTreeView( PMPart* part, QWidget* parent /*= 0*/,
+ const char* name /*= 0*/ )
+ : QListView( parent, name )
+{
+ addColumn( i18n( "Objects" ) );
+ header( )->hide( );
+ setRootIsDecorated( true );
+ setSorting( -1 );
+ setSelectionMode( Multi );
+ m_pPart = part;
+
+ m_itemSelected = false;
+ m_itemDeselected = false;
+ m_selectionCleared = false;
+ m_pLastSelected = 0;
+ m_event = false;
+ m_pressed = false;
+ m_pDragOverItem = 0;
+ m_acceptSelect = false;
+ m_pressedItem = 0;
+
+ viewport( )->setAcceptDrops( true );
+ viewport( )->setMouseTracking( true );
+ viewport( )->setFocusPolicy( QWidget::WheelFocus );
+ setFocusPolicy( QWidget::WheelFocus );
+ setAcceptDrops( true );
+
+ connect( part, SIGNAL( refresh( ) ), SLOT( slotRefresh( ) ) );
+ connect( part, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ),
+ SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) );
+ connect( part, SIGNAL( clear( ) ), SLOT( slotClear( ) ) );
+ connect( this, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ),
+ part, SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) );
+
+ slotRefresh( );
+}
+
+PMTreeView::~PMTreeView( )
+{
+ emit destroyed( this );
+}
+
+void PMTreeView::slotObjectChanged( PMObject* obj, const int mode,
+ QObject* sender )
+{
+ PMTreeViewItem* pTreeItem = 0;
+ bool as = m_acceptSelect;
+ m_acceptSelect = true;
+
+ if( sender != this )
+ {
+ if( ( mode & PMCAdd ) && !( mode & PMCInsertError ) )
+ {
+ // object was added
+ if( !obj->parent( ) )
+ {
+ // object has no parent, append it as top level item
+ pTreeItem = new PMTreeViewItem( obj, this );
+ }
+ else
+ {
+ // find the parent in the listview
+ QListViewItem* pParentTreeItem = findObject( obj->parent( ) );
+ if( pParentTreeItem )
+ {
+ PMObject* hObj = obj->prevSibling( );
+ QListViewItem* pSibling = 0;
+ bool found = false;
+
+ if( hObj )
+ {
+ // find the previous sibling
+ pSibling = pParentTreeItem->firstChild( );
+ while( pSibling && !found )
+ {
+ if( ( ( PMTreeViewItem* ) pSibling )->object( ) == hObj )
+ found = true;
+ else
+ pSibling = pSibling->nextSibling( );
+ }
+ }
+ if( found )
+ {
+ // object has sibling
+ pTreeItem = new PMTreeViewItem( obj, pParentTreeItem, pSibling );
+ }
+ else
+ {
+ // object has no sibling
+ pTreeItem = new PMTreeViewItem( obj, pParentTreeItem );
+ }
+ }
+ }
+
+ if( pTreeItem )
+ {
+ // add child items if necessary
+ if( obj->countChildren( ) > 0 )
+ addChildItems( pTreeItem );
+ }
+ }
+ if( mode & PMCDescription )
+ {
+ if( !pTreeItem )
+ pTreeItem = findObject( obj );
+
+ if( pTreeItem )
+ pTreeItem->setDescriptions( );
+ }
+ if( mode & PMCChildren )
+ {
+ if( !pTreeItem )
+ pTreeItem = findObject( obj );
+
+ if( pTreeItem )
+ {
+ // delete old items
+ while( pTreeItem->firstChild( ) )
+ delete pTreeItem->firstChild( );
+ // create new
+ addChildItems( pTreeItem );
+ pTreeItem->setOpen( true );
+ }
+ }
+ if( mode & PMCNewSelection )
+ {
+ clearSelection( );
+
+ if( !pTreeItem )
+ pTreeItem = findObject( obj );
+
+ if( pTreeItem )
+ {
+ PMTreeViewItem* p;
+ for( p = pTreeItem->parent( ); p; p = p->parent( ) )
+ p->setOpen( true );
+ pTreeItem->setSelected( true );
+ setCurrentItem( pTreeItem );
+ }
+ }
+ if( mode & PMCDeselected )
+ {
+ if( !pTreeItem )
+ pTreeItem = findObject( obj );
+ pTreeItem->setSelected( false );
+ }
+ if( mode & PMCSelected )
+ {
+ if( !pTreeItem )
+ pTreeItem = findObject( obj );
+ pTreeItem->setSelected( true );
+ }
+ if( mode & PMCRemove )
+ {
+ // object was removed, remove the listview item
+ if( !pTreeItem )
+ pTreeItem = findObject( obj );
+ delete( pTreeItem );
+ }
+ if( mode & PMCData )
+ {
+ // special case for texture maps
+ if( obj )
+ {
+ if( obj->isA( "TextureMapBase" ) )
+ {
+ if( !pTreeItem )
+ pTreeItem = findObject( obj );
+ if( pTreeItem )
+ {
+ PMTreeViewItem* it = ( PMTreeViewItem* ) pTreeItem->firstChild( );
+ for( ; it; it = ( PMTreeViewItem* ) it->nextSibling( ) )
+ it->setDescriptions( );
+ }
+ }
+ }
+ }
+ }
+ m_acceptSelect = as;
+}
+
+
+PMTreeViewItem* PMTreeView::findObject( const PMObject* obj )
+{
+ PMTreeViewItem* pTreeItem = 0;
+
+ if( !obj->parent( ) )
+ {
+ // top level object
+ pTreeItem = ( PMTreeViewItem* ) firstChild( );
+ for( ; pTreeItem; pTreeItem = ( PMTreeViewItem* ) pTreeItem->nextSibling( ) )
+ if( pTreeItem->object( ) == obj )
+ return pTreeItem;
+ }
+ else
+ {
+ pTreeItem = findObject( obj->parent( ) );
+ if( pTreeItem )
+ {
+ pTreeItem = ( PMTreeViewItem* ) pTreeItem->firstChild( );
+ for( ; pTreeItem; pTreeItem = ( PMTreeViewItem* ) pTreeItem->nextSibling( ) )
+ if( pTreeItem->object( ) == obj )
+ return pTreeItem;
+ }
+ }
+ return 0;
+}
+
+
+void PMTreeView::selectItem( QListViewItem* /*sitem*/ )
+{
+/* QListViewItem* pItem = 0;
+ bool emitSig;
+ emitSig = ( m_pSelectedObject != ( ( PMTreeViewItem* ) sitem )->object( ) );
+
+ m_pSelectedObject = ( ( PMTreeViewItem* ) sitem )->object( );
+
+ for( pItem = sitem->parent( ); pItem; pItem = pItem->parent( ) )
+ pItem->setOpen( true );
+ ensureItemVisible( sitem );
+ setCurrentItem( sitem );
+ setSelected( sitem, true );
+ if( emitSig )
+ emit objectSelected( m_pSelectedObject );
+*/
+}
+
+void PMTreeView::addChildItems( PMTreeViewItem* item )
+{
+ PMObject* obj = 0;
+ PMTreeViewItem* listItem = 0;
+
+ for( obj = item->object( )->firstChild( ); obj; obj = obj->nextSibling( ) )
+ {
+ // insert all child objects
+ if( listItem )
+ listItem = new PMTreeViewItem( obj, item, listItem );
+ else
+ // first child
+ listItem = new PMTreeViewItem( obj, item );
+ // recursive call, if child has children
+ if( obj->countChildren( ) > 0 )
+ addChildItems( listItem );
+ }
+}
+
+void PMTreeView::slotRefresh( )
+{
+ PMTreeViewItem* item;
+ slotClear( );
+ // insert the top level items
+ if( m_pPart->scene( ) )
+ {
+ item = new PMTreeViewItem( m_pPart->scene( ), this );
+ addChildItems( item );
+ item->setOpen( true );
+// item = new PMTreeViewItem( m_pPart->insertErrors( ), this );
+// addChildItems( item );
+// item->setOpen( true );
+ }
+}
+
+void PMTreeView::slotClear( )
+{
+ clear( );
+ m_pLastSelected = 0;
+ m_pDragOverItem = 0;
+ m_pressedItem = 0;
+}
+
+void PMTreeView::itemSelected( PMTreeViewItem* item, bool selected )
+{
+ repaintItem( item );
+
+ if( m_event )
+ {
+ m_pLastSelected = item;
+
+ if( selected )
+ m_itemSelected = true;
+ else
+ {
+ if( m_itemDeselected )
+ m_selectionCleared = true;
+ else
+ m_itemDeselected = true;
+ }
+ }
+}
+
+void PMTreeView::contentsMousePressEvent( QMouseEvent * e )
+{
+ m_itemSelected = false;
+ m_itemDeselected = false;
+ m_pLastSelected = 0;
+ m_selectionCleared = false;
+ m_selectOnReleaseEvent = false;
+ bool specialAction = false;
+
+ QListViewItem* oldCurrent = currentItem( );
+
+ m_event = true;
+ m_acceptSelect = true;
+ QListView::contentsMousePressEvent( e );
+ m_event = false;
+ m_acceptSelect = true;
+
+ if( m_selectionCleared )
+ {
+ emit objectChanged( 0, PMCNewSelection, this );
+ specialAction = true;
+ }
+ else if( m_itemSelected || m_itemDeselected )
+ {
+ if( !( e->state( ) & ( ShiftButton | ControlButton ) ) )
+ {
+ specialAction = true;
+ // simple click, deselect all selected item
+ // m_pLastSelected is the new selection
+
+ if( m_itemSelected )
+ {
+ clearSelection( );
+ m_pLastSelected->setSelected( true );
+
+ emit objectChanged( m_pLastSelected->object( ), PMCNewSelection,
+ this );
+ }
+ else
+ {
+ m_selectOnReleaseEvent = true;
+ m_pLastSelected->setSelected( true );
+ }
+ }
+ else if( ( e->state( ) & ShiftButton ) && oldCurrent && m_pLastSelected )
+ {
+ if( ( oldCurrent != m_pLastSelected ) &&
+ ( oldCurrent->parent( ) == m_pLastSelected->parent( ) ) )
+ {
+ specialAction = true;
+
+ // shift click, old current item has the same parent
+ // as the new selection. Select all items between the two
+ // items
+ if( m_pLastSelected->object( )->isSelectable( ) )
+ {
+ bool down = oldCurrent->itemPos( ) < m_pLastSelected->itemPos( );
+ QListViewItem* tmp;
+
+ if( down )
+ {
+ for( tmp = oldCurrent; tmp; tmp = tmp->nextSibling( ) )
+ {
+ tmp->setSelected( true );
+ emit objectChanged( (( PMTreeViewItem* ) tmp)->object( ),
+ PMCSelected, this );
+ if( tmp == m_pLastSelected )
+ break;
+ }
+ }
+ else
+ {
+ for( tmp = m_pLastSelected; tmp; tmp = tmp->nextSibling( ) )
+ {
+ tmp->setSelected( true );
+ emit objectChanged( (( PMTreeViewItem* ) tmp)->object( ),
+ PMCSelected, this );
+ if( tmp == oldCurrent )
+ break;
+ }
+ }
+ }
+ else
+ m_pLastSelected->setSelected( false );
+ }
+ }
+ }
+ if( !specialAction )
+ {
+ // no special action
+ // object is selected or deselected, no other objects are changed
+ if( m_itemSelected )
+ {
+ if( m_pLastSelected->object( )->isSelectable( ) )
+ emit objectChanged( m_pLastSelected->object( ), PMCSelected, this );
+ else
+ m_pLastSelected->setSelected( false );
+ }
+ else if( m_itemDeselected )
+ emit objectChanged( m_pLastSelected->object( ), PMCDeselected, this );
+ }
+ m_acceptSelect = false;
+}
+
+void PMTreeView::contentsMouseMoveEvent( QMouseEvent * e )
+{
+ m_itemSelected = false;
+ m_itemDeselected = false;
+ m_pLastSelected = 0;
+ m_selectionCleared = false;
+
+ m_event = true;
+ QListView::contentsMouseMoveEvent( e );
+ m_event = false;
+
+ // ignore all selections/deselections
+ if( m_itemSelected || m_itemDeselected )
+ m_pLastSelected->setSelected( m_pLastSelected->object( )->isSelected( ) );
+}
+
+void PMTreeView::viewportMousePressEvent( QMouseEvent* e )
+{
+ m_acceptSelect = true;
+ QListView::viewportMousePressEvent( e );
+ m_acceptSelect = false;
+
+ m_pressed = false;
+
+ QPoint p = e->pos( );
+
+ if( e->button( ) & RightButton )
+ {
+ if( m_pPart->factory( ) )
+ {
+ QPopupMenu* m =
+ ( QPopupMenu* ) m_pPart->factory( )->container( "treeViewPopup", m_pPart );
+ if( m )
+ m->exec( QCursor::pos( ) );
+ }
+ return;
+ }
+
+ PMTreeViewItem *item = ( PMTreeViewItem* )itemAt( p );
+ if( item )
+ {
+ // check if the root decoration was clicked
+ if( !( p.x( ) > header( )->cellPos( header( )->mapToActual( 0 ) ) +
+ treeStepSize( ) * ( item->depth( ) + ( rootIsDecorated( ) ? 1 : 0 ) )
+ + itemMargin( ) ||
+ p.x( ) < header( )->cellPos( header( )->mapToActual( 0 ) ) ) )
+ item = 0; // p is on the root decoration
+ }
+
+ if( item )
+ {
+ if( e->button( ) == LeftButton || e->button( ) == MidButton )
+ {
+ m_pressed = true;
+ m_pressedPos = e->pos( );
+ m_pressedItem = item;
+ return;
+ }
+ }
+}
+
+void PMTreeView::viewportMouseReleaseEvent( QMouseEvent* e )
+{
+ QListView::viewportMouseReleaseEvent( e );
+
+ if( !m_pressed )
+ return;
+
+ m_pressed = false;
+ m_pressedItem = 0L;
+
+ if( m_selectOnReleaseEvent )
+ {
+ if( m_pLastSelected )
+ {
+ m_acceptSelect = true;
+ clearSelection( );
+ m_pLastSelected->setSelected( true );
+ m_acceptSelect = false;
+
+ emit objectChanged( m_pLastSelected->object( ), PMCNewSelection, this );
+ }
+ }
+}
+
+void PMTreeView::viewportMouseMoveEvent( QMouseEvent *e )
+{
+ QListView::viewportMouseMoveEvent( e );
+
+ if( m_pressed && m_pressedItem )
+ {
+ int x = e->pos( ).x( );
+ int y = e->pos( ).y( );
+
+ //Is it time to start a drag?
+ if( abs( x - m_pressedPos.x( ) ) > KGlobalSettings::dndEventDelay( ) ||
+ abs( y - m_pressedPos.y( ) ) > KGlobalSettings::dndEventDelay( ) )
+ {
+ m_selectOnReleaseEvent = false;
+
+ // Calculate hotspot
+ QPoint hotspot;
+ PMObjectList sortedList = m_pPart->selectedObjects( );
+
+ // Do not handle more mouse move or mouse release events
+ m_pressed = false;
+
+ if( sortedList.count( ) > 0 )
+ {
+ PMObjectDrag* d = new PMObjectDrag( m_pPart, sortedList, viewport( ) );
+
+ hotspot.setX( m_pressedItem->pixmap( 0 )->width( ) / 2 );
+ hotspot.setY( m_pressedItem->pixmap( 0 )->height( ) / 2 );
+ if( sortedList.count( ) == 1 )
+ d->setPixmap( SmallIcon(
+ sortedList.first( )->pixmap( ) ), hotspot );
+ else
+ d->setPixmap( SmallIcon( "pmdrag" ) );
+
+ if( d->drag( ) )
+ {
+ kdDebug( PMArea ) << "Drag returned true\n";
+ if( !targetDisplaysPart( d->target( ) ) )
+ m_pPart->dragMoveSelectionTo( 0 );
+ }
+ }
+ }
+ }
+}
+
+void PMTreeView::viewportDragMoveEvent( QDragMoveEvent *e )
+{
+ bool accept = false;
+
+ if( m_pPart->isReadWrite( ) )
+ {
+ if( PMObjectDrag::canDecode( e, m_pPart ) )
+ {
+ PMTreeViewItem *item = ( PMTreeViewItem* ) itemAt( e->pos( ) );
+ PMObject* obj = 0;
+
+ if( !item )
+ {
+ accept = false;
+ /*
+ if( e->source( ) == viewport( ) )
+ {
+ if( m_pPart->scene( )->isSelected( ) )
+ accept = false;
+ else
+ accept = true;
+ }
+ else
+ accept = true;
+ obj = m_pPart->scene( );
+ */
+
+ m_pDragOverItem = 0L;
+ obj = 0;
+ }
+ else
+ {
+ obj = item->object( );
+ if( ( obj->isSelectable( ) &&
+ !obj->isSelected( ) ) || ( e->source( ) != viewport( ) ) )
+ {
+ accept = true;
+ setCurrentItem( item );
+ m_pDragOverItem = item;
+ }
+ else
+ {
+ accept = false;
+ m_pDragOverItem = 0L;
+ }
+ }
+
+ if( accept )
+ {
+ accept = false;
+ if( !obj->isReadOnly( ) )
+ accept = true;
+ if( obj->parent( ) )
+ if( !obj->parent( )->isReadOnly( ) )
+ accept = true;
+ }
+ }
+ else
+ accept = false;
+ }
+ else
+ accept = false;
+
+ if( accept )
+ e->acceptAction( );
+ else
+ e->ignore( );
+}
+
+void PMTreeView::viewportDragEnterEvent( QDragEnterEvent *e )
+{
+ m_pDragOverItem = 0L;
+
+ if( m_pPart->isReadWrite( ) )
+ e->accept( PMObjectDrag::canDecode( e, m_pPart ) );
+ else
+ e->ignore( );
+}
+
+void PMTreeView::viewportDragLeaveEvent( QDragLeaveEvent* )
+{
+ m_pDragOverItem = 0L;
+}
+
+void PMTreeView::viewportDropEvent( QDropEvent* e )
+{
+ PMObject* obj;
+
+ if( m_pPart->isReadWrite( ) )
+ {
+ if( m_pDragOverItem )
+ obj = m_pDragOverItem->object( );
+ else
+ obj = m_pPart->scene( );
+
+ if( PMObjectDrag::canDecode( e, m_pPart ) )
+ {
+ if( targetDisplaysPart( e->source( ) ) &&
+ ( e->action( ) == QDropEvent::Move ) )
+ {
+ if( m_pPart->dragMoveSelectionTo( obj ) )
+ e->acceptAction( );
+ else
+ e->ignore( );
+ }
+ else
+ {
+ if( m_pPart->drop( obj, e ) )
+ e->acceptAction( );
+ else
+ e->ignore( );
+ }
+ }
+ else
+ e->ignore( );
+ }
+ else
+ e->ignore( );
+
+ m_pDragOverItem = 0L;
+}
+
+void PMTreeView::focusOutEvent( QFocusEvent* e )
+{
+ QWidget::focusOutEvent( e );
+ m_pressed = false;
+ m_pressedItem = 0;
+}
+
+void PMTreeView::focusInEvent( QFocusEvent* e )
+{
+ QWidget::focusInEvent( e );
+ m_pressed = false;
+ m_pressedItem = 0;
+}
+
+void PMTreeView::keyPressEvent( QKeyEvent* e )
+{
+ QListViewItem* current = currentItem( );
+ QListViewItem* newSelection = 0;
+ bool accept = false;
+ bool deleteItem = false;
+ bool pasteItem = false;
+
+ if( current )
+ {
+ switch( e->key( ) )
+ {
+ case Qt::Key_Up:
+ newSelection = current->itemAbove( );
+ accept = true;
+ break;
+ case Qt::Key_Down:
+ newSelection = current->itemBelow( );
+ accept = true;
+ break;
+ case Qt::Key_Left:
+ newSelection = current->parent( );
+ accept = true;
+ break;
+ case Qt::Key_Right:
+ newSelection = current->firstChild( );
+ accept = true;
+ break;
+ case Qt::Key_Plus:
+ current->setOpen( true );
+ accept = true;
+ break;
+ case Qt::Key_Minus:
+ current->setOpen( false );
+ accept = true;
+ case Qt::Key_Delete:
+ deleteItem = true;
+ accept = true;
+ break;
+ case Qt::CTRL+Qt::Key_V:
+ case Qt::SHIFT+Qt::Key_Insert:
+ pasteItem = true;
+ accept = true;
+ break;
+ }
+ }
+
+ if( newSelection )
+ {
+ m_acceptSelect = true;
+ clearSelection( );
+ newSelection->setSelected( true );
+ setCurrentItem( newSelection );
+ ensureItemVisible( newSelection );
+ m_acceptSelect = false;
+
+ emit objectChanged( ( ( PMTreeViewItem* ) newSelection )->object( ),
+ PMCNewSelection, this );
+ }
+
+ if( deleteItem && m_pPart->isReadWrite( ) )
+ {
+ m_pPart->slotEditDelete( );
+ m_pPart->setModified( true );
+ }
+
+ if( pasteItem && m_pPart->isReadWrite( ) )
+ {
+ m_pPart->slotEditPaste( );
+ m_pPart->setModified( true );
+ }
+
+ if( accept )
+ e->accept( );
+ else
+ e->ignore( );
+ QWidget::keyPressEvent( e );
+}
+
+bool PMTreeView::targetDisplaysPart( QWidget* target )
+{
+ bool result = false;
+ if( !target ) // another application
+ result = false;
+ else if( target == viewport( ) ) // self
+ result = true;
+ else
+ {
+ // Widget may be a view port
+ // find the tree view
+ QWidget* t = target;
+ while( t && !t->isA( "PMTreeView" ) )
+ t = t->parentWidget( );
+ if( t )
+ if( ( ( PMTreeView* ) t )->part( ) == m_pPart )
+ result = true;
+ }
+ return result;
+}
+
+QString PMTreeViewFactory::description( ) const
+{
+ return i18n( "Object Tree" );
+}
+
+#include "pmtreeview.moc"