1
/**********************************************************************
2
** Copyright (C) 2002 Trolltech AS. All rights reserved.
4
** This file is part of Qt Designer.
6
** This file may be distributed and/or modified under the terms of the
7
** GNU General Public License version 2 as published by the Free Software
8
** Foundation and appearing in the file LICENSE.GPL included in the
9
** packaging of this file.
11
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
12
** licenses may use this file in accordance with the Qt Commercial License
13
** Agreement provided with the Software.
15
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18
** See http://www.trolltech.com/gpl/ for GPL licensing information.
19
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
20
** information about Qt Commercial License Agreements.
22
** Contact info@trolltech.com if any conditions of this licensing are
25
**********************************************************************/
27
#include "listviewdnd.h"
31
#include <qdragobject.h>
32
#include <qvaluelist.h>
34
// The Dragobject Declaration ---------------------------------------
35
class ListViewItemDrag : public QStoredDrag
38
enum DropRelation { Sibling, Child };
39
ListViewItemDrag( ListViewItemList & items, QWidget * parent = 0, const char * name = 0 );
40
~ListViewItemDrag() {};
41
static bool canDecode( QDragMoveEvent * event );
42
static bool decode( QDropEvent * event, QListView * parent, QListViewItem * insertPoint, DropRelation dr );
44
// ------------------------------------------------------------------
46
ListViewDnd::ListViewDnd( QListView * eventSource, const char * name )
47
: ListDnd( eventSource, name ) { }
49
void ListViewDnd::confirmDrop( QListViewItem * )
54
bool ListViewDnd::dropEvent( QDropEvent * event )
58
if ( dMode & NullDrop ) { // combined with Move, a NullDrop will delete an item
60
emit dropped( 0 ); // a NullDrop
64
QPoint pos = event->pos();
66
ListViewItemDrag::DropRelation dr = ListViewItemDrag::Sibling;
67
QListViewItem *item = itemAt( pos );
68
int dpos = dropDepth( item, pos );
71
if ( dpos > item->depth() && !(dMode & Flat) ) {
73
dr = ListViewItemDrag::Child;
74
} else if ( dpos < item->depth() ) {
76
while ( item && (item->depth() > dpos) )
77
item = item->parent();
81
if ( ListViewItemDrag::decode( event, (QListView *) src, item, dr ) ) {
83
emit dropped( 0 ); // Use ID instead of item?
93
bool ListViewDnd::mouseMoveEvent( QMouseEvent * event )
95
if ( event->state() & LeftButton ) {
96
if ( ( event->pos() - mousePressPos ).manhattanLength() > 3 ) {
97
ListViewItemList list;
100
buildFlatList( list );
102
buildTreeList( list );
104
ListViewItemDrag * dragobject = new ListViewItemDrag( list, (QListView *) src );
106
if ( dMode & Move ) {
107
disabledItems = list;
108
setVisibleItems( FALSE );
111
dragobject->dragCopy();
113
if ( dMode & Move ) {
114
// Did the target accept the drop?
115
if ( dropConfirmed ) {
116
// Shouldn't autoDelete handle this?
117
for( list.first(); list.current(); list.next() )
118
delete list.current();
119
dropConfirmed = FALSE;
121
// Reenable disabled items since
122
// drag'n'drop was aborted
123
setVisibleItems( TRUE );
125
disabledItems.clear();
132
int ListViewDnd::buildFlatList( ListViewItemList & list )
134
bool addKids = FALSE;
135
QListViewItem *nextSibling = 0;
136
QListViewItem *nextParent = 0;
137
QListViewItemIterator it = ((QListView *)src)->firstChild();
138
for ( ; *it; it++ ) {
139
// Hit the nextSibling, turn of child processing
140
if ( (*it) == nextSibling )
143
if ( (*it)->isSelected() ) {
144
if ( (*it)->childCount() == 0 ) {
145
// Selected, no children
147
} else if ( !addKids ) {
148
// Children processing not set, so set it
149
// Also find the item were we shall quit
150
// processing children...if any such item
152
nextSibling = (*it)->nextSibling();
153
nextParent = (*it)->parent();
154
while ( nextParent && !nextSibling ) {
155
nextSibling = nextParent->nextSibling();
156
nextParent = nextParent->parent();
159
} else if ( ((*it)->childCount() == 0) && addKids ) {
160
// Leaf node, and we _do_ process children
167
int ListViewDnd::buildTreeList( ListViewItemList & list )
169
QListViewItemIterator it = ((QListView *)src)->firstChild();
170
for ( ; *it; it++ ) {
171
if ( (*it)->isSelected() )
177
void ListViewDnd::setVisibleItems( bool b )
179
if ( disabledItems.isEmpty() )
182
disabledItems.first();
184
disabledItems.current()->setVisible( b );
185
} while ( disabledItems.next() );
188
void ListViewDnd::updateLine( const QPoint & dragPos )
190
QListViewItem * item = itemAt(dragPos);
191
QListView * src = (QListView *) this->src;
194
( src->itemRect( item ).bottom() - ( line->height() / 2 ) ) :
195
( src->itemRect( src->firstChild() ).top() );
197
int xpos = dropDepth( item, dragPos ) * src->treeStepSize();
198
line->resize( src->viewport()->width() - xpos, line->height() );
199
line->move( xpos, ypos );
202
QListViewItem * ListViewDnd::itemAt( QPoint pos )
204
QListView * src = (QListView *) this->src;
205
int headerHeight = (int)(src->header()->height());
206
pos.ry() -= headerHeight;
207
QListViewItem * result = src->itemAt( pos );
209
if ( result && ( pos.ry() < (src->itemPos(result) + result->height()/2) ) )
210
result = result->itemAbove();
212
// Wind back if has parent, and we're in flat mode
213
while ( result && result->parent() && (dMode & Flat) )
214
result = result->parent();
216
// Wind back if has parent, and we're in flat mode
217
while ( result && !result->isVisible() && result->parent() )
218
result = result->parent();
220
if ( !result && src->firstChild() && (pos.y() > src->itemRect(src->firstChild()).bottom()) ) {
221
result = src->lastItem();
222
if ( !result->isVisible() )
223
// Handle special case where last item is actually hidden
224
result = result->itemAbove();
230
int ListViewDnd::dropDepth( QListViewItem * item, QPoint pos )
232
if ( !item || (dMode & Flat) )
236
int itemDepth = item->depth();
237
int indentSize = ((QListView *)src)->treeStepSize();
238
int itemLeft = indentSize * itemDepth;
239
int childMargin = indentSize*2;
240
if ( pos.x() > itemLeft + childMargin ) {
241
result = itemDepth + 1;
242
} else if ( pos.x() < itemLeft ) {
243
result = pos.x() / indentSize;
250
bool ListViewDnd::canDecode( QDragEnterEvent * event )
252
return ListViewItemDrag::canDecode( event );
255
// ------------------------------------------------------------------
256
// The Dragobject Implementation ------------------------------------
257
// ------------------------------------------------------------------
259
QDataStream & operator<< ( QDataStream & stream, const QListViewItem & item );
260
QDataStream & operator>> ( QDataStream & stream, QListViewItem & item );
262
ListViewItemDrag::ListViewItemDrag( ListViewItemList & items, QWidget * parent, const char * name )
263
: QStoredDrag( "qt/listviewitem", parent, name )
266
QByteArray data( sizeof( Q_INT32 ) + sizeof( QListViewItem ) * items.count() );
267
QDataStream stream( data, IO_WriteOnly );
269
stream << items.count();
271
QListViewItem *i = items.first();
277
setEncodedData( data );
280
bool ListViewItemDrag::canDecode( QDragMoveEvent * event )
282
return event->provides( "qt/listviewitem" );
285
bool ListViewItemDrag::decode( QDropEvent * event, QListView * parent, QListViewItem * insertPoint, DropRelation dr )
287
QByteArray data = event->encodedData( "qt/listviewitem" );
288
QListViewItem* itemParent = insertPoint ? insertPoint->parent() : 0;
290
// Change from sibling (default) to child creation
291
if ( insertPoint && dr == Child ) {
292
itemParent = insertPoint;
298
QDataStream stream( data, IO_ReadOnly );
303
for( int i = 0; i < count; i++ ) {
305
insertPoint = new QListViewItem( itemParent, insertPoint );
306
itemParent->setOpen( TRUE );
307
} else { // No parent for insertPoint, use QListView
308
insertPoint = new QListViewItem( parent, insertPoint );
310
stream >> *insertPoint;
318
QDataStream & operator<< ( QDataStream & stream, const QListViewItem & item )
320
int columns = item.listView()->columns();
326
for ( i = 0; i < columns; i++ ) {
327
b = (Q_UINT8) ( item.text( i ) != QString::null ); // does column i have a string ?
330
stream << item.text( i );
334
for ( i = 0; i < columns; i++ ) {
335
b = (Q_UINT8) ( !!item.pixmap( i ) ); // does column i have a pixmap ?
338
stream << ( *item.pixmap( i ) );
342
stream << (Q_UINT8) item.isOpen();
343
stream << (Q_UINT8) item.isSelectable();
344
stream << (Q_UINT8) item.isExpandable();
345
stream << (Q_UINT8) item.dragEnabled();
346
stream << (Q_UINT8) item.dropEnabled();
347
stream << (Q_UINT8) item.isVisible();
349
for ( i = 0; i < columns; i++ ) {
350
stream << (Q_UINT8) item.renameEnabled( i );
353
stream << (Q_UINT8) item.multiLinesEnabled();
354
stream << item.childCount();
356
if ( item.childCount() > 0 ) {
357
QListViewItem * child = item.firstChild();
359
stream << ( *child ); // recursive call
360
child = child->nextSibling();
367
QDataStream & operator>> ( QDataStream & stream, QListViewItem & item )
376
for ( i = 0; i < columns; i++ ) {
378
if ( b ) { // column i has string ?
380
item.setText( i, text );
385
for ( i = 0; i < columns; i++ ) {
386
stream >> b; // column i has pixmap ?
389
item.setPixmap( i, pixmap );
397
item.setSelectable( b );
400
item.setExpandable( b );
403
item.setDragEnabled( b );
406
item.setDropEnabled( b );
409
item.setVisible( b );
411
for ( i = 0; i < columns; i++ ) {
413
item.setRenameEnabled( i, b );
417
item.setMultiLinesEnabled( b );
420
stream >> childCount;
422
QListViewItem *child = 0;
423
QListViewItem *prevchild = 0;
424
for ( i = 0; i < childCount; i++ ) {
425
child = new QListViewItem( &item, prevchild );
426
stream >> ( *child );
427
item.insertItem( child );