From b81da8504a25b4d6e72062bc74de30a46a408b77 Mon Sep 17 00:00:00 2001 From: Alessandro Pasotti Date: Fri, 21 Sep 2018 11:38:39 +0200 Subject: [PATCH] GPKG vacuumGeoPackageDb non-gui method and gui action Also moved non-gui things together --- src/providers/ogr/qgsgeopackagedataitems.cpp | 344 ++++++++++--------- src/providers/ogr/qgsgeopackagedataitems.h | 13 +- 2 files changed, 187 insertions(+), 170 deletions(-) diff --git a/src/providers/ogr/qgsgeopackagedataitems.cpp b/src/providers/ogr/qgsgeopackagedataitems.cpp index bfa66325d3d..66a5302a2d2 100644 --- a/src/providers/ogr/qgsgeopackagedataitems.cpp +++ b/src/providers/ogr/qgsgeopackagedataitems.cpp @@ -74,26 +74,15 @@ QVector QgsGeoPackageRootItem::createChildren() } #ifdef HAVE_GUI -QList QgsGeoPackageRootItem::actions( QWidget *parent ) +QList QgsGeoPackageAbstractLayerItem::actions( QWidget * ) { QList lst; - - QAction *actionNew = new QAction( tr( "New Connection…" ), parent ); - connect( actionNew, &QAction::triggered, this, &QgsGeoPackageRootItem::newConnection ); - lst.append( actionNew ); - - QAction *actionCreateDatabase = new QAction( tr( "Create Database…" ), parent ); - connect( actionCreateDatabase, &QAction::triggered, this, &QgsGeoPackageRootItem::createDatabase ); - lst.append( actionCreateDatabase ); - + QAction *actionDeleteLayer = new QAction( tr( "Delete Layer '%1'…" ).arg( mName ), this ); + connect( actionDeleteLayer, &QAction::triggered, this, &QgsGeoPackageAbstractLayerItem::deleteLayer ); + lst.append( actionDeleteLayer ); return lst; } -QWidget *QgsGeoPackageRootItem::paramWidget() -{ - return nullptr; -} - void QgsGeoPackageRootItem::onConnectionsChanged() { refresh(); @@ -121,7 +110,6 @@ void QgsGeoPackageRootItem::createDatabase() } #endif - QgsGeoPackageCollectionItem::QgsGeoPackageCollectionItem( QgsDataItem *parent, const QString &name, const QString &path ) : QgsDataCollectionItem( parent, name, path ) , mPath( path ) @@ -131,7 +119,6 @@ QgsGeoPackageCollectionItem::QgsGeoPackageCollectionItem( QgsDataItem *parent, c } - QVector QgsGeoPackageCollectionItem::createChildren() { QVector children; @@ -163,6 +150,25 @@ bool QgsGeoPackageCollectionItem::equal( const QgsDataItem *other ) } #ifdef HAVE_GUI +QList QgsGeoPackageRootItem::actions( QWidget *parent ) +{ + QList lst; + + QAction *actionNew = new QAction( tr( "New Connection…" ), parent ); + connect( actionNew, &QAction::triggered, this, &QgsGeoPackageRootItem::newConnection ); + lst.append( actionNew ); + + QAction *actionCreateDatabase = new QAction( tr( "Create Database…" ), parent ); + connect( actionCreateDatabase, &QAction::triggered, this, &QgsGeoPackageRootItem::createDatabase ); + lst.append( actionCreateDatabase ); + + return lst; +} + +QWidget *QgsGeoPackageRootItem::paramWidget() +{ + return nullptr; +} QList QgsGeoPackageCollectionItem::actions( QWidget *parent ) { @@ -350,8 +356,162 @@ bool QgsGeoPackageCollectionItem::handleDrop( const QMimeData *data, Qt::DropAct } return true; } + +QList QgsGeoPackageConnectionItem::actions( QWidget *parent ) +{ + QList lst; + + QAction *actionDeleteConnection = new QAction( tr( "Remove Connection" ), parent ); + 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…" ), parent ); + connect( actionAddTable, &QAction::triggered, this, &QgsGeoPackageConnectionItem::addTable ); + lst.append( actionAddTable ); + + // Run VACUUM + QAction *actionVacuumDb = new QAction( tr( "Compact database (VACUUM)" ), parent ); + connect( actionVacuumDb, &QAction::triggered, this, &QgsGeoPackageConnectionItem::vacuumGeoPackageDbAction ); + lst.append( actionVacuumDb ); + + + return lst; +} + +void QgsGeoPackageCollectionItem::deleteConnection() +{ + QgsOgrDbConnection::deleteConnection( name(), QStringLiteral( "GPKG" ) ); + mParent->refreshConnections(); +} + +void QgsGeoPackageCollectionItem::addTable() +{ + QgsNewGeoPackageLayerDialog dialog( nullptr ); + dialog.setDatabasePath( mPath ); + dialog.setCrs( QgsProject::instance()->defaultCrsForNewLayers() ); + dialog.setOverwriteBehavior( QgsNewGeoPackageLayerDialog::AddNewLayer ); + dialog.lockDatabasePath(); + if ( dialog.exec() == QDialog::Accepted ) + { + refreshConnections(); + } +} + +void QgsGeoPackageCollectionItem::addConnection() +{ + QgsOgrDbConnection connection( mName, QStringLiteral( "GPKG" ) ); + connection.setPath( mPath ); + connection.save(); + mParent->refreshConnections(); +} + +void QgsGeoPackageCollectionItem::vacuumGeoPackageDbAction() +{ + QString errCause; + bool result = QgsGeoPackageCollectionItem::vacuumGeoPackageDb( mPath, mName, errCause ); + if ( result && errCause.isEmpty() ) + { + QMessageBox::information( nullptr, tr( "Database compact (VACUUM)" ), tr( "Database %1 has been compacted successfully." ).arg( mName ) ); + } + else + { + QMessageBox::warning( nullptr, tr( "Database compact (VACUUM)" ), errCause ); + } +} + +void QgsGeoPackageAbstractLayerItem::deleteLayer() +{ + // Check if the layer(s) are in the registry + QList layersList; + const auto mapLayers( QgsProject::instance()->mapLayers() ); + for ( QgsMapLayer *layer : mapLayers ) + { + if ( layer->publicSource() == mUri ) + { + layersList << layer; + } + } + + if ( ! layersList.isEmpty( ) ) + { + if ( QMessageBox::question( nullptr, QObject::tr( "Delete Layer" ), QObject::tr( "The layer %1 exists in the current project %2," + " do you want to remove it from the project and delete it?" ).arg( mName, layersList.at( 0 )->name() ), QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes ) + { + return; + } + } + else if ( QMessageBox::question( nullptr, QObject::tr( "Delete Layer" ), + QObject::tr( "Are you sure you want to delete layer %1 from GeoPackage?" ).arg( mName ), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes ) + { + return; + } + + if ( layersList.isEmpty() ) + { + QgsProject::instance()->removeMapLayers( layersList ); + } + + QString errCause; + bool res = executeDeleteLayer( errCause ); + if ( !res ) + { + QMessageBox::warning( nullptr, tr( "Delete Layer" ), errCause ); + } + else + { + QMessageBox::information( nullptr, tr( "Delete Layer" ), tr( "Layer %1 deleted successfully." ).arg( mName ) ); + if ( mParent ) + mParent->refreshConnections(); + } + +} #endif +bool QgsGeoPackageCollectionItem::vacuumGeoPackageDb( const QString &path, const QString &name, QString &errCause ) +{ + bool result = false; + // Better safe than sorry + if ( ! path.isEmpty( ) ) + { + char *errmsg = nullptr; + sqlite3_database_unique_ptr database; + int status = database.open_v2( path, SQLITE_OPEN_READWRITE, nullptr ); + if ( status != SQLITE_OK ) + { + errCause = sqlite3_errmsg( database.get() ); + } + else + { + ( void )sqlite3_exec( + database.get(), /* An open database */ + "VACUUM", /* SQL to be evaluated */ + nullptr, /* Callback function */ + nullptr, /* 1st argument to callback */ + &errmsg /* Error msg written here */ + ); + } + if ( status != SQLITE_OK || errmsg ) + { + errCause = tr( "There was an error compacting (VACUUM) the database %1: %2" ) + .arg( name ) + .arg( QString::fromUtf8( errmsg ) ); + } + else + { + result = true; + } + sqlite3_free( errmsg ); + } + else + { + // This should never happen! + errCause = tr( "Layer path is empty: layer cannot be deleted!" ); + } + return result; +} + bool QgsGeoPackageCollectionItem::deleteGeoPackageRasterLayer( const QString &uri, QString &errCause ) { bool result = false; @@ -459,44 +619,6 @@ bool QgsGeoPackageCollectionItem::deleteGeoPackageRasterLayer( const QString &ur return result; } -void QgsGeoPackageCollectionItem::vacuumGeoPackageDb() -{ - QString errCause; - // Better safe than sorry - if ( ! mPath.isEmpty( ) ) - { - char *errmsg = nullptr; - sqlite3_database_unique_ptr database; - int status = database.open_v2( mPath, SQLITE_OPEN_READWRITE, nullptr ); - if ( status != SQLITE_OK ) - { - errCause = sqlite3_errmsg( database.get() ); - } - else - { - ( void )sqlite3_exec( - database.get(), /* An open database */ - "VACUUM", /* SQL to be evaluated */ - nullptr, /* Callback function */ - nullptr, /* 1st argument to callback */ - &errmsg /* Error msg written here */ - ); - } - if ( status == SQLITE_OK && ! errmsg ) - { - QMessageBox::information( nullptr, tr( "Database compact (VACUUM)" ), tr( "Database %1 has been compacted successfully." ).arg( mName ) ); - } - else - { - errCause = tr( "There was an error compacting (VACUUM) the database %1: %2" ) - .arg( mName ) - .arg( QString::fromUtf8( errmsg ) ); - QMessageBox::warning( nullptr, tr( "Database compact (VACUUM)" ), errCause ); - } - sqlite3_free( errmsg ); - } -} - QgsGeoPackageConnectionItem::QgsGeoPackageConnectionItem( QgsDataItem *parent, const QString &name, const QString &path ) : QgsGeoPackageCollectionItem( parent, name, path ) { @@ -514,118 +636,6 @@ bool QgsGeoPackageConnectionItem::equal( const QgsDataItem *other ) } -#ifdef HAVE_GUI -QList QgsGeoPackageConnectionItem::actions( QWidget *parent ) -{ - QList lst; - - QAction *actionDeleteConnection = new QAction( tr( "Remove Connection" ), parent ); - 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…" ), parent ); - connect( actionAddTable, &QAction::triggered, this, &QgsGeoPackageConnectionItem::addTable ); - lst.append( actionAddTable ); - - // Run VACUUM - QAction *actionVacuumDb = new QAction( tr( "Compact database (VACUUM)" ), parent ); - connect( actionVacuumDb, &QAction::triggered, this, &QgsGeoPackageConnectionItem::vacuumGeoPackageDb ); - lst.append( actionVacuumDb ); - - - return lst; -} - -void QgsGeoPackageCollectionItem::deleteConnection() -{ - QgsOgrDbConnection::deleteConnection( name(), QStringLiteral( "GPKG" ) ); - mParent->refreshConnections(); -} - - -void QgsGeoPackageCollectionItem::addTable() -{ - QgsNewGeoPackageLayerDialog dialog( nullptr ); - dialog.setDatabasePath( mPath ); - dialog.setCrs( QgsProject::instance()->defaultCrsForNewLayers() ); - dialog.setOverwriteBehavior( QgsNewGeoPackageLayerDialog::AddNewLayer ); - dialog.lockDatabasePath(); - if ( dialog.exec() == QDialog::Accepted ) - { - refreshConnections(); - } -} - -void QgsGeoPackageCollectionItem::addConnection() -{ - QgsOgrDbConnection connection( mName, QStringLiteral( "GPKG" ) ); - connection.setPath( mPath ); - connection.save(); - mParent->refreshConnections(); -} - -#endif - -#ifdef HAVE_GUI -QList QgsGeoPackageAbstractLayerItem::actions( QWidget * ) -{ - QList lst; - QAction *actionDeleteLayer = new QAction( tr( "Delete Layer '%1'…" ).arg( mName ), this ); - connect( actionDeleteLayer, &QAction::triggered, this, &QgsGeoPackageAbstractLayerItem::deleteLayer ); - lst.append( actionDeleteLayer ); - return lst; -} - -void QgsGeoPackageAbstractLayerItem::deleteLayer() -{ - // Check if the layer(s) are in the registry - QList layersList; - const auto mapLayers( QgsProject::instance()->mapLayers() ); - for ( QgsMapLayer *layer : mapLayers ) - { - if ( layer->publicSource() == mUri ) - { - layersList << layer; - } - } - - if ( ! layersList.isEmpty( ) ) - { - if ( QMessageBox::question( nullptr, QObject::tr( "Delete Layer" ), QObject::tr( "The layer %1 exists in the current project %2," - " do you want to remove it from the project and delete it?" ).arg( mName, layersList.at( 0 )->name() ), QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes ) - { - return; - } - } - else if ( QMessageBox::question( nullptr, QObject::tr( "Delete Layer" ), - QObject::tr( "Are you sure you want to delete layer %1 from GeoPackage?" ).arg( mName ), - QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes ) - { - return; - } - - if ( layersList.isEmpty() ) - { - QgsProject::instance()->removeMapLayers( layersList ); - } - - QString errCause; - bool res = executeDeleteLayer( errCause ); - if ( !res ) - { - QMessageBox::warning( nullptr, tr( "Delete Layer" ), errCause ); - } - else - { - QMessageBox::information( nullptr, tr( "Delete Layer" ), tr( "Layer %1 deleted successfully." ).arg( mName ) ); - if ( mParent ) - mParent->refreshConnections(); - } - -} -#endif - QgsGeoPackageAbstractLayerItem::QgsGeoPackageAbstractLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &uri, QgsLayerItem::LayerType layerType, const QString &providerKey ) : QgsLayerItem( parent, name, path, uri, layerType, providerKey ) { diff --git a/src/providers/ogr/qgsgeopackagedataitems.h b/src/providers/ogr/qgsgeopackagedataitems.h index e8308eb489c..7c5999e8287 100644 --- a/src/providers/ogr/qgsgeopackagedataitems.h +++ b/src/providers/ogr/qgsgeopackagedataitems.h @@ -88,10 +88,17 @@ class QgsGeoPackageCollectionItem : public QgsDataCollectionItem //! Returns the layer type from \a geometryType static QgsLayerItem::LayerType layerTypeFromDb( const QString &geometryType ); - //! Deletes a geopackage layer + //! Deletes a geopackage raster layer static bool deleteGeoPackageRasterLayer( const QString &uri, QString &errCause ); - + /** + * Compacts (VACUUM) a geopackage database + * \param path DB path + * \param name DB name + * \param errCause contains the error message + * \return true on success + */ + static bool vacuumGeoPackageDb( const QString &path, const QString &name, QString &errCause ); public slots: #ifdef HAVE_GUI @@ -99,7 +106,7 @@ class QgsGeoPackageCollectionItem : public QgsDataCollectionItem void addConnection(); void deleteConnection(); //! Compacts (VACUUM) a geopackage database - void vacuumGeoPackageDb(); + void vacuumGeoPackageDbAction(); #endif protected: