diff options
Diffstat (limited to 'kdevdesigner/designer/listviewdnd.cpp')
-rw-r--r-- | kdevdesigner/designer/listviewdnd.cpp | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/kdevdesigner/designer/listviewdnd.cpp b/kdevdesigner/designer/listviewdnd.cpp new file mode 100644 index 00000000..b4098237 --- /dev/null +++ b/kdevdesigner/designer/listviewdnd.cpp @@ -0,0 +1,432 @@ +/********************************************************************** +** Copyright (C) 2002 Trolltech AS. All rights reserved. +** +** This file is part of Qt Designer. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** See http://www.trolltech.com/pricing.html or email [email protected] for +** information about Qt Commercial License Agreements. +** +** Contact [email protected] if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "listviewdnd.h" +#include <qwidget.h> +#include <qheader.h> +#include <qpainter.h> +#include <qdragobject.h> +#include <qvaluelist.h> + +// The Dragobject Declaration --------------------------------------- +class ListViewItemDrag : public QStoredDrag +{ +public: + enum DropRelation { Sibling, Child }; + ListViewItemDrag( ListViewItemList & items, QWidget * parent = 0, const char * name = 0 ); + ~ListViewItemDrag() {}; + static bool canDecode( QDragMoveEvent * event ); + static bool decode( QDropEvent * event, QListView * parent, QListViewItem * insertPoint, DropRelation dr ); +}; +// ------------------------------------------------------------------ + +ListViewDnd::ListViewDnd( QListView * eventSource, const char * name ) + : ListDnd( eventSource, name ) { } + +void ListViewDnd::confirmDrop( QListViewItem * ) +{ + dropConfirmed = TRUE; +} + +bool ListViewDnd::dropEvent( QDropEvent * event ) +{ + if ( dragInside ) { + + if ( dMode & NullDrop ) { // combined with Move, a NullDrop will delete an item + event->accept(); + emit dropped( 0 ); // a NullDrop + return TRUE; + } + + QPoint pos = event->pos(); + + ListViewItemDrag::DropRelation dr = ListViewItemDrag::Sibling; + QListViewItem *item = itemAt( pos ); + int dpos = dropDepth( item, pos ); + + if ( item ) { + if ( dpos > item->depth() && !(dMode & Flat) ) { + // Child node + dr = ListViewItemDrag::Child; + } else if ( dpos < item->depth() ) { + // Parent(s) Sibling + while ( item && (item->depth() > dpos) ) + item = item->parent(); + } + } + + if ( ListViewItemDrag::decode( event, (QListView *) src, item, dr ) ) { + event->accept(); + emit dropped( 0 ); // Use ID instead of item? + } + } + + line->hide(); + dragInside = FALSE; + + return TRUE; +} + +bool ListViewDnd::mouseMoveEvent( QMouseEvent * event ) +{ + if ( event->state() & LeftButton ) { + if ( ( event->pos() - mousePressPos ).manhattanLength() > 3 ) { + ListViewItemList list; + + if ( dMode & Flat ) + buildFlatList( list ); + else + buildTreeList( list ); + + ListViewItemDrag * dragobject = new ListViewItemDrag( list, (QListView *) src ); + + if ( dMode & Move ) { + disabledItems = list; + setVisibleItems( FALSE ); + } + + dragobject->dragCopy(); + + if ( dMode & Move ) { + // Did the target accept the drop? + if ( dropConfirmed ) { + // Shouldn't autoDelete handle this? + for( list.first(); list.current(); list.next() ) + delete list.current(); + dropConfirmed = FALSE; + } else { + // Reenable disabled items since + // drag'n'drop was aborted + setVisibleItems( TRUE ); + } + disabledItems.clear(); + } + } + } + return FALSE; +} + +int ListViewDnd::buildFlatList( ListViewItemList & list ) +{ + bool addKids = FALSE; + QListViewItem *nextSibling = 0; + QListViewItem *nextParent = 0; + QListViewItemIterator it = ((QListView *)src)->firstChild(); + for ( ; *it; it++ ) { + // Hit the nextSibling, turn of child processing + if ( (*it) == nextSibling ) + addKids = FALSE; + + if ( (*it)->isSelected() ) { + if ( (*it)->childCount() == 0 ) { + // Selected, no children + list.append( *it ); + } else if ( !addKids ) { + // Children processing not set, so set it + // Also find the item were we shall quit + // processing children...if any such item + addKids = TRUE; + nextSibling = (*it)->nextSibling(); + nextParent = (*it)->parent(); + while ( nextParent && !nextSibling ) { + nextSibling = nextParent->nextSibling(); + nextParent = nextParent->parent(); + } + } + } else if ( ((*it)->childCount() == 0) && addKids ) { + // Leaf node, and we _do_ process children + list.append( *it ); + } + } + return list.count(); +} + +int ListViewDnd::buildTreeList( ListViewItemList & list ) +{ + QListViewItemIterator it = ((QListView *)src)->firstChild(); + for ( ; *it; it++ ) { + if ( (*it)->isSelected() ) + list.append( *it ); + } + return list.count(); +} + +void ListViewDnd::setVisibleItems( bool b ) +{ + if ( disabledItems.isEmpty() ) + return; + + disabledItems.first(); + do { + disabledItems.current()->setVisible( b ); + } while ( disabledItems.next() ); +} + +void ListViewDnd::updateLine( const QPoint & dragPos ) +{ + QListViewItem * item = itemAt(dragPos); + QListView * src = (QListView *) this->src; + + int ypos = item ? + ( src->itemRect( item ).bottom() - ( line->height() / 2 ) ) : + ( src->itemRect( src->firstChild() ).top() ); + + int xpos = dropDepth( item, dragPos ) * src->treeStepSize(); + line->resize( src->viewport()->width() - xpos, line->height() ); + line->move( xpos, ypos ); +} + +QListViewItem * ListViewDnd::itemAt( QPoint pos ) +{ + QListView * src = (QListView *) this->src; + int headerHeight = (int)(src->header()->height()); + pos.ry() -= headerHeight; + QListViewItem * result = src->itemAt( pos ); + + if ( result && ( pos.ry() < (src->itemPos(result) + result->height()/2) ) ) + result = result->itemAbove(); + + // Wind back if has parent, and we're in flat mode + while ( result && result->parent() && (dMode & Flat) ) + result = result->parent(); + + // Wind back if has parent, and we're in flat mode + while ( result && !result->isVisible() && result->parent() ) + result = result->parent(); + + if ( !result && src->firstChild() && (pos.y() > src->itemRect(src->firstChild()).bottom()) ) { + result = src->lastItem(); + if ( !result->isVisible() ) + // Handle special case where last item is actually hidden + result = result->itemAbove(); + } + + return result; +} + +int ListViewDnd::dropDepth( QListViewItem * item, QPoint pos ) +{ + if ( !item || (dMode & Flat) ) + return 0; + + int result = 0; + int itemDepth = item->depth(); + int indentSize = ((QListView *)src)->treeStepSize(); + int itemLeft = indentSize * itemDepth; + int childMargin = indentSize*2; + if ( pos.x() > itemLeft + childMargin ) { + result = itemDepth + 1; + } else if ( pos.x() < itemLeft ) { + result = pos.x() / indentSize; + } else { + result = itemDepth; + } + return result; +} + +bool ListViewDnd::canDecode( QDragEnterEvent * event ) +{ + return ListViewItemDrag::canDecode( event ); +} + +// ------------------------------------------------------------------ +// The Dragobject Implementation ------------------------------------ +// ------------------------------------------------------------------ + +QDataStream & operator<< ( QDataStream & stream, const QListViewItem & item ); +QDataStream & operator>> ( QDataStream & stream, QListViewItem & item ); + +ListViewItemDrag::ListViewItemDrag( ListViewItemList & items, QWidget * parent, const char * name ) + : QStoredDrag( "qt/listviewitem", parent, name ) +{ + // ### FIX! + QByteArray data( sizeof( Q_INT32 ) + sizeof( QListViewItem ) * items.count() ); + QDataStream stream( data, IO_WriteOnly ); + + stream << items.count(); + + QListViewItem *i = items.first(); + while ( i ) { + stream << *i; + i = items.next(); + } + + setEncodedData( data ); +} + +bool ListViewItemDrag::canDecode( QDragMoveEvent * event ) +{ + return event->provides( "qt/listviewitem" ); +} + +bool ListViewItemDrag::decode( QDropEvent * event, QListView * parent, QListViewItem * insertPoint, DropRelation dr ) +{ + QByteArray data = event->encodedData( "qt/listviewitem" ); + QListViewItem* itemParent = insertPoint ? insertPoint->parent() : 0; + + // Change from sibling (default) to child creation + if ( insertPoint && dr == Child ) { + itemParent = insertPoint; + insertPoint = 0; + } + + if ( data.size() ) { + event->accept(); + QDataStream stream( data, IO_ReadOnly ); + + int count = 0; + stream >> count; + + for( int i = 0; i < count; i++ ) { + if ( itemParent ) { + insertPoint = new QListViewItem( itemParent, insertPoint ); + itemParent->setOpen( TRUE ); + } else { // No parent for insertPoint, use QListView + insertPoint = new QListViewItem( parent, insertPoint ); + } + stream >> *insertPoint; + } + return TRUE; + } + return FALSE; +} + + +QDataStream & operator<< ( QDataStream & stream, const QListViewItem & item ) +{ + int columns = item.listView()->columns(); + stream << columns; + + Q_UINT8 b = 0; + + int i; + for ( i = 0; i < columns; i++ ) { + b = (Q_UINT8) ( item.text( i ) != QString::null ); // does column i have a string ? + stream << b; + if ( b ) { + stream << item.text( i ); + } + } + + for ( i = 0; i < columns; i++ ) { + b = (Q_UINT8) ( !!item.pixmap( i ) ); // does column i have a pixmap ? + stream << b; + if ( b ) { + stream << ( *item.pixmap( i ) ); + } + } + + stream << (Q_UINT8) item.isOpen(); + stream << (Q_UINT8) item.isSelectable(); + stream << (Q_UINT8) item.isExpandable(); + stream << (Q_UINT8) item.dragEnabled(); + stream << (Q_UINT8) item.dropEnabled(); + stream << (Q_UINT8) item.isVisible(); + + for ( i = 0; i < columns; i++ ) { + stream << (Q_UINT8) item.renameEnabled( i ); + } + + stream << (Q_UINT8) item.multiLinesEnabled(); + stream << item.childCount(); + + if ( item.childCount() > 0 ) { + QListViewItem * child = item.firstChild(); + while ( child ) { + stream << ( *child ); // recursive call + child = child->nextSibling(); + } + } + + return stream; +} + +QDataStream & operator>> ( QDataStream & stream, QListViewItem & item ) +{ + Q_INT32 columns; + stream >> columns; + + Q_UINT8 b = 0; + + QString text; + int i; + for ( i = 0; i < columns; i++ ) { + stream >> b; + if ( b ) { // column i has string ? + stream >> text; + item.setText( i, text ); + } + } + + QPixmap pixmap; + for ( i = 0; i < columns; i++ ) { + stream >> b; // column i has pixmap ? + if ( b ) { + stream >> pixmap; + item.setPixmap( i, pixmap ); + } + } + + stream >> b; + item.setOpen( b ); + + stream >> b; + item.setSelectable( b ); + + stream >> b; + item.setExpandable( b ); + + stream >> b; + item.setDragEnabled( b ); + + stream >> b; + item.setDropEnabled( b ); + + stream >> b; + item.setVisible( b ); + + for ( i = 0; i < columns; i++ ) { + stream >> b; + item.setRenameEnabled( i, b ); + } + + stream >> b; + item.setMultiLinesEnabled( b ); + + int childCount; + stream >> childCount; + + QListViewItem *child = 0; + QListViewItem *prevchild = 0; + for ( i = 0; i < childCount; i++ ) { + child = new QListViewItem( &item, prevchild ); + stream >> ( *child ); + item.insertItem( child ); + prevchild = child; + } + + return stream; +} |