Skip to content
Permalink
Browse files
Merge pull request #5027 from boundlessgeo/gpkg-vector-delete
[feature][needs-docs] Adds delete layer context action to ogr and geopackage items
  • Loading branch information
elpaso committed Aug 16, 2017
2 parents f610ffa + 497d4a8 commit 11fb601
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 7 deletions.
@@ -20,13 +20,16 @@
#include "qgsproject.h"
#include "qgsvectorlayer.h"
#include "qgsrasterlayer.h"
#include "qgsogrprovider.h"
#include "qgsnewgeopackagelayerdialog.h"

#include <QAction>
#include <QMessageBox>
#include <QFileDialog>
#include <QInputDialog>

QGISEXTERN bool deleteLayer( const QString &uri, const QString &errCause );

QgsDataItem *QgsGeoPackageDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
{
QgsDebugMsg( "path = " + path );
@@ -327,7 +330,6 @@ void QgsGeoPackageConnectionItem::addTable()
QList<QAction *> QgsGeoPackageAbstractLayerItem::actions()
{
QList<QAction *> lst;

// TODO: delete layer when the provider supports it (not currently implemented)
return lst;
}
@@ -352,3 +354,55 @@ QgsGeoPackageRasterLayerItem::QgsGeoPackageRasterLayerItem( QgsDataItem *parent,
{

}


#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 );
lst.append( actionDeleteLayer );
return lst;
}


void QgsGeoPackageVectorLayerItem::deleteLayer()
{
// Check if the layer is in the registry
const QgsMapLayer *projectLayer = nullptr;
Q_FOREACH ( const QgsMapLayer *layer, QgsProject::instance()->mapLayers() )
{
if ( layer->publicSource() == mUri )
{
projectLayer = layer;
}
}
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 ),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
return;

QString errCause;
bool res = ::deleteLayer( mUri, errCause );
if ( !res )
{
QMessageBox::warning( nullptr, tr( "Delete Layer" ), errCause );
}
else
{
QMessageBox::information( nullptr, tr( "Delete Layer" ), tr( "Layer deleted successfully." ) );
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',"
" remove it from the project and retry." ).arg( mName, projectLayer->name() ) );
}
}
#endif

@@ -49,7 +49,11 @@ class QgsGeoPackageVectorLayerItem : public QgsGeoPackageAbstractLayerItem
Q_OBJECT
public:
QgsGeoPackageVectorLayerItem( QgsDataItem *parent, QString name, QString path, QString uri, LayerType layerType );

#ifdef HAVE_GUI
QList<QAction *> actions() override;
public slots:
void deleteLayer();
#endif
};


@@ -18,10 +18,12 @@
#include "qgslogger.h"
#include "qgsmessagelog.h"
#include "qgssettings.h"
#include "qgsproject.h"

#include <QFileInfo>
#include <QTextStream>
#include <QAction>
#include <QMessageBox>

#include <ogr_srs_api.h>
#include <cpl_error.h>
@@ -31,11 +33,14 @@
QGISEXTERN QStringList fileExtensions();
QGISEXTERN QStringList wildcards();

QGISEXTERN bool deleteLayer( const QString &uri, const QString &errCause );


QgsOgrLayerItem::QgsOgrLayerItem( QgsDataItem *parent,
QString name, QString path, QString uri, LayerType layerType )
QString name, QString path, QString uri, LayerType layerType, bool isSubLayer )
: QgsLayerItem( parent, name, path, uri, layerType, QStringLiteral( "ogr" ) )
{
mIsSubLayer = isSubLayer;
mToolTip = uri;
setState( Populated ); // children are not expected

@@ -56,6 +61,7 @@ QgsOgrLayerItem::QgsOgrLayerItem( QgsDataItem *parent,
}
}


bool QgsOgrLayerItem::setCrs( const QgsCoordinateReferenceSystem &crs )
{
if ( !( mCapabilities & SetCrs ) )
@@ -110,9 +116,71 @@ QString QgsOgrLayerItem::layerName() const
return info.completeBaseName();
}

#ifdef HAVE_GUI
QList<QAction *> QgsOgrLayerItem::actions()
{
QList<QAction *> lst;
// Messages are different for files and tables
QString message = mIsSubLayer ? QObject::tr( "Delete layer '%1'..." ).arg( mName ) : QObject::tr( "Delete file '%1'..." ).arg( mUri );
QAction *actionDeleteLayer = new QAction( message, this );
connect( actionDeleteLayer, &QAction::triggered, this, &QgsOgrLayerItem::deleteLayer );
lst.append( actionDeleteLayer );
return lst;
}

void QgsOgrLayerItem::deleteLayer()
{
// Messages are different for files and tables
QString title = mIsSubLayer ? QObject::tr( "Delete Layer" ) : QObject::tr( "Delete File" );
// Check if the layer is in the registry
const QgsMapLayer *projectLayer = nullptr;
Q_FOREACH ( const QgsMapLayer *layer, QgsProject::instance()->mapLayers() )
{
if ( layer->publicSource() == mUri )
{
projectLayer = layer;
}
}
if ( ! projectLayer )
{
QString confirmMessage;
if ( mIsSubLayer )
{
confirmMessage = QObject::tr( "Are you sure you want to delete layer '%1' from datasource?" ).arg( mName );
}
else
{
confirmMessage = QObject::tr( "Are you sure you want to delete file '%1'?" ).arg( mUri );
}
if ( QMessageBox::question( nullptr, title,
confirmMessage,
QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
return;

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

// -------

static QgsOgrLayerItem *dataItemForLayer( QgsDataItem *parentItem, QString name, QString path, OGRDataSourceH hDataSource, int layerId )
static QgsOgrLayerItem *dataItemForLayer( QgsDataItem *parentItem, QString name, QString path, OGRDataSourceH hDataSource, int layerId, bool isSubLayer = false )
{
OGRLayerH hLayer = OGR_DS_GetLayer( hDataSource, layerId );
OGRFeatureDefnH hDef = OGR_L_GetLayerDefn( hLayer );
@@ -166,7 +234,7 @@ static QgsOgrLayerItem *dataItemForLayer( QgsDataItem *parentItem, QString name,

QgsDebugMsgLevel( "OGR layer uri : " + layerUri, 2 );

return new QgsOgrLayerItem( parentItem, name, path, layerUri, layerType );
return new QgsOgrLayerItem( parentItem, name, path, layerUri, layerType, isSubLayer );
}

// ----
@@ -189,7 +257,7 @@ QVector<QgsDataItem *> QgsOgrDataCollectionItem::createChildren()
children.reserve( numLayers );
for ( int i = 0; i < numLayers; ++i )
{
QgsOgrLayerItem *item = dataItemForLayer( this, QString(), mPath, hDataSource, i );
QgsOgrLayerItem *item = dataItemForLayer( this, QString(), mPath, hDataSource, i, true );
children.append( item );
}

@@ -24,11 +24,19 @@ class QgsOgrLayerItem : public QgsLayerItem
{
Q_OBJECT
public:
QgsOgrLayerItem( QgsDataItem *parent, QString name, QString path, QString uri, LayerType layerType );
QgsOgrLayerItem( QgsDataItem *parent, QString name, QString path, QString uri, LayerType layerType, bool isSubLayer = false );

bool setCrs( const QgsCoordinateReferenceSystem &crs ) override;

QString layerName() const override;

#ifdef HAVE_GUI
QList<QAction *> actions() override;
public slots:
void deleteLayer();
#endif
private:
bool mIsSubLayer;
};


@@ -4297,3 +4297,76 @@ QGISEXTERN void cleanupProvider()
// NOTE: QgsApplication takes care of
// calling OGRCleanupAll();
}



QGISEXTERN bool deleteLayer( const QString &uri, QString &errCause )
{
bool isSubLayer;
int layerIndex;
QString layerName;
QString subsetString;
OGRwkbGeometryType ogrGeometryType;
QString filePath = AnalyzeURI( uri,
isSubLayer,
layerIndex,
layerName,
subsetString,
ogrGeometryType );

OGRDataSourceH hDS = GDALOpenEx( filePath.toLocal8Bit().data(), GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_UPDATE, NULL, NULL, NULL );
if ( hDS && ( ! layerName.isEmpty() || layerIndex != -1 ) )
{
if ( layerIndex == -1 )
{
for ( int i = 0; i < GDALDatasetGetLayerCount( hDS ); i++ )
{
OGRLayerH hL = GDALDatasetGetLayer( hDS, i );
if ( layerName == QString( OGR_L_GetName( hL ) ) )
{
layerIndex = i;
}
}
}
OGRErr error = GDALDatasetDeleteLayer( hDS, layerIndex );
switch ( error )
{
case OGRERR_NOT_ENOUGH_DATA:
errCause = QObject::tr( "Not enough data to deserialize" );
break;
case OGRERR_NOT_ENOUGH_MEMORY:
errCause = QObject::tr( "Not enough memory" );
break;
case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
errCause = QObject::tr( "Unsupported geometry type" );
break;
case OGRERR_UNSUPPORTED_OPERATION:
errCause = QObject::tr( "Unsupported operation" );
break;
case OGRERR_CORRUPT_DATA:
errCause = QObject::tr( "Corrupt data" );
break;
case OGRERR_FAILURE:
errCause = QObject::tr( "Failure" );
break;
case OGRERR_UNSUPPORTED_SRS:
errCause = QObject::tr( "Unsupported SRS" );
break;
case OGRERR_INVALID_HANDLE:
errCause = QObject::tr( "Invalid handle" );
break;
case OGRERR_NON_EXISTING_FEATURE:
errCause = QObject::tr( "Non existing feature" );
break;
default:
case OGRERR_NONE:
errCause = QObject::tr( "Success" );
break;
}
errCause = QObject::tr( "GDAL result code: %s" ).arg( errCause );
return error == OGRERR_NONE;
}
// This should never happen:
errCause = QObject::tr( "Layer not found: %s" ).arg( uri );
return false;
}

0 comments on commit 11fb601

Please sign in to comment.