Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[composer] Support drag and drop restacking of items via item panel (fix
  • Loading branch information
nyalldawson committed Sep 1, 2014
1 parent 5b1a516 commit a4377ae
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 4 deletions.
6 changes: 6 additions & 0 deletions src/app/composer/qgscomposer.cpp
Expand Up @@ -551,6 +551,12 @@ QgsComposer::QgsComposer( QgisApp *qgis, const QString& title )
mItemsTreeView->header()->setResizeMode( 0, QHeaderView::Fixed );
mItemsTreeView->header()->setResizeMode( 1, QHeaderView::Fixed );
mItemsTreeView->header()->setMovable( false );

mItemsTreeView->setDragEnabled( true );
mItemsTreeView->setAcceptDrops( true );
mItemsTreeView->setDropIndicatorShown( true );
mItemsTreeView->setDragDropMode( QAbstractItemView::InternalMove );

mItemsTreeView->setIndentation( 0 );
mItemsDock->setWidget( mItemsTreeView );
connect( mItemsTreeView->selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), mComposition->itemsModel(), SLOT( setSelected( QModelIndex ) ) );
Expand Down
174 changes: 170 additions & 4 deletions src/core/composer/qgscomposermodel.cpp
Expand Up @@ -281,6 +281,170 @@ QVariant QgsComposerModel::headerData( int section, Qt::Orientation orientation,

}

Qt::DropActions QgsComposerModel::supportedDropActions() const
{
return Qt::MoveAction;
}

QStringList QgsComposerModel::mimeTypes() const
{
QStringList types;
types << "application/x-vnd.qgis.qgis.composeritemid";
return types;
}

QMimeData* QgsComposerModel::mimeData( const QModelIndexList &indexes ) const
{
QMimeData *mimeData = new QMimeData();
QByteArray encodedData;

QDataStream stream( &encodedData, QIODevice::WriteOnly );

foreach ( const QModelIndex &index, indexes )
{
if ( index.isValid() && index.column() == ItemId )
{
QgsComposerItem *item = itemFromIndex( index );
if ( !item )
{
continue;
}
QString text = item->uuid();
stream << text;
}
}

mimeData->setData( "application/x-vnd.qgis.qgis.composeritemid", encodedData );
return mimeData;
}

bool zOrderDescending( QgsComposerItem* item1 , QgsComposerItem* item2 )
{
return item1->zValue() > item2->zValue();
}

bool QgsComposerModel::dropMimeData( const QMimeData *data,
Qt::DropAction action, int row, int column, const QModelIndex &parent )
{
if ( column != ItemId )
{
return false;
}

if ( action == Qt::IgnoreAction )
{
return true;
}

if ( !data->hasFormat( "application/x-vnd.qgis.qgis.composeritemid" ) )
{
return false;
}

if ( parent.isValid() )
{
return false;
}

int beginRow = row != -1 ? row : rowCount( QModelIndex() );

QByteArray encodedData = data->data( "application/x-vnd.qgis.qgis.composeritemid" );
QDataStream stream( &encodedData, QIODevice::ReadOnly );
QList<QgsComposerItem*> droppedItems;
int rows = 0;

while ( !stream.atEnd() )
{
QString text;
stream >> text;
const QgsComposerItem* item = mComposition->getComposerItemByUuid( text );
if ( item )
{
droppedItems << const_cast<QgsComposerItem*>( item );
++rows;
}
}

if ( droppedItems.length() == 0 )
{
//no dropped items
return false;
}

//move dropped items

//first sort them by z-order
qSort( droppedItems.begin(), droppedItems.end(), zOrderDescending );

//calculate position in z order list to drop items at
int destPos = 0;
if ( beginRow < rowCount() )
{
QgsComposerItem* itemBefore = mItemsInScene.at( beginRow );
destPos = mItemZList.indexOf( itemBefore );
}
else
{
//place items at end
destPos = mItemZList.size();
}

//calculate position to insert moved rows to
int insertPos = destPos;
QList<QgsComposerItem*>::iterator itemIt = droppedItems.begin();
for ( ; itemIt != droppedItems.end(); ++itemIt )
{
int listPos = mItemZList.indexOf( *itemIt );
if ( listPos == -1 )
{
//should be impossible
continue;
}

if ( listPos < destPos )
{
insertPos--;
}
}

//remove rows from list
itemIt = droppedItems.begin();
for ( ; itemIt != droppedItems.end(); ++itemIt )
{
mItemZList.removeOne( *itemIt );
}

//insert items
itemIt = droppedItems.begin();
for ( ; itemIt != droppedItems.end(); ++itemIt )
{
mItemZList.insert( insertPos, *itemIt );
insertPos++;
}

rebuildSceneItemList();
mComposition->updateZValues( false );

return true;
}

bool QgsComposerModel::removeRows( int row, int count, const QModelIndex &parent )
{
Q_UNUSED( count );
if ( parent.isValid() )
{
return false;
}

if ( row >= rowCount() )
{
return false;
}

//do nothing - moves are handled by the dropMimeData method
return true;
}

void QgsComposerModel::clear()
{
//totally reset model
Expand Down Expand Up @@ -727,20 +891,22 @@ QList<QgsComposerItem *>* QgsComposerModel::zOrderList()

Qt::ItemFlags QgsComposerModel::flags( const QModelIndex & index ) const
{
Qt::ItemFlags flags = QAbstractItemModel::flags( index );

if ( ! index.isValid() )
{
return 0;
return flags | Qt::ItemIsDropEnabled;;
}

switch ( index.column() )
{
case Visibility:
case LockStatus:
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable;
return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
case ItemId:
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
default:
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/core/composer/qgscomposermodel.h
Expand Up @@ -67,6 +67,11 @@ class CORE_EXPORT QgsComposerModel: public QAbstractItemModel
Qt::ItemFlags flags( const QModelIndex & index ) const;
bool setData( const QModelIndex & index, const QVariant & value, int role );
QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
Qt::DropActions supportedDropActions() const;
virtual QStringList mimeTypes() const;
virtual QMimeData* mimeData( const QModelIndexList &indexes ) const;
bool dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent );
bool removeRows( int row, int count, const QModelIndex & parent = QModelIndex() );

/**Clears all items from z-order list and resets the model
* @note added in QGIS 2.5
Expand Down
1 change: 1 addition & 0 deletions src/core/composer/qgscomposition.h
Expand Up @@ -797,6 +797,7 @@ class CORE_EXPORT QgsComposition : public QGraphicsScene
void statusMsgChanged( QString message );

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

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

0 comments on commit a4377ae

Please sign in to comment.