Skip to content

Commit 11fb601

Browse files
authored
Merge pull request #5027 from boundlessgeo/gpkg-vector-delete
[feature][needs-docs] Adds delete layer context action to ogr and geopackage items
2 parents f610ffa + 497d4a8 commit 11fb601

File tree

5 files changed

+214
-7
lines changed

5 files changed

+214
-7
lines changed

src/providers/ogr/qgsgeopackagedataitems.cpp

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@
2020
#include "qgsproject.h"
2121
#include "qgsvectorlayer.h"
2222
#include "qgsrasterlayer.h"
23+
#include "qgsogrprovider.h"
2324
#include "qgsnewgeopackagelayerdialog.h"
2425

2526
#include <QAction>
2627
#include <QMessageBox>
2728
#include <QFileDialog>
2829
#include <QInputDialog>
2930

31+
QGISEXTERN bool deleteLayer( const QString &uri, const QString &errCause );
32+
3033
QgsDataItem *QgsGeoPackageDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
3134
{
3235
QgsDebugMsg( "path = " + path );
@@ -327,7 +330,6 @@ void QgsGeoPackageConnectionItem::addTable()
327330
QList<QAction *> QgsGeoPackageAbstractLayerItem::actions()
328331
{
329332
QList<QAction *> lst;
330-
331333
// TODO: delete layer when the provider supports it (not currently implemented)
332334
return lst;
333335
}
@@ -352,3 +354,55 @@ QgsGeoPackageRasterLayerItem::QgsGeoPackageRasterLayerItem( QgsDataItem *parent,
352354
{
353355

354356
}
357+
358+
359+
#ifdef HAVE_GUI
360+
QList<QAction *> QgsGeoPackageVectorLayerItem::actions()
361+
{
362+
QList<QAction *> lst = QgsGeoPackageAbstractLayerItem::actions();
363+
QAction *actionDeleteLayer = new QAction( tr( "Delete layer '%1'..." ).arg( mName ), this );
364+
connect( actionDeleteLayer, &QAction::triggered, this, &QgsGeoPackageVectorLayerItem::deleteLayer );
365+
lst.append( actionDeleteLayer );
366+
return lst;
367+
}
368+
369+
370+
void QgsGeoPackageVectorLayerItem::deleteLayer()
371+
{
372+
// Check if the layer is in the registry
373+
const QgsMapLayer *projectLayer = nullptr;
374+
Q_FOREACH ( const QgsMapLayer *layer, QgsProject::instance()->mapLayers() )
375+
{
376+
if ( layer->publicSource() == mUri )
377+
{
378+
projectLayer = layer;
379+
}
380+
}
381+
if ( ! projectLayer )
382+
{
383+
if ( QMessageBox::question( nullptr, QObject::tr( "Delete Layer" ),
384+
QObject::tr( "Are you sure you want to delete layer '%1' from GeoPackage?" ).arg( mName ),
385+
QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
386+
return;
387+
388+
QString errCause;
389+
bool res = ::deleteLayer( mUri, errCause );
390+
if ( !res )
391+
{
392+
QMessageBox::warning( nullptr, tr( "Delete Layer" ), errCause );
393+
}
394+
else
395+
{
396+
QMessageBox::information( nullptr, tr( "Delete Layer" ), tr( "Layer deleted successfully." ) );
397+
if ( mParent )
398+
mParent->refresh();
399+
}
400+
}
401+
else
402+
{
403+
QMessageBox::warning( nullptr, QObject::tr( "Delete Layer" ), QObject::tr( "The layer '%1' cannot be deleted because it is in the current project as '%2',"
404+
" remove it from the project and retry." ).arg( mName, projectLayer->name() ) );
405+
}
406+
}
407+
#endif
408+

src/providers/ogr/qgsgeopackagedataitems.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ class QgsGeoPackageVectorLayerItem : public QgsGeoPackageAbstractLayerItem
4949
Q_OBJECT
5050
public:
5151
QgsGeoPackageVectorLayerItem( QgsDataItem *parent, QString name, QString path, QString uri, LayerType layerType );
52-
52+
#ifdef HAVE_GUI
53+
QList<QAction *> actions() override;
54+
public slots:
55+
void deleteLayer();
56+
#endif
5357
};
5458

5559

src/providers/ogr/qgsogrdataitems.cpp

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
#include "qgslogger.h"
1919
#include "qgsmessagelog.h"
2020
#include "qgssettings.h"
21+
#include "qgsproject.h"
2122

2223
#include <QFileInfo>
2324
#include <QTextStream>
2425
#include <QAction>
26+
#include <QMessageBox>
2527

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

36+
QGISEXTERN bool deleteLayer( const QString &uri, const QString &errCause );
37+
3438

3539
QgsOgrLayerItem::QgsOgrLayerItem( QgsDataItem *parent,
36-
QString name, QString path, QString uri, LayerType layerType )
40+
QString name, QString path, QString uri, LayerType layerType, bool isSubLayer )
3741
: QgsLayerItem( parent, name, path, uri, layerType, QStringLiteral( "ogr" ) )
3842
{
43+
mIsSubLayer = isSubLayer;
3944
mToolTip = uri;
4045
setState( Populated ); // children are not expected
4146

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

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

119+
#ifdef HAVE_GUI
120+
QList<QAction *> QgsOgrLayerItem::actions()
121+
{
122+
QList<QAction *> lst;
123+
// Messages are different for files and tables
124+
QString message = mIsSubLayer ? QObject::tr( "Delete layer '%1'..." ).arg( mName ) : QObject::tr( "Delete file '%1'..." ).arg( mUri );
125+
QAction *actionDeleteLayer = new QAction( message, this );
126+
connect( actionDeleteLayer, &QAction::triggered, this, &QgsOgrLayerItem::deleteLayer );
127+
lst.append( actionDeleteLayer );
128+
return lst;
129+
}
130+
131+
void QgsOgrLayerItem::deleteLayer()
132+
{
133+
// Messages are different for files and tables
134+
QString title = mIsSubLayer ? QObject::tr( "Delete Layer" ) : QObject::tr( "Delete File" );
135+
// Check if the layer is in the registry
136+
const QgsMapLayer *projectLayer = nullptr;
137+
Q_FOREACH ( const QgsMapLayer *layer, QgsProject::instance()->mapLayers() )
138+
{
139+
if ( layer->publicSource() == mUri )
140+
{
141+
projectLayer = layer;
142+
}
143+
}
144+
if ( ! projectLayer )
145+
{
146+
QString confirmMessage;
147+
if ( mIsSubLayer )
148+
{
149+
confirmMessage = QObject::tr( "Are you sure you want to delete layer '%1' from datasource?" ).arg( mName );
150+
}
151+
else
152+
{
153+
confirmMessage = QObject::tr( "Are you sure you want to delete file '%1'?" ).arg( mUri );
154+
}
155+
if ( QMessageBox::question( nullptr, title,
156+
confirmMessage,
157+
QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
158+
return;
159+
160+
QString errCause;
161+
bool res = ::deleteLayer( mUri, errCause );
162+
if ( !res )
163+
{
164+
QMessageBox::warning( nullptr, title, errCause );
165+
}
166+
else
167+
{
168+
QMessageBox::information( nullptr, title, mIsSubLayer ? tr( "Layer deleted successfully." ) : tr( "File deleted successfully." ) );
169+
if ( mParent )
170+
mParent->refresh();
171+
}
172+
}
173+
else
174+
{
175+
QMessageBox::warning( nullptr, title, QObject::tr( "The layer '%1' cannot be deleted because it is in the current project as '%2',"
176+
" remove it from the project and retry." ).arg( mName, projectLayer->name() ) );
177+
}
178+
}
179+
#endif
180+
113181
// -------
114182

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

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

169-
return new QgsOgrLayerItem( parentItem, name, path, layerUri, layerType );
237+
return new QgsOgrLayerItem( parentItem, name, path, layerUri, layerType, isSubLayer );
170238
}
171239

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

src/providers/ogr/qgsogrdataitems.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,19 @@ class QgsOgrLayerItem : public QgsLayerItem
2424
{
2525
Q_OBJECT
2626
public:
27-
QgsOgrLayerItem( QgsDataItem *parent, QString name, QString path, QString uri, LayerType layerType );
27+
QgsOgrLayerItem( QgsDataItem *parent, QString name, QString path, QString uri, LayerType layerType, bool isSubLayer = false );
2828

2929
bool setCrs( const QgsCoordinateReferenceSystem &crs ) override;
3030

3131
QString layerName() const override;
32+
33+
#ifdef HAVE_GUI
34+
QList<QAction *> actions() override;
35+
public slots:
36+
void deleteLayer();
37+
#endif
38+
private:
39+
bool mIsSubLayer;
3240
};
3341

3442

src/providers/ogr/qgsogrprovider.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4297,3 +4297,76 @@ QGISEXTERN void cleanupProvider()
42974297
// NOTE: QgsApplication takes care of
42984298
// calling OGRCleanupAll();
42994299
}
4300+
4301+
4302+
4303+
QGISEXTERN bool deleteLayer( const QString &uri, QString &errCause )
4304+
{
4305+
bool isSubLayer;
4306+
int layerIndex;
4307+
QString layerName;
4308+
QString subsetString;
4309+
OGRwkbGeometryType ogrGeometryType;
4310+
QString filePath = AnalyzeURI( uri,
4311+
isSubLayer,
4312+
layerIndex,
4313+
layerName,
4314+
subsetString,
4315+
ogrGeometryType );
4316+
4317+
OGRDataSourceH hDS = GDALOpenEx( filePath.toLocal8Bit().data(), GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_UPDATE, NULL, NULL, NULL );
4318+
if ( hDS && ( ! layerName.isEmpty() || layerIndex != -1 ) )
4319+
{
4320+
if ( layerIndex == -1 )
4321+
{
4322+
for ( int i = 0; i < GDALDatasetGetLayerCount( hDS ); i++ )
4323+
{
4324+
OGRLayerH hL = GDALDatasetGetLayer( hDS, i );
4325+
if ( layerName == QString( OGR_L_GetName( hL ) ) )
4326+
{
4327+
layerIndex = i;
4328+
}
4329+
}
4330+
}
4331+
OGRErr error = GDALDatasetDeleteLayer( hDS, layerIndex );
4332+
switch ( error )
4333+
{
4334+
case OGRERR_NOT_ENOUGH_DATA:
4335+
errCause = QObject::tr( "Not enough data to deserialize" );
4336+
break;
4337+
case OGRERR_NOT_ENOUGH_MEMORY:
4338+
errCause = QObject::tr( "Not enough memory" );
4339+
break;
4340+
case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
4341+
errCause = QObject::tr( "Unsupported geometry type" );
4342+
break;
4343+
case OGRERR_UNSUPPORTED_OPERATION:
4344+
errCause = QObject::tr( "Unsupported operation" );
4345+
break;
4346+
case OGRERR_CORRUPT_DATA:
4347+
errCause = QObject::tr( "Corrupt data" );
4348+
break;
4349+
case OGRERR_FAILURE:
4350+
errCause = QObject::tr( "Failure" );
4351+
break;
4352+
case OGRERR_UNSUPPORTED_SRS:
4353+
errCause = QObject::tr( "Unsupported SRS" );
4354+
break;
4355+
case OGRERR_INVALID_HANDLE:
4356+
errCause = QObject::tr( "Invalid handle" );
4357+
break;
4358+
case OGRERR_NON_EXISTING_FEATURE:
4359+
errCause = QObject::tr( "Non existing feature" );
4360+
break;
4361+
default:
4362+
case OGRERR_NONE:
4363+
errCause = QObject::tr( "Success" );
4364+
break;
4365+
}
4366+
errCause = QObject::tr( "GDAL result code: %s" ).arg( errCause );
4367+
return error == OGRERR_NONE;
4368+
}
4369+
// This should never happen:
4370+
errCause = QObject::tr( "Layer not found: %s" ).arg( uri );
4371+
return false;
4372+
}

0 commit comments

Comments
 (0)