From ab74ecc3ad6fe8dc20a942d14d01f185b2fe1797 Mon Sep 17 00:00:00 2001 From: Alessandro Pasotti Date: Fri, 15 Sep 2017 19:12:45 +0200 Subject: [PATCH] File browser: use GeoPackage items for gpkg files --- src/providers/ogr/qgsgeopackagedataitems.cpp | 71 ++++++++++++++++---- src/providers/ogr/qgsgeopackagedataitems.h | 36 ++++++++-- src/providers/ogr/qgsogrdataitems.cpp | 37 +++++++--- 3 files changed, 117 insertions(+), 27 deletions(-) diff --git a/src/providers/ogr/qgsgeopackagedataitems.cpp b/src/providers/ogr/qgsgeopackagedataitems.cpp index c5c39e96ecb..ea717014c48 100644 --- a/src/providers/ogr/qgsgeopackagedataitems.cpp +++ b/src/providers/ogr/qgsgeopackagedataitems.cpp @@ -120,7 +120,7 @@ void QgsGeoPackageRootItem::createDatabase() #endif -QgsGeoPackageConnectionItem::QgsGeoPackageConnectionItem( QgsDataItem *parent, const QString &name, const QString &path ) +QgsGeoPackageCollectionItem::QgsGeoPackageCollectionItem( QgsDataItem *parent, const QString &name, const QString &path ) : QgsDataCollectionItem( parent, name, path ) , mPath( path ) { @@ -129,7 +129,7 @@ QgsGeoPackageConnectionItem::QgsGeoPackageConnectionItem( QgsDataItem *parent, c -QVector QgsGeoPackageConnectionItem::createChildren() +QVector QgsGeoPackageCollectionItem::createChildren() { QVector children; const auto layers = QgsOgrLayerItem::subLayers( mPath, QStringLiteral( "GPKG" ) ); @@ -148,30 +148,31 @@ QVector QgsGeoPackageConnectionItem::createChildren() return children; } -bool QgsGeoPackageConnectionItem::equal( const QgsDataItem *other ) +bool QgsGeoPackageCollectionItem::equal( const QgsDataItem *other ) { if ( type() != other->type() ) { return false; } - const QgsGeoPackageConnectionItem *o = dynamic_cast( other ); + const QgsGeoPackageCollectionItem *o = dynamic_cast( other ); return o && mPath == o->mPath && mName == o->mName; } #ifdef HAVE_GUI -QList QgsGeoPackageConnectionItem::actions() +QList QgsGeoPackageCollectionItem::actions() { QList lst; - QAction *actionDeleteConnection = new QAction( tr( "Remove connection" ), this ); - connect( actionDeleteConnection, &QAction::triggered, this, &QgsGeoPackageConnectionItem::deleteConnection ); - lst.append( actionDeleteConnection ); + // Add to stored connections + QAction *actionAddConnection = new QAction( tr( "Add connection" ), this ); + connect( actionAddConnection, &QAction::triggered, this, &QgsGeoPackageCollectionItem::addConnection ); + lst.append( actionAddConnection ); // Add table to existing DB QAction *actionAddTable = new QAction( tr( "Create a new layer or table..." ), this ); - connect( actionAddTable, &QAction::triggered, this, &QgsGeoPackageConnectionItem::addTable ); + connect( actionAddTable, &QAction::triggered, this, &QgsGeoPackageCollectionItem::addTable ); lst.append( actionAddTable ); return lst; @@ -180,7 +181,7 @@ QList QgsGeoPackageConnectionItem::actions() -bool QgsGeoPackageConnectionItem::handleDrop( const QMimeData *data, Qt::DropAction ) +bool QgsGeoPackageCollectionItem::handleDrop( const QMimeData *data, Qt::DropAction ) { if ( !QgsMimeDataUtils::isUriList( data ) ) @@ -327,7 +328,7 @@ bool QgsGeoPackageConnectionItem::handleDrop( const QMimeData *data, Qt::DropAct } -bool QgsGeoPackageConnectionItem::deleteGeoPackageRasterLayer( const QString &uri, QString &errCause ) +bool QgsGeoPackageCollectionItem::deleteGeoPackageRasterLayer( const QString &uri, QString &errCause ) { bool result = false; // Better safe than sorry @@ -444,6 +445,40 @@ bool QgsGeoPackageConnectionItem::deleteGeoPackageRasterLayer( const QString &ur return result; } +QgsGeoPackageConnectionItem::QgsGeoPackageConnectionItem( QgsDataItem *parent, const QString &name, const QString &path ) + : QgsGeoPackageCollectionItem( parent, name, path ) +{ + +} + +bool QgsGeoPackageConnectionItem::equal( const QgsDataItem *other ) +{ + if ( type() != other->type() ) + { + return false; + } + const QgsGeoPackageConnectionItem *o = dynamic_cast( other ); + return o && mPath == o->mPath && mName == o->mName; + +} + +#ifdef HAVE_GUI +QList QgsGeoPackageConnectionItem::actions() +{ + QList lst; + + QAction *actionDeleteConnection = new QAction( tr( "Remove connection" ), this ); + connect( actionDeleteConnection, &QAction::triggered, this, &QgsGeoPackageConnectionItem::deleteConnection ); + lst.append( actionDeleteConnection ); + + // Add table to existing DB + QAction *actionAddTable = new QAction( tr( "Create a new layer or table..." ), this ); + connect( actionAddTable, &QAction::triggered, this, &QgsGeoPackageConnectionItem::addTable ); + lst.append( actionAddTable ); + + + return lst; +} void QgsGeoPackageConnectionItem::deleteConnection() { @@ -451,8 +486,8 @@ void QgsGeoPackageConnectionItem::deleteConnection() mParent->refreshConnections(); } -#ifdef HAVE_GUI -void QgsGeoPackageConnectionItem::addTable() + +void QgsGeoPackageCollectionItem::addTable() { QgsNewGeoPackageLayerDialog dialog( nullptr ); QFileInfo fileInfo( mPath ); @@ -472,6 +507,14 @@ void QgsGeoPackageConnectionItem::addTable() QgsDebugMsg( QStringLiteral( "Cannot add Table: connection %1 does not exists or the path is empy!" ).arg( connName ) ); } } + +void QgsGeoPackageCollectionItem::addConnection() +{ + QgsOgrDbConnection connection( mName, QStringLiteral( "GeoPackage" ) ); + connection.save(); + emit connectionsChanged(); +} + #endif #ifdef HAVE_GUI @@ -554,7 +597,7 @@ QgsGeoPackageRasterLayerItem::QgsGeoPackageRasterLayerItem( QgsDataItem *parent, bool QgsGeoPackageRasterLayerItem::executeDeleteLayer( QString &errCause ) { - return QgsGeoPackageConnectionItem::deleteGeoPackageRasterLayer( mUri, errCause ); + return QgsGeoPackageCollectionItem::deleteGeoPackageRasterLayer( mUri, errCause ); } diff --git a/src/providers/ogr/qgsgeopackagedataitems.h b/src/providers/ogr/qgsgeopackagedataitems.h index 83f04c8f2da..3e4b93ac427 100644 --- a/src/providers/ogr/qgsgeopackagedataitems.h +++ b/src/providers/ogr/qgsgeopackagedataitems.h @@ -64,12 +64,16 @@ class QgsGeoPackageVectorLayerItem : public QgsGeoPackageAbstractLayerItem }; -class QgsGeoPackageConnectionItem : public QgsDataCollectionItem +/** + * \brief The QgsGeoPackageCollectionItem class is the base class for + * GeoPackage container + */ +class QgsGeoPackageCollectionItem : public QgsDataCollectionItem { Q_OBJECT public: - QgsGeoPackageConnectionItem( QgsDataItem *parent, const QString &name, const QString &path ); + QgsGeoPackageCollectionItem( QgsDataItem *parent, const QString &name, const QString &path ); QVector createChildren() override; virtual bool equal( const QgsDataItem *other ) override; @@ -87,9 +91,8 @@ class QgsGeoPackageConnectionItem : public QgsDataCollectionItem public slots: #ifdef HAVE_GUI - void editConnection(); - void deleteConnection(); void addTable(); + void addConnection(); #endif protected: @@ -97,6 +100,31 @@ class QgsGeoPackageConnectionItem : public QgsDataCollectionItem }; +/** + * \brief The QgsGeoPackageConnectionItem class adds the stored + * connection management to QgsGeoPackageCollectionItem + */ +class QgsGeoPackageConnectionItem : public QgsGeoPackageCollectionItem +{ + Q_OBJECT + + public: + QgsGeoPackageConnectionItem( QgsDataItem *parent, const QString &name, const QString &path ); + virtual bool equal( const QgsDataItem *other ) override; + +#ifdef HAVE_GUI + QList actions() override; +#endif + + public slots: +#ifdef HAVE_GUI + void editConnection(); + void deleteConnection(); +#endif + +}; + + class QgsGeoPackageRootItem : public QgsDataCollectionItem { Q_OBJECT diff --git a/src/providers/ogr/qgsogrdataitems.cpp b/src/providers/ogr/qgsogrdataitems.cpp index 20af61ba131..b04bfaba702 100644 --- a/src/providers/ogr/qgsogrdataitems.cpp +++ b/src/providers/ogr/qgsogrdataitems.cpp @@ -22,6 +22,7 @@ #include "qgsproject.h" #include "qgsvectorlayer.h" #include "qgsrasterlayer.h" +#include "qgsgeopackagedataitems.h" #include #include @@ -567,9 +568,19 @@ QGISEXTERN QgsDataItem *dataItem( QString path, QgsDataItem *parentItem ) #endif } - // return item without testing if: - // scanExtSetting - // or zipfile and scan zip == "Basic scan" + // Filters out the OGR/GDAL supported formats that can contain multiple layers + // and should be treated like a DB: GeoPackage and SQLite + // NOTE: this formats are scanned for rasters too and they must + // be skipped by "gdal" provider or the rasters will be listed + // twice. ogrSupportedDbLayersExtensions must be kept in sync + // with the companion variable (same name) in the gdal provider + // class + // TODO: add more OGR supported multiple layers formats here! + QStringList ogrSupportedDbLayersExtensions; + ogrSupportedDbLayersExtensions << QLatin1String( "gpkg" ) << QLatin1String( "sqlite" ) << QLatin1String( "db" ); + + // Fast track: return item without testing if: + // scanExtSetting or zipfile and scan zip == "Basic scan" if ( scanExtSetting || ( ( is_vsizip || is_vsitar ) && scanZipSetting == QLatin1String( "basic" ) ) ) { @@ -596,13 +607,18 @@ QGISEXTERN QgsDataItem *dataItem( QString path, QgsDataItem *parentItem ) // Handle collections // Check if the layer has sublayers by comparing the extension QgsDataItem *item; - QStringList multipleLayersExtensions; - // TODO: add more OGR supported multiple layers formats here! - multipleLayersExtensions << QLatin1String( "gpkg" ) << QLatin1String( "sqlite" ) << QLatin1String( "db" ); - if ( ! multipleLayersExtensions.contains( suffix ) ) + if ( ! ogrSupportedDbLayersExtensions.contains( suffix ) ) + { item = new QgsOgrLayerItem( parentItem, name, path, path, QgsLayerItem::Vector ); + } + else if ( suffix.compare( QLatin1String( "gpkg" ), Qt::CaseInsensitive ) == 0 ) + { + item = new QgsGeoPackageCollectionItem( parentItem, name, path ); + } else + { item = new QgsOgrDataCollectionItem( parentItem, name, path ); + } if ( item ) return item; @@ -625,10 +641,9 @@ QGISEXTERN QgsDataItem *dataItem( QString path, QgsDataItem *parentItem ) QgsDebugMsgLevel( QString( "GDAL Driver : %1" ).arg( GDALGetDriverShortName( hDriver ) ), 2 ); - int numLayers = GDALDatasetGetLayerCount( hDataSource ); - QgsDataItem *item = nullptr; + int numLayers = OGR_DS_GetLayerCount( hDataSource ); if ( numLayers == 1 ) { QgsDebugMsgLevel( QString( "using name = %1" ).arg( name ), 2 ); @@ -639,6 +654,10 @@ QGISEXTERN QgsDataItem *dataItem( QString path, QgsDataItem *parentItem ) QgsDebugMsgLevel( QString( "using name = %1" ).arg( name ), 2 ); item = new QgsOgrDataCollectionItem( parentItem, name, path ); } + else if ( suffix.compare( QLatin1String( "gpkg" ), Qt::CaseInsensitive ) == 0 ) + { + item = new QgsGeoPackageCollectionItem( parentItem, name, path ); + } GDALClose( hDataSource ); return item;