From fb6f181fa80bdcc49efb416031a722c6c2312f8a Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Wed, 21 Jun 2017 15:11:11 +0200 Subject: [PATCH] support copy vector layer to browser postgres/spatialite by drag and drop --- python/core/qgsmimedatautils.sip | 8 ++++ python/core/qgsvectorlayerexporter.sip | 4 +- src/core/qgsmimedatautils.cpp | 43 ++++++++++++++++++- src/core/qgsmimedatautils.h | 7 +++ src/core/qgsvectorlayerexporter.cpp | 3 +- src/core/qgsvectorlayerexporter.h | 4 +- .../postgres/qgspostgresdataitems.cpp | 15 ++++--- .../spatialite/qgsspatialitedataitems.cpp | 15 ++++--- 8 files changed, 81 insertions(+), 18 deletions(-) diff --git a/python/core/qgsmimedatautils.sip b/python/core/qgsmimedatautils.sip index ad829da927b..6f9c062d79c 100644 --- a/python/core/qgsmimedatautils.sip +++ b/python/core/qgsmimedatautils.sip @@ -40,6 +40,14 @@ Returns encoded representation of the object :rtype: str %End + QgsVectorLayer *vectorLayer( bool &owner, QString &error ) const; +%Docstring + Get vector layer from uri if possible, otherwise returns 0 and error is set + \param owner set to true if caller becomes owner + \param error set to error message if cannot get vector + :rtype: QgsVectorLayer +%End + QString layerType; %Docstring Type of URI. Recognized types: "vector" / "raster" / "plugin" / "custom" diff --git a/python/core/qgsvectorlayerexporter.sip b/python/core/qgsvectorlayerexporter.sip index 73e2c795534..bc3a28508c9 100644 --- a/python/core/qgsvectorlayerexporter.sip +++ b/python/core/qgsvectorlayerexporter.sip @@ -149,11 +149,13 @@ class QgsVectorLayerExporterTask : QgsTask const QString &uri, const QString &providerKey, const QgsCoordinateReferenceSystem &destinationCrs, - QMap *options = 0 ); + QMap *options = 0, + bool ownsLayer = false ); %Docstring Constructor for QgsVectorLayerExporterTask. Takes a source ``layer``, destination ``uri`` and ``providerKey``, and various export related parameters such as destination CRS and export ``options``. + \param ownsLayer take ownership of layer and deletes it after export %End static QgsVectorLayerExporterTask *withLayerOwnership( QgsVectorLayer *layer /Transfer/, diff --git a/src/core/qgsmimedatautils.cpp b/src/core/qgsmimedatautils.cpp index 93301f78e3d..9d1b6cc9a42 100644 --- a/src/core/qgsmimedatautils.cpp +++ b/src/core/qgsmimedatautils.cpp @@ -27,7 +27,6 @@ static const char *QGIS_URILIST_MIMETYPE = "application/x-vnd.qgis.qgis.uri"; - QgsMimeDataUtils::Uri::Uri() { } @@ -66,6 +65,41 @@ QString QgsMimeDataUtils::Uri::data() const return encode( QStringList() << layerType << providerKey << name << uri << encode( supportedCrs ) << encode( supportedFormats ) ); } +QgsVectorLayer *QgsMimeDataUtils::Uri::vectorLayer( bool &owner, QString &error ) const +{ + owner = false; + if ( layerType != QLatin1String( "vector" ) ) + { + error = QObject::tr( "%1: Not a vector layer." ).arg( name ); + return nullptr; + } + if ( providerKey == QLatin1String( "memory" ) ) + { + QUrl url = QUrl::fromEncoded( uri.toUtf8() ); + if ( !url.hasQueryItem( QStringLiteral( "pid" ) ) || !url.hasQueryItem( QStringLiteral( "layerid" ) ) ) + { + error = QObject::tr( "Memory layer uri does not contain process or layer id." ); + return nullptr; + } + qint64 pid = url.queryItemValue( QStringLiteral( "pid" ) ).toLongLong(); + if ( pid != QCoreApplication::applicationPid() ) + { + error = QObject::tr( "Memory layer from another QGIS instance." ); + return nullptr; + } + QString layerId = url.queryItemValue( QStringLiteral( "layerid" ) ); + QgsVectorLayer *vectorLayer = qobject_cast< QgsVectorLayer *>( QgsProject::instance()->mapLayer( layerId ) ); + if ( !vectorLayer ) + { + error = QObject::tr( "Cannot get memory layer." ); + return nullptr; + } + return vectorLayer; + } + owner = true; + return new QgsVectorLayer( uri, name, providerKey ); +} + // ----- bool QgsMimeDataUtils::isUriList( const QMimeData *data ) @@ -119,6 +153,13 @@ static void _addLayerTreeNodeToUriList( QgsLayerTreeNode *node, QgsMimeDataUtils if ( layer->type() == QgsMapLayer::VectorLayer ) { uri.layerType = QStringLiteral( "vector" ); + if ( uri.providerKey == QStringLiteral( "memory" ) ) + { + QUrl url = QUrl::fromEncoded( uri.uri.toUtf8() ); + url.addQueryItem( QStringLiteral( "pid" ), QString::number( QCoreApplication::applicationPid() ) ); + url.addQueryItem( QStringLiteral( "layerid" ), layer->id() ); + uri.uri = QString( url.toEncoded() ); + } } else if ( layer->type() == QgsMapLayer::RasterLayer ) { diff --git a/src/core/qgsmimedatautils.h b/src/core/qgsmimedatautils.h index 20fe2434a60..d7edcb8ae2c 100644 --- a/src/core/qgsmimedatautils.h +++ b/src/core/qgsmimedatautils.h @@ -22,6 +22,7 @@ class QgsLayerItem; class QgsLayerTreeNode; +class QgsVectorLayer; /** \ingroup core * \class QgsMimeDataUtils @@ -44,6 +45,12 @@ class CORE_EXPORT QgsMimeDataUtils //! Returns encoded representation of the object QString data() const; + /** Get vector layer from uri if possible, otherwise returns 0 and error is set + * \param owner set to true if caller becomes owner + * \param error set to error message if cannot get vector + */ + QgsVectorLayer *vectorLayer( bool &owner, QString &error ) const; + //! Type of URI. Recognized types: "vector" / "raster" / "plugin" / "custom" QString layerType; //! For "vector" / "raster" type: provider id. diff --git a/src/core/qgsvectorlayerexporter.cpp b/src/core/qgsvectorlayerexporter.cpp index 3481eb10e89..73648567cda 100644 --- a/src/core/qgsvectorlayerexporter.cpp +++ b/src/core/qgsvectorlayerexporter.cpp @@ -456,9 +456,10 @@ QgsVectorLayerExporter::exportLayer( QgsVectorLayer *layer, // QgsVectorLayerExporterTask // -QgsVectorLayerExporterTask::QgsVectorLayerExporterTask( QgsVectorLayer *layer, const QString &uri, const QString &providerKey, const QgsCoordinateReferenceSystem &destinationCrs, QMap *options ) +QgsVectorLayerExporterTask::QgsVectorLayerExporterTask( QgsVectorLayer *layer, const QString &uri, const QString &providerKey, const QgsCoordinateReferenceSystem &destinationCrs, QMap *options, bool ownsLayer ) : QgsTask( tr( "Exporting %1" ).arg( layer->name() ), QgsTask::CanCancel ) , mLayer( layer ) + , mOwnsLayer( ownsLayer ) , mDestUri( uri ) , mDestProviderKey( providerKey ) , mDestCrs( destinationCrs ) diff --git a/src/core/qgsvectorlayerexporter.h b/src/core/qgsvectorlayerexporter.h index f1df1ac2172..791988455e9 100644 --- a/src/core/qgsvectorlayerexporter.h +++ b/src/core/qgsvectorlayerexporter.h @@ -189,12 +189,14 @@ class CORE_EXPORT QgsVectorLayerExporterTask : public QgsTask * Constructor for QgsVectorLayerExporterTask. Takes a source \a layer, destination \a uri * and \a providerKey, and various export related parameters such as destination CRS * and export \a options. + * \param ownsLayer take ownership of layer and deletes it after export */ QgsVectorLayerExporterTask( QgsVectorLayer *layer, const QString &uri, const QString &providerKey, const QgsCoordinateReferenceSystem &destinationCrs, - QMap *options = nullptr ); + QMap *options = nullptr, + bool ownsLayer = false ); /** * Creates a new QgsVectorLayerExporterTask which has ownership over a source \a layer. diff --git a/src/providers/postgres/qgspostgresdataitems.cpp b/src/providers/postgres/qgspostgresdataitems.cpp index 2b5182d196b..9415a43e2aa 100644 --- a/src/providers/postgres/qgspostgresdataitems.cpp +++ b/src/providers/postgres/qgspostgresdataitems.cpp @@ -201,16 +201,17 @@ bool QgsPGConnectionItem::handleDrop( const QMimeData *data, const QString &toSc QgsMimeDataUtils::UriList lst = QgsMimeDataUtils::decodeUriList( data ); Q_FOREACH ( const QgsMimeDataUtils::Uri &u, lst ) { - if ( u.layerType != QLatin1String( "vector" ) ) + // open the source layer + bool owner; + QString error; + QgsVectorLayer *srcLayer = u.vectorLayer( owner, error ); + if ( !srcLayer ) { - importResults.append( tr( "%1: Not a vector layer!" ).arg( u.name ) ); - hasError = true; // only vectors can be imported + importResults.append( tr( "%1: %2" ).arg( u.name ).arg( error ) ); + hasError = true; continue; } - // open the source layer - QgsVectorLayer *srcLayer = new QgsVectorLayer( u.uri, u.name, u.providerKey ); - if ( srcLayer->isValid() ) { uri.setDataSource( QString(), u.name, srcLayer->geometryType() != QgsWkbTypes::NullGeometry ? QStringLiteral( "geom" ) : QString() ); @@ -221,7 +222,7 @@ bool QgsPGConnectionItem::handleDrop( const QMimeData *data, const QString &toSc uri.setSchema( toSchema ); } - std::unique_ptr< QgsVectorLayerExporterTask > exportTask( QgsVectorLayerExporterTask::withLayerOwnership( srcLayer, uri.uri( false ), QStringLiteral( "postgres" ), srcLayer->crs() ) ); + std::unique_ptr< QgsVectorLayerExporterTask > exportTask( new QgsVectorLayerExporterTask( srcLayer, uri.uri( false ), QStringLiteral( "postgres" ), srcLayer->crs(), nullptr, owner ) ); // when export is successful: connect( exportTask.get(), &QgsVectorLayerExporterTask::exportComplete, this, [ = ]() diff --git a/src/providers/spatialite/qgsspatialitedataitems.cpp b/src/providers/spatialite/qgsspatialitedataitems.cpp index 4dc0d191b2b..e6f04b9f98d 100644 --- a/src/providers/spatialite/qgsspatialitedataitems.cpp +++ b/src/providers/spatialite/qgsspatialitedataitems.cpp @@ -205,22 +205,23 @@ bool QgsSLConnectionItem::handleDrop( const QMimeData *data, Qt::DropAction ) QgsMimeDataUtils::UriList lst = QgsMimeDataUtils::decodeUriList( data ); Q_FOREACH ( const QgsMimeDataUtils::Uri &u, lst ) { - if ( u.layerType != QLatin1String( "vector" ) ) + // open the source layer + bool owner; + QString error; + QgsVectorLayer *srcLayer = u.vectorLayer( owner, error ); + if ( !srcLayer ) { - importResults.append( tr( "%1: Not a vector layer!" ).arg( u.name ) ); - hasError = true; // only vectors can be imported + importResults.append( tr( "%1: %2" ).arg( u.name ).arg( error ) ); + hasError = true; continue; } - // open the source layer - QgsVectorLayer *srcLayer = new QgsVectorLayer( u.uri, u.name, u.providerKey ); - if ( srcLayer->isValid() ) { destUri.setDataSource( QString(), u.name, srcLayer->geometryType() != QgsWkbTypes::NullGeometry ? QStringLiteral( "geom" ) : QString() ); QgsDebugMsg( "URI " + destUri.uri() ); - std::unique_ptr< QgsVectorLayerExporterTask > exportTask( QgsVectorLayerExporterTask::withLayerOwnership( srcLayer, destUri.uri(), QStringLiteral( "spatialite" ), srcLayer->crs() ) ); + std::unique_ptr< QgsVectorLayerExporterTask > exportTask( new QgsVectorLayerExporterTask( srcLayer, destUri.uri(), QStringLiteral( "spatialite" ), srcLayer->crs(), nullptr, owner ) ); // when export is successful: connect( exportTask.get(), &QgsVectorLayerExporterTask::exportComplete, this, [ = ]()