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
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* * * *
***************************************************************************/ ***************************************************************************/


#include "sqlite3.h"

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


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


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

#endif


void QgsGeoPackageRootItem::connectionsChanged() void QgsGeoPackageRootItem::connectionsChanged()
{ {
Expand Down Expand Up @@ -214,29 +218,65 @@ QVector<QgsDataItem *> QgsGeoPackageConnectionItem::createChildren()
uri = QStringLiteral( "%1|layerid=%2" ).arg( mPath, layerId ); uri = QStringLiteral( "%1|layerid=%2" ).arg( mPath, layerId );
} }
QgsGeoPackageVectorLayerItem *item = new QgsGeoPackageVectorLayerItem( this, name, mPath, uri, layerType ); 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 ); children.append( item );
} }
} }
else else
{ {
QgsDebugMsgLevel( QStringLiteral( "Layer type is not a supported GeoPackage Vector layer %1" ).arg( mPath ), 3 ); 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 ); QgsDebugMsgLevel( QStringLiteral( "Adding GeoPackage Vector item %1 %2 %3" ).arg( name, uri, geometryType ), 3 );
qDebug() << QStringLiteral( "Adding GPKG Vector item %1 %2 %3" ).arg( name, uri, geometryType );
} }
} }
} }
// Raster layers // Raster layers
QgsRasterLayer rlayer( mPath, QStringLiteral( "gdal_tmp" ), QStringLiteral( "gdal" ), false ); 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( ':' ); Q_FOREACH ( const QString &uri, rlayer.dataProvider()->subLayers( ) )
QString name = pieces.value( pieces.length() - 1 ); {
QgsDebugMsg( QStringLiteral( "Adding GPKG Raster item %1 %2 %3" ).arg( name, uri ) ); QStringList pieces = uri.split( ':' );
QgsGeoPackageRasterLayerItem *item = new QgsGeoPackageRasterLayerItem( this, name, mPath, uri ); QString name = pieces.value( pieces.length() - 1 );
children.append( item ); 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; return children;


Expand Down Expand Up @@ -361,7 +401,7 @@ bool QgsGeoPackageConnectionItem::handleDrop( const QMimeData *data, Qt::DropAct
} }
else else
{ {
// TODO: implemnent raster import // TODO: implement raster import
QgsMessageOutput *output = QgsMessageOutput::createMessageOutput(); QgsMessageOutput *output = QgsMessageOutput::createMessageOutput();
output->setTitle( tr( "Import to GeoPackage database faile" ) ); 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 ); 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 *> QgsGeoPackageAbstractLayerItem::actions()
{ {
QList<QAction *> lst; 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 ); 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 ); lst.append( actionDeleteLayer );
return lst; return lst;
} }
#endif



void QgsGeoPackageAbstractLayerItem::deleteLayer()
void QgsGeoPackageVectorLayerItem::deleteLayer()
{ {
// Check if the layer is in the registry // Check if the layer is in the registry
const QgsMapLayer *projectLayer = nullptr; const QgsMapLayer *projectLayer = nullptr;
Expand All @@ -492,28 +502,140 @@ void QgsGeoPackageVectorLayerItem::deleteLayer()
if ( ! projectLayer ) if ( ! projectLayer )
{ {
if ( QMessageBox::question( nullptr, QObject::tr( "Delete Layer" ), 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 ) QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
return; return;


QString errCause; QString errCause;
bool res = ::deleteLayer( mUri, errCause ); bool res = executeDeleteLayer( errCause );
if ( !res ) if ( !res )
{ {
QMessageBox::warning( nullptr, tr( "Delete Layer" ), errCause ); QMessageBox::warning( nullptr, tr( "Delete Layer" ), errCause );
} }
else 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 ) if ( mParent )
mParent->refresh(); mParent->refresh();
} }
} }
else 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() ) ); " 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


Loading

0 comments on commit 475998e

Please sign in to comment.