Skip to content

Commit 1b72a0d

Browse files
committed
Moved some reusable methods from gpkg to the ogr items class
1 parent ce54111 commit 1b72a0d

File tree

2 files changed

+238
-1
lines changed

2 files changed

+238
-1
lines changed

src/providers/ogr/qgsogrdataitems.cpp

+187
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,26 @@
1414
***************************************************************************/
1515

1616
#include "qgsogrdataitems.h"
17+
#include "qgsogrdbconnection.h"
1718

1819
#include "qgslogger.h"
1920
#include "qgsmessagelog.h"
2021
#include "qgssettings.h"
2122
#include "qgsproject.h"
23+
#include "qgsvectorlayer.h"
24+
#include "qgsrasterlayer.h"
2225

2326
#include <QFileInfo>
2427
#include <QTextStream>
2528
#include <QAction>
2629
#include <QMessageBox>
30+
#include <QInputDialog>
31+
#include <QFileDialog>
2732

2833
#include <ogr_srs_api.h>
2934
#include <cpl_error.h>
3035
#include <cpl_conv.h>
36+
#include <gdal.h>
3137

3238
// these are defined in qgsogrprovider.cpp
3339
QGISEXTERN QStringList fileExtensions();
@@ -107,6 +113,155 @@ bool QgsOgrLayerItem::setCrs( const QgsCoordinateReferenceSystem &crs )
107113
return true;
108114
}
109115

116+
QgsLayerItem::LayerType QgsOgrLayerItem::layerTypeFromDb( const QString &geometryType )
117+
{
118+
if ( geometryType.contains( QStringLiteral( "Point" ), Qt::CaseInsensitive ) )
119+
{
120+
return QgsLayerItem::LayerType::Point;
121+
}
122+
else if ( geometryType.contains( QStringLiteral( "Polygon" ), Qt::CaseInsensitive ) )
123+
{
124+
return QgsLayerItem::LayerType::Polygon;
125+
}
126+
else if ( geometryType.contains( QStringLiteral( "LineString" ), Qt::CaseInsensitive ) )
127+
{
128+
return QgsLayerItem::LayerType::Line;
129+
}
130+
else if ( geometryType.contains( QStringLiteral( "Collection" ), Qt::CaseInsensitive ) )
131+
{
132+
return QgsLayerItem::LayerType::Vector;
133+
}
134+
// To be moved in a parent class that would also work for gdal and rasters
135+
else if ( geometryType.contains( QStringLiteral( "Raster" ), Qt::CaseInsensitive ) )
136+
{
137+
return QgsLayerItem::LayerType::Raster;
138+
}
139+
return QgsLayerItem::LayerType::TableLayer;
140+
}
141+
142+
QList<QgsOgrDbLayerInfo *> QgsOgrLayerItem::subLayers( const QString &path, const QString &driver )
143+
{
144+
145+
QList<QgsOgrDbLayerInfo *> children;
146+
147+
// Vector layers
148+
QgsVectorLayer layer( path, QStringLiteral( "ogr_tmp" ), QStringLiteral( "ogr" ) );
149+
if ( ! layer.isValid( ) )
150+
{
151+
QgsDebugMsgLevel( tr( "Layer is not a valid %1 Vector layer %2" ).arg( path ), 3 );
152+
}
153+
else
154+
{
155+
// Collect mixed-geom layers
156+
QMultiMap<int, QStringList> subLayersMap;
157+
const QStringList subLayersList( layer.dataProvider()->subLayers( ) );
158+
for ( const QString &descriptor : subLayersList )
159+
{
160+
QStringList pieces = descriptor.split( ':' );
161+
subLayersMap.insert( pieces[0].toInt(), pieces );
162+
}
163+
int prevIdx = -1;
164+
for ( const int &idx : subLayersMap.keys( ) )
165+
{
166+
if ( idx == prevIdx )
167+
{
168+
continue;
169+
}
170+
prevIdx = idx;
171+
QList<QStringList> values = subLayersMap.values( idx );
172+
for ( int i = 0; i < values.size(); ++i )
173+
{
174+
QStringList pieces = values.at( i );
175+
QString layerId = pieces[0];
176+
QString name = pieces[1];
177+
// QString featuresCount = pieces[2]; // Not used
178+
QString geometryType = pieces[3];
179+
QString geometryColumn = pieces[4];
180+
QgsLayerItem::LayerType layerType;
181+
layerType = QgsOgrLayerItem::layerTypeFromDb( geometryType );
182+
// example URI for mixed-geoms geoms: '/path/gdal_sample_v1.2_no_extensions.gpkg|layerid=7|geometrytype=Point'
183+
// example URI for mixed-geoms attr table: '/path/gdal_sample_v1.2_no_extensions.gpkg|layername=MyLayer|layerid=7'
184+
// example URI for single geoms: '/path/gdal_sample_v1.2_no_extensions.gpkg|layerid=6'
185+
QString uri;
186+
if ( layerType != QgsLayerItem::LayerType::NoType )
187+
{
188+
if ( geometryType.contains( QStringLiteral( "Collection" ), Qt::CaseInsensitive ) )
189+
{
190+
QgsDebugMsgLevel( QStringLiteral( "Layer %1 is a geometry collection: skipping %2" ).arg( name, path ), 3 );
191+
}
192+
else
193+
{
194+
if ( values.size() > 1 )
195+
{
196+
uri = QStringLiteral( "%1|layerid=%2|geometrytype=%3" ).arg( path, layerId, geometryType );
197+
}
198+
else
199+
{
200+
uri = QStringLiteral( "%1|layerid=%2" ).arg( path, layerId );
201+
}
202+
QgsDebugMsgLevel( QStringLiteral( "Adding %1 Vector item %2 %3 %4" ).arg( driver, name, uri, geometryType ), 3 );
203+
children.append( new QgsOgrDbLayerInfo( path, uri, name, geometryColumn, geometryType, layerType ) );
204+
}
205+
}
206+
else
207+
{
208+
QgsDebugMsgLevel( QStringLiteral( "Layer type is not a supported %1 Vector layer %2" ).arg( driver, path ), 3 );
209+
uri = QStringLiteral( "%1|layerid=%2|layername=%3" ).arg( path, layerId, name );
210+
children.append( new QgsOgrDbLayerInfo( path, uri, name, geometryColumn, geometryType, QgsLayerItem::LayerType::TableLayer ) );
211+
}
212+
QgsDebugMsgLevel( QStringLiteral( "Adding %1 Vector item %2 %3 %4" ).arg( driver, name, uri, geometryType ), 3 );
213+
}
214+
}
215+
}
216+
// Raster layers
217+
QgsRasterLayer rlayer( path, QStringLiteral( "gdal_tmp" ), QStringLiteral( "gdal" ), false );
218+
if ( rlayer.dataProvider()->subLayers( ).size() > 0 )
219+
{
220+
Q_FOREACH ( const QString &uri, rlayer.dataProvider()->subLayers( ) )
221+
{
222+
QStringList pieces = uri.split( ':' );
223+
QString name = pieces.value( pieces.length() - 1 );
224+
QgsDebugMsgLevel( QStringLiteral( "Adding GeoPackage Raster item %1 %2 %3" ).arg( name, uri ), 3 );
225+
children.append( new QgsOgrDbLayerInfo( path, uri, name, QStringLiteral( "" ), QStringLiteral( "Raster" ), QgsLayerItem::LayerType::Raster ) );
226+
}
227+
}
228+
else if ( rlayer.isValid( ) )
229+
{
230+
// Get the identifier
231+
GDALAllRegister();
232+
// do not print errors, but write to debug
233+
CPLPushErrorHandler( CPLQuietErrorHandler );
234+
CPLErrorReset();
235+
GDALDatasetH hDS = GDALOpen( path.toUtf8().constData(), GA_ReadOnly );
236+
CPLPopErrorHandler();
237+
238+
if ( ! hDS )
239+
{
240+
QgsDebugMsg( QString( "GDALOpen error # %1 : %2 " ).arg( CPLGetLastErrorNo() ).arg( CPLGetLastErrorMsg() ) );
241+
242+
}
243+
else
244+
{
245+
QString uri( QStringLiteral( "%1:%1" ).arg( driver, path ) );
246+
QString name = GDALGetMetadataItem( hDS, "IDENTIFIER", NULL );
247+
GDALClose( hDS );
248+
// Fallback: will not be able to delete the table
249+
if ( name.isEmpty() )
250+
{
251+
name = QFileInfo( path ).fileName();
252+
}
253+
else
254+
{
255+
uri += QStringLiteral( ":%1" ).arg( name );
256+
}
257+
258+
QgsDebugMsgLevel( QStringLiteral( "Adding %1 Raster item %2 %3" ).arg( driver, name, path ), 3 );
259+
children.append( new QgsOgrDbLayerInfo( path, uri, name, QStringLiteral( "" ), QStringLiteral( "Raster" ), QgsLayerItem::LayerType::Raster ) );
260+
}
261+
}
262+
return children;
263+
}
264+
110265
QString QgsOgrLayerItem::layerName() const
111266
{
112267
QFileInfo info( name() );
@@ -266,6 +421,38 @@ QVector<QgsDataItem *> QgsOgrDataCollectionItem::createChildren()
266421
return children;
267422
}
268423

424+
bool QgsOgrDataCollectionItem::storeConnection( const QString &path, const QString &ogrDriverName )
425+
{
426+
QFileInfo fileInfo( path );
427+
QString connName = fileInfo.fileName();
428+
if ( ! path.isEmpty() )
429+
{
430+
bool ok = true;
431+
while ( ok && ! QgsOgrDbConnection( connName, ogrDriverName ).path( ).isEmpty( ) )
432+
{
433+
434+
connName = QInputDialog::getText( nullptr, tr( "Cannot add connection '%1'" ).arg( connName ),
435+
tr( "A connection with the same name already exists,\nplease provide a new name:" ), QLineEdit::Normal,
436+
QLatin1String( "" ), &ok );
437+
}
438+
if ( ok && ! connName.isEmpty() )
439+
{
440+
QgsOgrDbConnection connection( connName, ogrDriverName );
441+
connection.setPath( path );
442+
connection.save();
443+
return true;
444+
}
445+
}
446+
return false;
447+
}
448+
449+
bool QgsOgrDataCollectionItem::createConnection( const QString &name, const QString &extensions, const QString &ogrDriverName )
450+
{
451+
QString path = QFileDialog::getOpenFileName( nullptr, tr( "Open %1" ).arg( name ), "", extensions );
452+
return storeConnection( path, ogrDriverName );
453+
}
454+
455+
269456
// ---------------------------------------------------------------------------
270457

271458
QGISEXTERN int dataCapabilities()

src/providers/ogr/qgsogrdataitems.h

+51-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,39 @@
2020
#include "qgsogrprovider.h"
2121
#include "qgsdataitemprovider.h"
2222

23+
24+
/**
25+
* Holds the information about a gpkg layer
26+
*/
27+
class QgsOgrDbLayerInfo
28+
{
29+
public:
30+
QgsOgrDbLayerInfo( const QString &path, const QString &uri, const QString &name, const QString &theGeometryColumn, const QString &theGeometryType, const QgsLayerItem::LayerType &theLayerType )
31+
: mPath( path )
32+
, mUri( uri )
33+
, mName( name )
34+
, mGeometryColumn( theGeometryColumn )
35+
, mGeometryType( theGeometryType )
36+
, mLayerType( theLayerType )
37+
{
38+
}
39+
const QString path() const { return mPath; }
40+
const QString uri() const { return mUri; }
41+
const QString name() const { return mName; }
42+
const QString geometryColumn() const { return mGeometryColumn; }
43+
const QString geometryType() const { return mGeometryType; }
44+
QgsLayerItem::LayerType layerType() const { return mLayerType; }
45+
46+
private:
47+
QString mPath;
48+
QString mUri;
49+
QString mName;
50+
QString mGeometryColumn;
51+
QString mGeometryType;
52+
QgsLayerItem::LayerType mLayerType = QgsLayerItem::LayerType::NoType;
53+
};
54+
55+
2356
class QgsOgrLayerItem : public QgsLayerItem
2457
{
2558
Q_OBJECT
@@ -29,6 +62,10 @@ class QgsOgrLayerItem : public QgsLayerItem
2962
bool setCrs( const QgsCoordinateReferenceSystem &crs ) override;
3063

3164
QString layerName() const override;
65+
//! Retrieve sub layers from a DB ogr layer \a path with the specified \a driver
66+
static QList<QgsOgrDbLayerInfo *> subLayers( const QString &path, const QString &driver );
67+
//! Return a LayerType from a geometry type string
68+
static QgsLayerItem::LayerType layerTypeFromDb( const QString &geometryType );
3269

3370
#ifdef HAVE_GUI
3471
QList<QAction *> actions() override;
@@ -47,8 +84,21 @@ class QgsOgrDataCollectionItem : public QgsDataCollectionItem
4784
QgsOgrDataCollectionItem( QgsDataItem *parent, QString name, QString path );
4885

4986
QVector<QgsDataItem *> createChildren() override;
50-
};
5187

88+
/** Utility function to store DB connections
89+
* \param path to the DB
90+
* \param ogrDriverName the OGR/GDAL driver name (e.g. "GPKG")
91+
*/
92+
static bool storeConnection( const QString &path, const QString &ogrDriverName );
93+
94+
/** Utility function to create and tore a new DB connection
95+
* \param name is the translatable name of the managed layers (e.g. "GeoPackage")
96+
* \param extensions is a string with file extensions (e.g. "GeoPackage Database (*.gpkg *.GPKG)")
97+
* \param ogrDriverName the OGR/GDAL driver name (e.g. "GPKG")
98+
*/
99+
static bool createConnection( const QString &name, const QString &extensions, const QString &ogrDriverName );
100+
101+
};
52102

53103

54104
#endif // QGSOGRDATAITEMS_H

0 commit comments

Comments
 (0)