Skip to content

Commit

Permalink
Merge pull request #5040 from boundlessgeo/gpkg-raster-delete
Browse files Browse the repository at this point in the history
Geopackage: moved delete to abstract item and implemented raster deletion
  • Loading branch information
elpaso committed Aug 18, 2017
2 parents 86949cb + dc6d1c1 commit 475998e
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 64 deletions.
220 changes: 171 additions & 49 deletions src/providers/ogr/qgsgeopackagedataitems.cpp
Expand Up @@ -13,6 +13,8 @@
* *
***************************************************************************/

#include "sqlite3.h"

#include "qgsgeopackagedataitems.h"
#include "qgsgeopackageconnection.h"
#include "qgslogger.h"
Expand All @@ -24,6 +26,7 @@
#include "qgsnewgeopackagelayerdialog.h"
#include "qgsmessageoutput.h"
#include "qgsvectorlayerexporter.h"
#include "gdal.h"

#include <QAction>
#include <QMessageBox>
Expand Down Expand Up @@ -69,6 +72,7 @@ QVector<QgsDataItem *> QgsGeoPackageRootItem::createChildren()
return connections;
}

#ifdef HAVE_GUI
QList<QAction *> QgsGeoPackageRootItem::actions()
{
QList<QAction *> lst;
Expand All @@ -88,7 +92,7 @@ QWidget *QgsGeoPackageRootItem::paramWidget()
{
return nullptr;
}

#endif

void QgsGeoPackageRootItem::connectionsChanged()
{
Expand Down Expand Up @@ -214,29 +218,65 @@ QVector<QgsDataItem *> QgsGeoPackageConnectionItem::createChildren()
uri = QStringLiteral( "%1|layerid=%2" ).arg( mPath, layerId );
}
QgsGeoPackageVectorLayerItem *item = new QgsGeoPackageVectorLayerItem( this, name, mPath, uri, layerType );
QgsDebugMsgLevel( QStringLiteral( "Adding GPKG Vector item %1 %2 %3" ).arg( name, uri, geometryType ), 3 );
QgsDebugMsgLevel( QStringLiteral( "Adding GeoPackage Vector item %1 %2 %3" ).arg( name, uri, geometryType ), 3 );
children.append( item );
}
}
else
{
QgsDebugMsgLevel( QStringLiteral( "Layer type is not a supported GeoPackage Vector layer %1" ).arg( mPath ), 3 );
}
QgsDebugMsgLevel( QStringLiteral( "Adding GPKG Vector item %1 %2 %3" ).arg( name, uri, geometryType ), 3 );
qDebug() << QStringLiteral( "Adding GPKG Vector item %1 %2 %3" ).arg( name, uri, geometryType );
QgsDebugMsgLevel( QStringLiteral( "Adding GeoPackage Vector item %1 %2 %3" ).arg( name, uri, geometryType ), 3 );
}
}
}
// Raster layers
QgsRasterLayer rlayer( mPath, QStringLiteral( "gdal_tmp" ), QStringLiteral( "gdal" ), false );
Q_FOREACH ( const QString &uri, rlayer.dataProvider()->subLayers( ) )
if ( rlayer.dataProvider()->subLayers( ).size() > 0 )
{
QStringList pieces = uri.split( ':' );
QString name = pieces.value( pieces.length() - 1 );
QgsDebugMsg( QStringLiteral( "Adding GPKG Raster item %1 %2 %3" ).arg( name, uri ) );
QgsGeoPackageRasterLayerItem *item = new QgsGeoPackageRasterLayerItem( this, name, mPath, uri );
children.append( item );
Q_FOREACH ( const QString &uri, rlayer.dataProvider()->subLayers( ) )
{
QStringList pieces = uri.split( ':' );
QString name = pieces.value( pieces.length() - 1 );
QgsDebugMsgLevel( QStringLiteral( "Adding GeoPackage Raster item %1 %2 %3" ).arg( name, uri ), 3 );
QgsGeoPackageRasterLayerItem *item = new QgsGeoPackageRasterLayerItem( this, name, mPath, uri );
children.append( item );
}
}
else if ( rlayer.isValid( ) )
{
// Get the identifier
GDALAllRegister();
// do not print errors, but write to debug
CPLPushErrorHandler( CPLQuietErrorHandler );
CPLErrorReset();
GDALDatasetH hDS = GDALOpen( mPath.toUtf8().constData(), GA_ReadOnly );
CPLPopErrorHandler();

if ( ! hDS )
{
QgsDebugMsg( QString( "GDALOpen error # %1 : %2 " ).arg( CPLGetLastErrorNo() ).arg( CPLGetLastErrorMsg() ) );

}
else
{
QString uri( QStringLiteral( "GPKG:%1" ).arg( mPath ) );
QString name = GDALGetMetadataItem( hDS, "IDENTIFIER", NULL );
GDALClose( hDS );
// Fallback: will not be able to delete the table
if ( name.isEmpty() )
{
name = QFileInfo( mPath ).fileName();
}
else
{
uri += QStringLiteral( ":%1" ).arg( name );
}

QgsDebugMsgLevel( QStringLiteral( "Adding GeoPackage Raster item %1 %2 %3" ).arg( name, mPath ), 3 );
QgsGeoPackageRasterLayerItem *item = new QgsGeoPackageRasterLayerItem( this, name, mPath, uri );
children.append( item );
}
}
return children;

Expand Down Expand Up @@ -361,7 +401,7 @@ bool QgsGeoPackageConnectionItem::handleDrop( const QMimeData *data, Qt::DropAct
}
else
{
// TODO: implemnent raster import
// TODO: implement raster import
QgsMessageOutput *output = QgsMessageOutput::createMessageOutput();
output->setTitle( tr( "Import to GeoPackage database faile" ) );
output->setMessage( tr( "Failed to import some layers!\n\n" ) + QStringLiteral( "Raster import is not yet implemented!\n" ), QgsMessageOutput::MessageText );
Expand Down Expand Up @@ -441,44 +481,14 @@ void QgsGeoPackageConnectionItem::addTable()
QList<QAction *> QgsGeoPackageAbstractLayerItem::actions()
{
QList<QAction *> lst;
// TODO: delete layer when the provider supports it (not currently implemented)
return lst;
}
#endif

QgsGeoPackageAbstractLayerItem::QgsGeoPackageAbstractLayerItem( QgsDataItem *parent, QString name, QString path, QString uri, QgsLayerItem::LayerType layerType, QString providerKey )
: QgsLayerItem( parent, name, path, uri, layerType, providerKey )
{
setState( Populated ); // no children are expected
}


QgsGeoPackageVectorLayerItem::QgsGeoPackageVectorLayerItem( QgsDataItem *parent, QString name, QString path, QString uri, LayerType layerType )
: QgsGeoPackageAbstractLayerItem( parent, name, path, uri, layerType, QStringLiteral( "ogr" ) )
{

}


QgsGeoPackageRasterLayerItem::QgsGeoPackageRasterLayerItem( QgsDataItem *parent, QString name, QString path, QString uri )
: QgsGeoPackageAbstractLayerItem( parent, name, path, uri, QgsLayerItem::LayerType::Raster, QStringLiteral( "gdal" ) )
{

}


#ifdef HAVE_GUI
QList<QAction *> QgsGeoPackageVectorLayerItem::actions()
{
QList<QAction *> lst = QgsGeoPackageAbstractLayerItem::actions();
QAction *actionDeleteLayer = new QAction( tr( "Delete layer '%1'..." ).arg( mName ), this );
connect( actionDeleteLayer, &QAction::triggered, this, &QgsGeoPackageVectorLayerItem::deleteLayer );
connect( actionDeleteLayer, &QAction::triggered, this, &QgsGeoPackageAbstractLayerItem::deleteLayer );
lst.append( actionDeleteLayer );
return lst;
}
#endif


void QgsGeoPackageVectorLayerItem::deleteLayer()
void QgsGeoPackageAbstractLayerItem::deleteLayer()
{
// Check if the layer is in the registry
const QgsMapLayer *projectLayer = nullptr;
Expand All @@ -492,28 +502,140 @@ void QgsGeoPackageVectorLayerItem::deleteLayer()
if ( ! projectLayer )
{
if ( QMessageBox::question( nullptr, QObject::tr( "Delete Layer" ),
QObject::tr( "Are you sure you want to delete layer '%1' from GeoPackage?" ).arg( mName ),
QObject::tr( "Are you sure you want to delete layer <b>%1</b> from GeoPackage?" ).arg( mName ),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
return;

QString errCause;
bool res = ::deleteLayer( mUri, errCause );
bool res = executeDeleteLayer( errCause );
if ( !res )
{
QMessageBox::warning( nullptr, tr( "Delete Layer" ), errCause );
}
else
{
QMessageBox::information( nullptr, tr( "Delete Layer" ), tr( "Layer deleted successfully." ) );
QMessageBox::information( nullptr, tr( "Delete Layer" ), tr( "Layer <b>%1</b> deleted successfully." ).arg( mName ) );
if ( mParent )
mParent->refresh();
}
}
else
{
QMessageBox::warning( nullptr, QObject::tr( "Delete Layer" ), QObject::tr( "The layer '%1' cannot be deleted because it is in the current project as '%2',"
QMessageBox::warning( nullptr, QObject::tr( "Delete Layer" ), QObject::tr( "The layer <b>%1</b> cannot be deleted because it is in the current project as <b>%2</b>,"
" remove it from the project and retry." ).arg( mName, projectLayer->name() ) );
}

}

QgsGeoPackageAbstractLayerItem::QgsGeoPackageAbstractLayerItem( QgsDataItem *parent, QString name, QString path, QString uri, QgsLayerItem::LayerType layerType, QString providerKey )
: QgsLayerItem( parent, name, path, uri, layerType, providerKey )
{
setState( Populated ); // no children are expected
}

bool QgsGeoPackageAbstractLayerItem::executeDeleteLayer( QString &errCause )
{
errCause = QObject::tr( "The layer <b>%1</b> cannot be deleted because the this feature is not yet implemented for this kind of layers." ).arg( mName );
return false;
}


QgsGeoPackageVectorLayerItem::QgsGeoPackageVectorLayerItem( QgsDataItem *parent, QString name, QString path, QString uri, LayerType layerType )
: QgsGeoPackageAbstractLayerItem( parent, name, path, uri, layerType, QStringLiteral( "ogr" ) )
{

}


QgsGeoPackageRasterLayerItem::QgsGeoPackageRasterLayerItem( QgsDataItem *parent, QString name, QString path, QString uri )
: QgsGeoPackageAbstractLayerItem( parent, name, path, uri, QgsLayerItem::LayerType::Raster, QStringLiteral( "gdal" ) )
{

}

bool QgsGeoPackageRasterLayerItem::executeDeleteLayer( QString &errCause )
{
bool result = false;
// Better safe than sorry
if ( ! mUri.isEmpty( ) )
{
QStringList pieces( mUri.split( ':' ) );
if ( pieces.size() != 3 )
{
errCause = QStringLiteral( "Layer URI is malformed: layer <b>%1</b> cannot be deleted!" ).arg( mName );
}
else
{
QString baseUri = pieces.at( 1 );
QString layerName = pieces.at( 2 );
sqlite3 *handle;
int status = sqlite3_open_v2( baseUri.toUtf8().constData(), &handle, SQLITE_OPEN_READWRITE, NULL );
if ( status != SQLITE_OK )
{
errCause = sqlite3_errmsg( handle );
}
else
{
// Remove table
char *errmsg = NULL;
char *sql = sqlite3_mprintf(
"DROP table %w;"
"DELETE FROM gpkg_contents WHERE table_name = '%q';"
"DELETE FROM gpkg_tile_matrix WHERE table_name = '%q';"
"DELETE FROM gpkg_tile_matrix_set WHERE table_name = '%q';",
layerName.toUtf8().constData(),
layerName.toUtf8().constData(),
layerName.toUtf8().constData(),
layerName.toUtf8().constData() );
status = sqlite3_exec(
handle, /* An open database */
sql, /* SQL to be evaluated */
NULL, /* Callback function */
NULL, /* 1st argument to callback */
&errmsg /* Error msg written here */
);
sqlite3_free( sql );
// Remove from optional tables, may silently fail
for ( const auto tableName : QStringList()
<< QStringLiteral( "gpkg_extensions" )
<< QStringLiteral( "gpkg_metadata_reference" ) )
{
char *sql = sqlite3_mprintf( "DELETE FROM table %w WHERE table_name = '%q",
tableName.toUtf8().constData(),
layerName.toUtf8().constData() );
status = sqlite3_exec(
handle, /* An open database */
sql, /* SQL to be evaluated */
NULL, /* Callback function */
NULL, /* 1st argument to callback */
NULL /* Error msg written here */
);
sqlite3_free( sql );
}
if ( status == SQLITE_OK )
{
result = true;
}
else
{
errCause = tr( "There was an error deleting the layer: %1" ).arg( errmsg );
sqlite3_free( errmsg );
}
}
sqlite3_close( handle );
}
}
else
{
// This should never happen!
errCause = QStringLiteral( "Layer URI is empty: layer <b>%1</b> cannot be deleted!" ).arg( mName );
}
return result;
}


bool QgsGeoPackageVectorLayerItem::executeDeleteLayer( QString &errCause )
{
return ::deleteLayer( mUri, errCause );
}
#endif

0 comments on commit 475998e

Please sign in to comment.