Skip to content

Commit a4377ae

Browse files
committedSep 1, 2014
[composer] Support drag and drop restacking of items via item panel (fix #11058)
1 parent 5b1a516 commit a4377ae

File tree

4 files changed

+182
-4
lines changed

4 files changed

+182
-4
lines changed
 

‎src/app/composer/qgscomposer.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,12 @@ QgsComposer::QgsComposer( QgisApp *qgis, const QString& title )
551551
mItemsTreeView->header()->setResizeMode( 0, QHeaderView::Fixed );
552552
mItemsTreeView->header()->setResizeMode( 1, QHeaderView::Fixed );
553553
mItemsTreeView->header()->setMovable( false );
554+
555+
mItemsTreeView->setDragEnabled( true );
556+
mItemsTreeView->setAcceptDrops( true );
557+
mItemsTreeView->setDropIndicatorShown( true );
558+
mItemsTreeView->setDragDropMode( QAbstractItemView::InternalMove );
559+
554560
mItemsTreeView->setIndentation( 0 );
555561
mItemsDock->setWidget( mItemsTreeView );
556562
connect( mItemsTreeView->selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), mComposition->itemsModel(), SLOT( setSelected( QModelIndex ) ) );

‎src/core/composer/qgscomposermodel.cpp

Lines changed: 170 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,170 @@ QVariant QgsComposerModel::headerData( int section, Qt::Orientation orientation,
281281

282282
}
283283

284+
Qt::DropActions QgsComposerModel::supportedDropActions() const
285+
{
286+
return Qt::MoveAction;
287+
}
288+
289+
QStringList QgsComposerModel::mimeTypes() const
290+
{
291+
QStringList types;
292+
types << "application/x-vnd.qgis.qgis.composeritemid";
293+
return types;
294+
}
295+
296+
QMimeData* QgsComposerModel::mimeData( const QModelIndexList &indexes ) const
297+
{
298+
QMimeData *mimeData = new QMimeData();
299+
QByteArray encodedData;
300+
301+
QDataStream stream( &encodedData, QIODevice::WriteOnly );
302+
303+
foreach ( const QModelIndex &index, indexes )
304+
{
305+
if ( index.isValid() && index.column() == ItemId )
306+
{
307+
QgsComposerItem *item = itemFromIndex( index );
308+
if ( !item )
309+
{
310+
continue;
311+
}
312+
QString text = item->uuid();
313+
stream << text;
314+
}
315+
}
316+
317+
mimeData->setData( "application/x-vnd.qgis.qgis.composeritemid", encodedData );
318+
return mimeData;
319+
}
320+
321+
bool zOrderDescending( QgsComposerItem* item1 , QgsComposerItem* item2 )
322+
{
323+
return item1->zValue() > item2->zValue();
324+
}
325+
326+
bool QgsComposerModel::dropMimeData( const QMimeData *data,
327+
Qt::DropAction action, int row, int column, const QModelIndex &parent )
328+
{
329+
if ( column != ItemId )
330+
{
331+
return false;
332+
}
333+
334+
if ( action == Qt::IgnoreAction )
335+
{
336+
return true;
337+
}
338+
339+
if ( !data->hasFormat( "application/x-vnd.qgis.qgis.composeritemid" ) )
340+
{
341+
return false;
342+
}
343+
344+
if ( parent.isValid() )
345+
{
346+
return false;
347+
}
348+
349+
int beginRow = row != -1 ? row : rowCount( QModelIndex() );
350+
351+
QByteArray encodedData = data->data( "application/x-vnd.qgis.qgis.composeritemid" );
352+
QDataStream stream( &encodedData, QIODevice::ReadOnly );
353+
QList<QgsComposerItem*> droppedItems;
354+
int rows = 0;
355+
356+
while ( !stream.atEnd() )
357+
{
358+
QString text;
359+
stream >> text;
360+
const QgsComposerItem* item = mComposition->getComposerItemByUuid( text );
361+
if ( item )
362+
{
363+
droppedItems << const_cast<QgsComposerItem*>( item );
364+
++rows;
365+
}
366+
}
367+
368+
if ( droppedItems.length() == 0 )
369+
{
370+
//no dropped items
371+
return false;
372+
}
373+
374+
//move dropped items
375+
376+
//first sort them by z-order
377+
qSort( droppedItems.begin(), droppedItems.end(), zOrderDescending );
378+
379+
//calculate position in z order list to drop items at
380+
int destPos = 0;
381+
if ( beginRow < rowCount() )
382+
{
383+
QgsComposerItem* itemBefore = mItemsInScene.at( beginRow );
384+
destPos = mItemZList.indexOf( itemBefore );
385+
}
386+
else
387+
{
388+
//place items at end
389+
destPos = mItemZList.size();
390+
}
391+
392+
//calculate position to insert moved rows to
393+
int insertPos = destPos;
394+
QList<QgsComposerItem*>::iterator itemIt = droppedItems.begin();
395+
for ( ; itemIt != droppedItems.end(); ++itemIt )
396+
{
397+
int listPos = mItemZList.indexOf( *itemIt );
398+
if ( listPos == -1 )
399+
{
400+
//should be impossible
401+
continue;
402+
}
403+
404+
if ( listPos < destPos )
405+
{
406+
insertPos--;
407+
}
408+
}
409+
410+
//remove rows from list
411+
itemIt = droppedItems.begin();
412+
for ( ; itemIt != droppedItems.end(); ++itemIt )
413+
{
414+
mItemZList.removeOne( *itemIt );
415+
}
416+
417+
//insert items
418+
itemIt = droppedItems.begin();
419+
for ( ; itemIt != droppedItems.end(); ++itemIt )
420+
{
421+
mItemZList.insert( insertPos, *itemIt );
422+
insertPos++;
423+
}
424+
425+
rebuildSceneItemList();
426+
mComposition->updateZValues( false );
427+
428+
return true;
429+
}
430+
431+
bool QgsComposerModel::removeRows( int row, int count, const QModelIndex &parent )
432+
{
433+
Q_UNUSED( count );
434+
if ( parent.isValid() )
435+
{
436+
return false;
437+
}
438+
439+
if ( row >= rowCount() )
440+
{
441+
return false;
442+
}
443+
444+
//do nothing - moves are handled by the dropMimeData method
445+
return true;
446+
}
447+
284448
void QgsComposerModel::clear()
285449
{
286450
//totally reset model
@@ -727,20 +891,22 @@ QList<QgsComposerItem *>* QgsComposerModel::zOrderList()
727891

728892
Qt::ItemFlags QgsComposerModel::flags( const QModelIndex & index ) const
729893
{
894+
Qt::ItemFlags flags = QAbstractItemModel::flags( index );
895+
730896
if ( ! index.isValid() )
731897
{
732-
return 0;
898+
return flags | Qt::ItemIsDropEnabled;;
733899
}
734900

735901
switch ( index.column() )
736902
{
737903
case Visibility:
738904
case LockStatus:
739-
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable;
905+
return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
740906
case ItemId:
741-
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
907+
return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
742908
default:
743-
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
909+
return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
744910
}
745911
}
746912

‎src/core/composer/qgscomposermodel.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ class CORE_EXPORT QgsComposerModel: public QAbstractItemModel
6767
Qt::ItemFlags flags( const QModelIndex & index ) const;
6868
bool setData( const QModelIndex & index, const QVariant & value, int role );
6969
QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
70+
Qt::DropActions supportedDropActions() const;
71+
virtual QStringList mimeTypes() const;
72+
virtual QMimeData* mimeData( const QModelIndexList &indexes ) const;
73+
bool dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent );
74+
bool removeRows( int row, int count, const QModelIndex & parent = QModelIndex() );
7075

7176
/**Clears all items from z-order list and resets the model
7277
* @note added in QGIS 2.5

‎src/core/composer/qgscomposition.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,7 @@ class CORE_EXPORT QgsComposition : public QGraphicsScene
797797
void statusMsgChanged( QString message );
798798

799799
friend class QgsComposerObject; //for accessing dataDefinedEvaluate, readDataDefinedPropertyMap and writeDataDefinedPropertyMap
800+
friend class QgsComposerModel; //for accessing updateZValues (should not be public)
800801
};
801802

802803
template<class T> void QgsComposition::composerItems( QList<T*>& itemList )

0 commit comments

Comments
 (0)
Please sign in to comment.