Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsgeopackagedataitems.h
3 : : ---------------------
4 : : begin : August 2017
5 : : copyright : (C) 2017 by Alessandro Pasotti
6 : : email : apasotti at boundlessgeo dot com
7 : : ***************************************************************************
8 : : * *
9 : : * This program is free software; you can redistribute it and/or modify *
10 : : * it under the terms of the GNU General Public License as published by *
11 : : * the Free Software Foundation; either version 2 of the License, or *
12 : : * (at your option) any later version. *
13 : : * *
14 : : ***************************************************************************/
15 : : #include "qgsgeopackagedataitems.h"
16 : : ///@cond PRIVATE
17 : :
18 : : #include "qgssqliteutils.h"
19 : : #include "qgsgeopackagedataitems.h"
20 : : #include "qgsogrdbconnection.h"
21 : : #include "qgslogger.h"
22 : : #include "qgssettings.h"
23 : : #include "qgsproject.h"
24 : : #include "qgsvectorlayer.h"
25 : : #include "qgsrasterlayer.h"
26 : : #include "qgsogrprovider.h"
27 : : #include "qgsogrdataitems.h"
28 : : #include "qgsapplication.h"
29 : : #include "qgsmessageoutput.h"
30 : : #include "qgsvectorlayerexporter.h"
31 : : #include "qgsgeopackagerasterwritertask.h"
32 : : #include "qgstaskmanager.h"
33 : : #include "qgsproviderregistry.h"
34 : : #include "qgsproxyprogresstask.h"
35 : : #include "qgsprojectstorageregistry.h"
36 : : #include "qgsgeopackageprojectstorage.h"
37 : : #include "qgsgeopackageproviderconnection.h"
38 : :
39 : 3 : QString QgsGeoPackageDataItemProvider::name()
40 : : {
41 : 6 : return QStringLiteral( "GPKG" );
42 : : }
43 : :
44 : 6 : QString QgsGeoPackageDataItemProvider::dataProviderKey() const
45 : : {
46 : 12 : return QStringLiteral( "ogr" );
47 : : }
48 : :
49 : 0 : int QgsGeoPackageDataItemProvider::capabilities() const
50 : : {
51 : 0 : return QgsDataProvider::Database;
52 : : }
53 : :
54 : 0 : QgsDataItem *QgsGeoPackageDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
55 : : {
56 : 0 : QgsDebugMsgLevel( "path = " + path, 2 );
57 : 0 : if ( path.isEmpty() )
58 : : {
59 : 0 : return new QgsGeoPackageRootItem( parentItem, QStringLiteral( "GeoPackage" ), QStringLiteral( "gpkg:" ) );
60 : : }
61 : 0 : return nullptr;
62 : 0 : }
63 : :
64 : 0 : QgsGeoPackageRootItem::QgsGeoPackageRootItem( QgsDataItem *parent, const QString &name, const QString &path )
65 : 0 : : QgsConnectionsRootItem( parent, name, path, QStringLiteral( "GPKG" ) )
66 : 0 : {
67 : 0 : mCapabilities |= Fast;
68 : 0 : mIconName = QStringLiteral( "mGeoPackage.svg" );
69 : 0 : populate();
70 : 0 : }
71 : :
72 : 0 : QVector<QgsDataItem *> QgsGeoPackageRootItem::createChildren()
73 : : {
74 : 0 : QVector<QgsDataItem *> connections;
75 : 0 : const QStringList connList( QgsOgrDbConnection::connectionList( QStringLiteral( "GPKG" ) ) );
76 : 0 : for ( const QString &connName : connList )
77 : : {
78 : 0 : QgsOgrDbConnection connection( connName, QStringLiteral( "GPKG" ) );
79 : 0 : QgsDataItem *conn = new QgsGeoPackageConnectionItem( this, connection.name(), mPath + '/' + connection.path() );
80 : :
81 : 0 : connections.append( conn );
82 : 0 : }
83 : 0 : return connections;
84 : 0 : }
85 : :
86 : 0 : void QgsGeoPackageRootItem::onConnectionsChanged()
87 : : {
88 : 0 : refresh();
89 : 0 : }
90 : :
91 : 0 : void QgsGeoPackageRootItem::newConnection()
92 : : {
93 : 0 : if ( QgsOgrDataCollectionItem::createConnection( QStringLiteral( "GeoPackage" ), QStringLiteral( "GeoPackage Database (*.gpkg)" ), QStringLiteral( "GPKG" ) ) )
94 : : {
95 : 0 : refreshConnections();
96 : 0 : }
97 : 0 : }
98 : :
99 : 0 : QgsGeoPackageCollectionItem::QgsGeoPackageCollectionItem( QgsDataItem *parent, const QString &name, const QString &path )
100 : 0 : : QgsDataCollectionItem( parent, name, path, QStringLiteral( "GPKG" ) )
101 : 0 : {
102 : 0 : mToolTip = QString( path ).remove( QLatin1String( "gpkg:/" ) );
103 : 0 : mCapabilities |= Collapse;
104 : 0 : }
105 : :
106 : :
107 : 0 : QVector<QgsDataItem *> QgsGeoPackageCollectionItem::createChildren()
108 : : {
109 : 0 : QVector<QgsDataItem *> children;
110 : : try
111 : : {
112 : 0 : const auto layers = QgsOgrLayerItem::subLayers( mPath.remove( QLatin1String( "gpkg:/" ) ), QStringLiteral( "GPKG" ) );
113 : 0 : for ( const QgsOgrDbLayerInfo *info : layers )
114 : : {
115 : 0 : if ( info->layerType() == QgsLayerItem::LayerType::Raster )
116 : : {
117 : 0 : children.append( new QgsGeoPackageRasterLayerItem( this, info->name(), info->path(), info->uri() ) );
118 : 0 : }
119 : : else
120 : : {
121 : 0 : children.append( new QgsGeoPackageVectorLayerItem( this, info->name(), info->path(), info->uri(), info->layerType( ) ) );
122 : : }
123 : : }
124 : 0 : qDeleteAll( layers );
125 : 0 : QgsProjectStorage *storage = QgsApplication::projectStorageRegistry()->projectStorageFromType( "geopackage" );
126 : 0 : if ( storage )
127 : : {
128 : 0 : const QStringList projectNames = storage->listProjects( mPath );
129 : 0 : for ( const QString &projectName : projectNames )
130 : : {
131 : 0 : QgsGeoPackageProjectUri projectUri { true, mPath, projectName };
132 : 0 : children.append( new QgsProjectItem( this, projectName, QgsGeoPackageProjectStorage::encodeUri( projectUri ) ) );
133 : 0 : }
134 : 0 : }
135 : 0 : }
136 : : catch ( QgsOgrLayerNotValidException &ex )
137 : : {
138 : 0 : children.append( new QgsErrorItem( this, ex.what(), mPath + "/error" ) );
139 : 0 : }
140 : 0 : return children;
141 : 0 : }
142 : :
143 : 0 : bool QgsGeoPackageCollectionItem::equal( const QgsDataItem *other )
144 : : {
145 : 0 : if ( type() != other->type() )
146 : : {
147 : 0 : return false;
148 : : }
149 : 0 : const QgsGeoPackageCollectionItem *o = qobject_cast<const QgsGeoPackageCollectionItem *>( other );
150 : 0 : return o && mPath == o->mPath && mName == o->mName;
151 : :
152 : 0 : }
153 : :
154 : 0 : bool QgsGeoPackageCollectionItem::deleteRasterLayer( const QString &layerName, QString &errCause )
155 : : {
156 : 0 : QgsProviderMetadata *md { QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) ) };
157 : 0 : std::unique_ptr<QgsGeoPackageProviderConnection> conn( static_cast<QgsGeoPackageProviderConnection *>( md->createConnection( path(), QVariantMap() ) ) );
158 : 0 : if ( conn )
159 : : {
160 : : try
161 : : {
162 : 0 : conn->dropRasterTable( QString(), layerName );
163 : 0 : }
164 : : catch ( QgsProviderConnectionException &ex )
165 : : {
166 : 0 : errCause = ex.what();
167 : 0 : return false;
168 : 0 : }
169 : 0 : }
170 : : else
171 : : {
172 : 0 : errCause = QObject::tr( "There was an error retrieving the connection %1!" ).arg( path() );
173 : 0 : return false;
174 : : }
175 : 0 : return true;
176 : 0 : }
177 : :
178 : 0 : bool QgsGeoPackageCollectionItem::deleteVectorLayer( const QString &layerName, QString &errCause )
179 : : {
180 : 0 : QgsProviderMetadata *md { QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) ) };
181 : 0 : std::unique_ptr<QgsGeoPackageProviderConnection> conn( static_cast<QgsGeoPackageProviderConnection *>( md->createConnection( path(), QVariantMap() ) ) );
182 : 0 : if ( conn )
183 : : {
184 : : try
185 : : {
186 : 0 : conn->dropVectorTable( QString(), layerName );
187 : 0 : }
188 : : catch ( QgsProviderConnectionException &ex )
189 : : {
190 : 0 : errCause = ex.what();
191 : 0 : return false;
192 : 0 : }
193 : 0 : }
194 : : else
195 : : {
196 : 0 : errCause = QObject::tr( "There was an error retrieving the connection %1!" ).arg( path() );
197 : 0 : return false;
198 : : }
199 : 0 : return true;
200 : 0 : }
201 : :
202 : 0 : QWidget *QgsGeoPackageRootItem::paramWidget()
203 : : {
204 : 0 : return nullptr;
205 : : }
206 : :
207 : 0 : void QgsGeoPackageCollectionItem::addConnection()
208 : : {
209 : 0 : QgsOgrDbConnection connection( mName, QStringLiteral( "GPKG" ) );
210 : 0 : connection.setPath( mPath );
211 : 0 : connection.save();
212 : 0 : mParent->refreshConnections( QStringLiteral( "GPKG" ) );
213 : 0 : }
214 : :
215 : 0 : void QgsGeoPackageCollectionItem::deleteConnection()
216 : : {
217 : 0 : QgsOgrDbConnection::deleteConnection( name(), QStringLiteral( "GPKG" ) );
218 : 0 : mParent->refreshConnections( QStringLiteral( "GPKG" ) );
219 : 0 : }
220 : :
221 : 0 : bool QgsGeoPackageCollectionItem::vacuumGeoPackageDb( const QString &name, const QString &path, QString &errCause )
222 : : {
223 : 0 : QgsScopedProxyProgressTask task( tr( "Vacuuming %1" ).arg( name ) );
224 : 0 : QgsProviderMetadata *md { QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) ) };
225 : 0 : std::unique_ptr<QgsGeoPackageProviderConnection> conn( static_cast<QgsGeoPackageProviderConnection *>( md->createConnection( path, QVariantMap() ) ) );
226 : 0 : if ( conn )
227 : : {
228 : : try
229 : : {
230 : 0 : conn->vacuum( QString(), QString() );
231 : 0 : }
232 : : catch ( QgsProviderConnectionException &ex )
233 : : {
234 : 0 : errCause = ex.what();
235 : 0 : return false;
236 : 0 : }
237 : 0 : }
238 : : else
239 : : {
240 : 0 : errCause = QObject::tr( "There was an error retrieving the connection %1!" ).arg( name );
241 : 0 : return false;
242 : : }
243 : 0 : return true;
244 : 0 : }
245 : :
246 : 0 : QgsGeoPackageConnectionItem::QgsGeoPackageConnectionItem( QgsDataItem *parent, const QString &name, const QString &path )
247 : 0 : : QgsGeoPackageCollectionItem( parent, name, path )
248 : 0 : {
249 : :
250 : 0 : }
251 : :
252 : 0 : bool QgsGeoPackageConnectionItem::equal( const QgsDataItem *other )
253 : : {
254 : 0 : if ( type() != other->type() )
255 : : {
256 : 0 : return false;
257 : : }
258 : 0 : const QgsGeoPackageConnectionItem *o = qobject_cast<const QgsGeoPackageConnectionItem *>( other );
259 : 0 : return o && mPath == o->mPath && mName == o->mName;
260 : :
261 : 0 : }
262 : :
263 : 0 : QgsGeoPackageAbstractLayerItem::QgsGeoPackageAbstractLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &uri, QgsLayerItem::LayerType layerType, const QString &providerKey )
264 : 0 : : QgsLayerItem( parent, name, path, uri, layerType, providerKey )
265 : 0 : , mCollection( qobject_cast<QgsGeoPackageCollectionItem*>( parent ) )
266 : 0 : {
267 : 0 : mCapabilities |= Delete;
268 : 0 : mToolTip = uri;
269 : 0 : setState( Populated ); // no children are expected
270 : 0 : }
271 : :
272 : :
273 : 0 : QStringList QgsGeoPackageAbstractLayerItem::tableNames() const
274 : : {
275 : 0 : QStringList names;
276 : : // note: not using providerKey() because GPKG methods are implemented in OGR
277 : 0 : QgsProviderMetadata *md { QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) ) };
278 : 0 : QgsGeoPackageProviderConnection *conn { static_cast<QgsGeoPackageProviderConnection *>( md->findConnection( parent()->name() ) ) };
279 : 0 : if ( conn )
280 : : {
281 : 0 : for ( const QgsGeoPackageProviderConnection::TableProperty &p : conn->tables( ) )
282 : : {
283 : 0 : names.push_back( p.tableName() );
284 : : }
285 : 0 : }
286 : 0 : return names;
287 : 0 : }
288 : :
289 : :
290 : 0 : QList<QgsMapLayer *> QgsGeoPackageAbstractLayerItem::layersInProject() const
291 : : {
292 : : // Check if the layer(s) are in the registry
293 : 0 : QList<QgsMapLayer *> layersList;
294 : 0 : const auto mapLayers( QgsProject::instance()->mapLayers() );
295 : 0 : for ( QgsMapLayer *layer : mapLayers )
296 : : {
297 : 0 : if ( layer->publicSource() == mUri )
298 : : {
299 : 0 : layersList << layer;
300 : 0 : }
301 : : }
302 : 0 : return layersList;
303 : 0 : }
304 : :
305 : 0 : QgsGeoPackageCollectionItem *QgsGeoPackageAbstractLayerItem::collection() const
306 : : {
307 : 0 : return mCollection;
308 : : }
309 : :
310 : 0 : QgsGeoPackageVectorLayerItem::QgsGeoPackageVectorLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &uri, LayerType layerType )
311 : 0 : : QgsGeoPackageAbstractLayerItem( parent, name, path, uri, layerType, QStringLiteral( "ogr" ) )
312 : 0 : {
313 : 0 : mCapabilities |= ( Rename | Fertile );
314 : 0 : setState( QgsDataItem::State::NotPopulated );
315 : 0 : }
316 : :
317 : :
318 : 0 : QVector<QgsDataItem *> QgsGeoPackageVectorLayerItem::createChildren()
319 : : {
320 : 0 : QVector<QgsDataItem *> children;
321 : 0 : children.push_back( new QgsFieldsItem( this, collection()->path() + QStringLiteral( "/columns/ " ), collection()->path(), providerKey(), QString(), name() ) );
322 : 0 : return children;
323 : 0 : }
324 : :
325 : :
326 : 0 : QgsGeoPackageRasterLayerItem::QgsGeoPackageRasterLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &uri )
327 : 0 : : QgsGeoPackageAbstractLayerItem( parent, name, path, uri, QgsLayerItem::LayerType::Raster, QStringLiteral( "gdal" ) )
328 : 0 : {
329 : 0 : }
330 : :
331 : 0 : bool QgsGeoPackageRasterLayerItem::executeDeleteLayer( QString &errCause )
332 : : {
333 : 0 : QgsProviderMetadata *md { QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) ) };
334 : 0 : std::unique_ptr<QgsGeoPackageProviderConnection> conn( static_cast<QgsGeoPackageProviderConnection *>( md->createConnection( collection()->path(), QVariantMap() ) ) );
335 : 0 : QString tableName = name();
336 : 0 : if ( conn->tableExists( QString(), tableName ) )
337 : : {
338 : : try
339 : : {
340 : 0 : conn->dropRasterTable( QString(), tableName );
341 : 0 : }
342 : : catch ( QgsProviderConnectionException &ex )
343 : : {
344 : 0 : errCause = ex.what();
345 : 0 : return false;
346 : 0 : }
347 : 0 : }
348 : : else
349 : : {
350 : 0 : errCause = QObject::tr( "There was an error deleting '%1' on '%2'!" )
351 : 0 : .arg( tableName )
352 : 0 : .arg( collection()->path() );
353 : 0 : return false;
354 : : }
355 : 0 : return true;
356 : 0 : }
357 : :
358 : 0 : bool QgsGeoPackageVectorLayerItem::executeDeleteLayer( QString &errCause )
359 : : {
360 : 0 : QgsProviderMetadata *md { QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) ) };
361 : 0 : std::unique_ptr<QgsGeoPackageProviderConnection> conn( static_cast<QgsGeoPackageProviderConnection *>( md->createConnection( collection()->path(), QVariantMap() ) ) );
362 : 0 : QString tableName = name();
363 : 0 : if ( conn )
364 : : {
365 : : try
366 : : {
367 : 0 : conn->dropVectorTable( QString(), tableName );
368 : 0 : }
369 : : catch ( QgsProviderConnectionException &ex )
370 : : {
371 : 0 : errCause = ex.what();
372 : 0 : return false;
373 : 0 : }
374 : 0 : }
375 : : else
376 : : {
377 : 0 : errCause = QObject::tr( "There was an error deleting '%1' on '%2'!" )
378 : 0 : .arg( tableName, parent()->path() );
379 : 0 : return false;
380 : : }
381 : 0 : return true;
382 : 0 : }
383 : :
384 : : ///@endcond
385 : :
386 : :
387 : 0 : bool QgsGeoPackageCollectionItem::layerCollection() const
388 : : {
389 : 0 : return true;
390 : : }
391 : :
392 : 0 : bool QgsGeoPackageCollectionItem::hasDragEnabled() const
393 : : {
394 : 0 : return true;
395 : : }
396 : :
397 : 0 : QgsMimeDataUtils::UriList QgsGeoPackageCollectionItem::mimeUris() const
398 : : {
399 : 0 : QgsMimeDataUtils::Uri vectorUri;
400 : 0 : vectorUri.providerKey = QStringLiteral( "ogr" );
401 : 0 : vectorUri.uri = path();
402 : 0 : vectorUri.layerType = QStringLiteral( "vector" );
403 : 0 : QgsMimeDataUtils::Uri rasterUri { vectorUri };
404 : 0 : rasterUri.layerType = QStringLiteral( "raster" );
405 : 0 : rasterUri.providerKey = QStringLiteral( "gdal" );
406 : 0 : return { vectorUri, rasterUri };
407 : 0 : }
|