Skip to content

Commit 26dd130

Browse files
committed
[FEATURE] Drag'n'drop layers from layer tree view to browser dock
Makes it easy to e.g. store your temporary layers in PostGIS
1 parent b101510 commit 26dd130

7 files changed

+109
-9
lines changed

python/core/qgsmimedatautils.sip

+6
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,10 @@ class QgsMimeDataUtils
4040

4141
static UriList decodeUriList( const QMimeData* data );
4242

43+
/**
44+
* Returns encoded URI list from a list of layer tree nodes.
45+
* @note added in QGIS 3.0
46+
*/
47+
static QByteArray layerTreeNodesToUriList( const QList<QgsLayerTreeNode*>& nodes );
48+
4349
};

src/app/qgisapp.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -1273,7 +1273,9 @@ void QgisApp::dragEnterEvent( QDragEnterEvent *event )
12731273
{
12741274
if ( event->mimeData()->hasUrls() || event->mimeData()->hasFormat( "application/x-vnd.qgis.qgis.uri" ) )
12751275
{
1276-
event->acceptProposedAction();
1276+
// the mime data are coming from layer tree, so ignore that, do not import those layers again
1277+
if ( !event->mimeData()->hasFormat( "application/qgis.layertreemodeldata" ) )
1278+
event->acceptProposedAction();
12771279
}
12781280
}
12791281

src/app/qgsbrowserdockwidget.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,12 @@ QgsDockBrowserTreeView::QgsDockBrowserTreeView( QWidget* parent ) : QgsBrowserTr
767767

768768
void QgsDockBrowserTreeView::dragEnterEvent( QDragEnterEvent* e )
769769
{
770+
// if this mime data come from layer tree, the proposed action will be MoveAction
771+
// but for browser we really need CopyAction
772+
if ( e->mimeData()->hasFormat( "application/qgis.layertreemodeldata" ) &&
773+
e->mimeData()->hasFormat( "application/x-vnd.qgis.qgis.uri" ) )
774+
e->setDropAction( Qt::CopyAction );
775+
770776
// accept drag enter so that our widget will not get ignored
771777
// and drag events will not get passed to QgisApp
772778
e->accept();
@@ -782,6 +788,12 @@ void QgsDockBrowserTreeView::dragMoveEvent( QDragMoveEvent* e )
782788
return;
783789
}*/
784790

791+
// if this mime data come from layer tree, the proposed action will be MoveAction
792+
// but for browser we really need CopyAction
793+
if ( e->mimeData()->hasFormat( "application/qgis.layertreemodeldata" ) &&
794+
e->mimeData()->hasFormat( "application/x-vnd.qgis.qgis.uri" ) )
795+
e->setDropAction( Qt::CopyAction );
796+
785797
QTreeView::dragMoveEvent( e );
786798

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

806+
void QgsDockBrowserTreeView::dropEvent( QDropEvent *e )
807+
{
808+
// if this mime data come from layer tree, the proposed action will be MoveAction
809+
// but for browser we really need CopyAction
810+
if ( e->mimeData()->hasFormat( "application/qgis.layertreemodeldata" ) &&
811+
e->mimeData()->hasFormat( "application/x-vnd.qgis.qgis.uri" ) )
812+
e->setDropAction( Qt::CopyAction );
813+
814+
QTreeView::dropEvent( e );
815+
}
816+
794817

795818
//
796819
// QgsBrowserTreeFilterProxyModel

src/app/qgsbrowserdockwidget.h

+1
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ class QgsDockBrowserTreeView : public QgsBrowserTreeView
173173

174174
void dragEnterEvent( QDragEnterEvent* e ) override;
175175
void dragMoveEvent( QDragMoveEvent* e ) override;
176+
void dropEvent( QDropEvent* e ) override;
176177
};
177178

178179
/**

src/core/layertree/qgslayertreemodel.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -1011,6 +1011,9 @@ QMimeData* QgsLayerTreeModel::mimeData( const QModelIndexList& indexes ) const
10111011
QString txt = doc.toString();
10121012

10131013
mimeData->setData( "application/qgis.layertreemodeldata", txt.toUtf8() );
1014+
1015+
mimeData->setData( "application/x-vnd.qgis.qgis.uri", QgsMimeDataUtils::layerTreeNodesToUriList( nodesFinal ) );
1016+
10141017
return mimeData;
10151018
}
10161019

src/core/qgsmimedatautils.cpp

+65-8
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@
1717
#include "qgsmimedatautils.h"
1818

1919
#include "qgsdataitem.h"
20+
#include "qgslayertree.h"
2021
#include "qgslogger.h"
22+
#include "qgspluginlayer.h"
23+
#include "qgsrasterdataprovider.h"
24+
#include "qgsrasterlayer.h"
25+
#include "qgsvectordataprovider.h"
26+
#include "qgsvectorlayer.h"
2127

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

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

75-
QDataStream stream( &encodedData, QIODevice::WriteOnly );
76-
Q_FOREACH ( const Uri& u, layers )
77-
{
78-
stream << u.data();
79-
}
80-
81-
mimeData->setData( QGIS_URILIST_MIMETYPE, encodedData );
80+
mimeData->setData( QGIS_URILIST_MIMETYPE, uriListToByteArray( layers ) );
8281
return mimeData;
8382
}
8483

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

100+
101+
static void _addLayerTreeNodeToUriList( QgsLayerTreeNode* node, QgsMimeDataUtils::UriList& uris )
102+
{
103+
if ( QgsLayerTree::isGroup( node ) )
104+
{
105+
Q_FOREACH ( QgsLayerTreeNode* child, QgsLayerTree::toGroup( node )->children() )
106+
_addLayerTreeNodeToUriList( child, uris );
107+
}
108+
else if ( QgsLayerTree::isLayer( node ) )
109+
{
110+
QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
111+
if ( !nodeLayer->layer() )
112+
return;
113+
114+
QgsMimeDataUtils::Uri uri;
115+
if ( QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( nodeLayer->layer() ) )
116+
{
117+
uri.layerType = "vector";
118+
uri.name = vlayer->name();
119+
uri.providerKey = vlayer->dataProvider()->name();
120+
uri.uri = vlayer->dataProvider()->dataSourceUri();
121+
}
122+
else if ( QgsRasterLayer* rlayer = qobject_cast<QgsRasterLayer*>( nodeLayer->layer() ) )
123+
{
124+
uri.layerType = "raster";
125+
uri.name = rlayer->name();
126+
uri.providerKey = rlayer->dataProvider()->name();
127+
uri.uri = rlayer->dataProvider()->dataSourceUri();
128+
}
129+
else
130+
{
131+
// plugin layers do not have a standard way of storing their URI...
132+
return;
133+
}
134+
uris << uri;
135+
}
136+
}
137+
138+
QByteArray QgsMimeDataUtils::layerTreeNodesToUriList( const QList<QgsLayerTreeNode *>& nodes )
139+
{
140+
UriList uris;
141+
Q_FOREACH ( QgsLayerTreeNode* node, nodes )
142+
_addLayerTreeNodeToUriList( node, uris );
143+
return uriListToByteArray( uris );
144+
}
145+
101146
QString QgsMimeDataUtils::encode( const QStringList& items )
102147
{
103148
QString encoded;
@@ -141,3 +186,15 @@ QStringList QgsMimeDataUtils::decode( const QString& encoded )
141186
return items;
142187
}
143188

189+
190+
QByteArray QgsMimeDataUtils::uriListToByteArray( const QgsMimeDataUtils::UriList& layers )
191+
{
192+
QByteArray encodedData;
193+
194+
QDataStream stream( &encodedData, QIODevice::WriteOnly );
195+
Q_FOREACH ( const Uri& u, layers )
196+
{
197+
stream << u.data();
198+
}
199+
return encodedData;
200+
}

src/core/qgsmimedatautils.h

+8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <QStringList>
2020

2121
class QgsLayerItem;
22+
class QgsLayerTreeNode;
2223

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

6364
static UriList decodeUriList( const QMimeData* data );
6465

66+
/**
67+
* Returns encoded URI list from a list of layer tree nodes.
68+
* @note added in QGIS 3.0
69+
*/
70+
static QByteArray layerTreeNodesToUriList( const QList<QgsLayerTreeNode*>& nodes );
71+
6572
private:
6673
static QString encode( const QStringList& items );
6774
static QStringList decode( const QString& encoded );
75+
static QByteArray uriListToByteArray( const UriList& layers );
6876

6977
};
7078

0 commit comments

Comments
 (0)