Skip to content
Permalink
Browse files
[FEATURE] Drag'n'drop layers from layer tree view to browser dock
Makes it easy to e.g. store your temporary layers in PostGIS
  • Loading branch information
wonder-sk committed Aug 22, 2016
1 parent b101510 commit 26dd130
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 9 deletions.
@@ -40,4 +40,10 @@ class QgsMimeDataUtils

static UriList decodeUriList( const QMimeData* data );

/**
* Returns encoded URI list from a list of layer tree nodes.
* @note added in QGIS 3.0
*/
static QByteArray layerTreeNodesToUriList( const QList<QgsLayerTreeNode*>& nodes );

};
@@ -1273,7 +1273,9 @@ void QgisApp::dragEnterEvent( QDragEnterEvent *event )
{
if ( event->mimeData()->hasUrls() || event->mimeData()->hasFormat( "application/x-vnd.qgis.qgis.uri" ) )
{
event->acceptProposedAction();
// the mime data are coming from layer tree, so ignore that, do not import those layers again
if ( !event->mimeData()->hasFormat( "application/qgis.layertreemodeldata" ) )
event->acceptProposedAction();
}
}

@@ -767,6 +767,12 @@ QgsDockBrowserTreeView::QgsDockBrowserTreeView( QWidget* parent ) : QgsBrowserTr

void QgsDockBrowserTreeView::dragEnterEvent( QDragEnterEvent* e )
{
// if this mime data come from layer tree, the proposed action will be MoveAction
// but for browser we really need CopyAction
if ( e->mimeData()->hasFormat( "application/qgis.layertreemodeldata" ) &&
e->mimeData()->hasFormat( "application/x-vnd.qgis.qgis.uri" ) )
e->setDropAction( Qt::CopyAction );

// accept drag enter so that our widget will not get ignored
// and drag events will not get passed to QgisApp
e->accept();
@@ -782,6 +788,12 @@ void QgsDockBrowserTreeView::dragMoveEvent( QDragMoveEvent* e )
return;
}*/

// if this mime data come from layer tree, the proposed action will be MoveAction
// but for browser we really need CopyAction
if ( e->mimeData()->hasFormat( "application/qgis.layertreemodeldata" ) &&
e->mimeData()->hasFormat( "application/x-vnd.qgis.qgis.uri" ) )
e->setDropAction( Qt::CopyAction );

QTreeView::dragMoveEvent( e );

if ( !e->mimeData()->hasFormat( "application/x-vnd.qgis.qgis.uri" ) )
@@ -791,6 +803,17 @@ void QgsDockBrowserTreeView::dragMoveEvent( QDragMoveEvent* e )
}
}

void QgsDockBrowserTreeView::dropEvent( QDropEvent *e )
{
// if this mime data come from layer tree, the proposed action will be MoveAction
// but for browser we really need CopyAction
if ( e->mimeData()->hasFormat( "application/qgis.layertreemodeldata" ) &&
e->mimeData()->hasFormat( "application/x-vnd.qgis.qgis.uri" ) )
e->setDropAction( Qt::CopyAction );

QTreeView::dropEvent( e );
}


//
// QgsBrowserTreeFilterProxyModel
@@ -173,6 +173,7 @@ class QgsDockBrowserTreeView : public QgsBrowserTreeView

void dragEnterEvent( QDragEnterEvent* e ) override;
void dragMoveEvent( QDragMoveEvent* e ) override;
void dropEvent( QDropEvent* e ) override;
};

/**
@@ -1011,6 +1011,9 @@ QMimeData* QgsLayerTreeModel::mimeData( const QModelIndexList& indexes ) const
QString txt = doc.toString();

mimeData->setData( "application/qgis.layertreemodeldata", txt.toUtf8() );

mimeData->setData( "application/x-vnd.qgis.qgis.uri", QgsMimeDataUtils::layerTreeNodesToUriList( nodesFinal ) );

return mimeData;
}

@@ -17,7 +17,13 @@
#include "qgsmimedatautils.h"

#include "qgsdataitem.h"
#include "qgslayertree.h"
#include "qgslogger.h"
#include "qgspluginlayer.h"
#include "qgsrasterdataprovider.h"
#include "qgsrasterlayer.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"

static const char* QGIS_URILIST_MIMETYPE = "application/x-vnd.qgis.qgis.uri";

@@ -70,15 +76,8 @@ bool QgsMimeDataUtils::isUriList( const QMimeData* data )
QMimeData* QgsMimeDataUtils::encodeUriList( const QgsMimeDataUtils::UriList& layers )
{
QMimeData *mimeData = new QMimeData();
QByteArray encodedData;

QDataStream stream( &encodedData, QIODevice::WriteOnly );
Q_FOREACH ( const Uri& u, layers )
{
stream << u.data();
}

mimeData->setData( QGIS_URILIST_MIMETYPE, encodedData );
mimeData->setData( QGIS_URILIST_MIMETYPE, uriListToByteArray( layers ) );
return mimeData;
}

@@ -98,6 +97,52 @@ QgsMimeDataUtils::UriList QgsMimeDataUtils::decodeUriList( const QMimeData* data
return list;
}


static void _addLayerTreeNodeToUriList( QgsLayerTreeNode* node, QgsMimeDataUtils::UriList& uris )
{
if ( QgsLayerTree::isGroup( node ) )
{
Q_FOREACH ( QgsLayerTreeNode* child, QgsLayerTree::toGroup( node )->children() )
_addLayerTreeNodeToUriList( child, uris );
}
else if ( QgsLayerTree::isLayer( node ) )
{
QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
if ( !nodeLayer->layer() )
return;

QgsMimeDataUtils::Uri uri;
if ( QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( nodeLayer->layer() ) )
{
uri.layerType = "vector";
uri.name = vlayer->name();
uri.providerKey = vlayer->dataProvider()->name();
uri.uri = vlayer->dataProvider()->dataSourceUri();
}
else if ( QgsRasterLayer* rlayer = qobject_cast<QgsRasterLayer*>( nodeLayer->layer() ) )
{
uri.layerType = "raster";
uri.name = rlayer->name();
uri.providerKey = rlayer->dataProvider()->name();
uri.uri = rlayer->dataProvider()->dataSourceUri();
}
else
{
// plugin layers do not have a standard way of storing their URI...
return;
}
uris << uri;
}
}

QByteArray QgsMimeDataUtils::layerTreeNodesToUriList( const QList<QgsLayerTreeNode *>& nodes )
{
UriList uris;
Q_FOREACH ( QgsLayerTreeNode* node, nodes )
_addLayerTreeNodeToUriList( node, uris );
return uriListToByteArray( uris );
}

QString QgsMimeDataUtils::encode( const QStringList& items )
{
QString encoded;
@@ -141,3 +186,15 @@ QStringList QgsMimeDataUtils::decode( const QString& encoded )
return items;
}


QByteArray QgsMimeDataUtils::uriListToByteArray( const QgsMimeDataUtils::UriList& layers )
{
QByteArray encodedData;

QDataStream stream( &encodedData, QIODevice::WriteOnly );
Q_FOREACH ( const Uri& u, layers )
{
stream << u.data();
}
return encodedData;
}
@@ -19,6 +19,7 @@
#include <QStringList>

class QgsLayerItem;
class QgsLayerTreeNode;

/** \ingroup core
* \class QgsMimeDataUtils
@@ -62,9 +63,16 @@ class CORE_EXPORT QgsMimeDataUtils

static UriList decodeUriList( const QMimeData* data );

/**
* Returns encoded URI list from a list of layer tree nodes.
* @note added in QGIS 3.0
*/
static QByteArray layerTreeNodesToUriList( const QList<QgsLayerTreeNode*>& nodes );

private:
static QString encode( const QStringList& items );
static QStringList decode( const QString& encoded );
static QByteArray uriListToByteArray( const UriList& layers );

};

2 comments on commit 26dd130

@3nids
Copy link
Member

@3nids 3nids commented on 26dd130 Aug 22, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or shape to Postgis with a simple drag'n'drop....so cool, thanks!

@gioman
Copy link
Contributor

@gioman gioman commented on 26dd130 Aug 22, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@3nids that was already possible from within the browser, but doing it from the layer tree gave users much more flexibility. Very cool indeed!

Please sign in to comment.