43 #include <QDomDocument> 46 #include <QMessageBox> 48 #include <ogr_srs_api.h> 53 #include <spatialite.h> 56 #define CUSTOM_PROPERTY_IS_OFFLINE_EDITABLE "isOfflineEditable" 57 #define CUSTOM_PROPERTY_REMOTE_SOURCE "remoteSource" 58 #define CUSTOM_PROPERTY_REMOTE_PROVIDER "remoteProvider" 59 #define CUSTOM_SHOW_FEATURE_COUNT "showFeatureCount" 60 #define PROJECT_ENTRY_SCOPE_OFFLINE "OfflineEditingPlugin" 61 #define PROJECT_ENTRY_KEY_OFFLINE_DB_PATH "/OfflineDbPath" 85 if ( layerIds.isEmpty() )
90 QString dbPath = QDir( offlineDataPath ).absoluteFilePath( offlineDbFile );
91 if ( createOfflineDb( dbPath, containerType ) )
94 int rc = database.
open( dbPath );
95 if ( rc != SQLITE_OK )
97 showWarning( tr(
"Could not open the SpatiaLite database" ) );
102 createLoggingTables( database.get() );
106 QMap<QString, QgsVectorJoinList > joinInfoBuffer;
107 QMap<QString, QgsVectorLayer *> layerIdMapping;
109 for (
const QString &layerId : layerIds )
121 QgsVectorJoinList::iterator joinIt = joins.begin();
122 while ( joinIt != joins.end() )
124 if ( joinIt->prefix().isNull() )
129 joinIt->setPrefix( vl->
name() +
'_' );
133 joinInfoBuffer.insert( vl->
id(), joins );
139 for (
int i = 0; i < layerIds.count(); i++ )
147 QString origLayerId = vl->
id();
148 QgsVectorLayer *newLayer = copyVectorLayer( vl, database.get(), dbPath, onlySelected, containerType );
151 layerIdMapping.insert( origLayerId, newLayer );
154 snappingConfig.
removeLayers( QList<QgsMapLayer *>() << vl );
158 QStringList() << origLayerId );
166 QMap<QString, QgsVectorJoinList >::ConstIterator it;
167 for ( it = joinInfoBuffer.constBegin(); it != joinInfoBuffer.constEnd(); ++it )
173 const QList<QgsVectorLayerJoinInfo> joins = it.value();
176 QgsVectorLayer *newJoinedLayer = layerIdMapping.value( join.joinLayerId() );
177 if ( newJoinedLayer )
180 join.setJoinLayer( newJoinedLayer );
191 if ( projectTitle.isEmpty() )
195 projectTitle += QLatin1String(
" (offline)" );
226 QList<QgsMapLayer *> offlineLayers;
228 for ( QMap<QString, QgsMapLayer *>::iterator layer_it = mapLayers.begin() ; layer_it != mapLayers.end(); ++layer_it )
233 offlineLayers << layer;
237 QgsDebugMsgLevel( QStringLiteral(
"Found %1 offline layers" ).arg( offlineLayers.count() ), 4 );
238 for (
int l = 0; l < offlineLayers.count(); l++ )
246 QString remoteName = layer->
name();
247 remoteName.remove( QRegExp(
" \\(offline\\)$" ) );
253 if ( remoteLayer->
providerType().contains( QLatin1String(
"WFS" ), Qt::CaseInsensitive ) )
269 copySymbology( offlineLayer, remoteLayer );
270 updateRelations( offlineLayer, remoteLayer );
271 updateMapThemes( offlineLayer, remoteLayer );
272 updateLayerOrder( offlineLayer, remoteLayer );
276 snappingConfig.
removeLayers( QList<QgsMapLayer *>() << offlineLayer );
284 QString qgisLayerId = layer->
id();
285 QString sql = QStringLiteral(
"SELECT \"id\" FROM 'log_layer_ids' WHERE \"qgis_id\" = '%1'" ).arg( qgisLayerId );
286 int layerId = sqlQueryInt( database.get(), sql, -1 );
292 int commitNo = getCommitNo( database.get() );
293 QgsDebugMsgLevel( QStringLiteral(
"Found %1 commits" ).arg( commitNo ), 4 );
294 for (
int i = 0; i < commitNo; i++ )
298 applyAttributesAdded( remoteLayer, database.get(), layerId, i );
299 applyAttributeValueChanges( offlineLayer, remoteLayer, database.get(), layerId, i );
300 applyGeometryChanges( remoteLayer, database.get(), layerId, i );
303 applyFeaturesAdded( offlineLayer, remoteLayer, database.get(), layerId );
304 applyFeaturesRemoved( remoteLayer, database.get(), layerId );
309 updateFidLookup( remoteLayer, database.get(), layerId );
312 sql = QStringLiteral(
"DELETE FROM 'log_added_attrs' WHERE \"layer_id\" = %1" ).arg( layerId );
313 sqlExec( database.get(), sql );
314 sql = QStringLiteral(
"DELETE FROM 'log_added_features' WHERE \"layer_id\" = %1" ).arg( layerId );
315 sqlExec( database.get(), sql );
316 sql = QStringLiteral(
"DELETE FROM 'log_removed_features' WHERE \"layer_id\" = %1" ).arg( layerId );
317 sqlExec( database.get(), sql );
318 sql = QStringLiteral(
"DELETE FROM 'log_feature_updates' WHERE \"layer_id\" = %1" ).arg( layerId );
319 sqlExec( database.get(), sql );
320 sql = QStringLiteral(
"DELETE FROM 'log_geometry_updates' WHERE \"layer_id\" = %1" ).arg( layerId );
321 sqlExec( database.get(), sql );
325 showWarning( remoteLayer->
commitErrors().join( QStringLiteral(
"\n" ) ) );
330 QgsDebugMsg( QStringLiteral(
"Could not find the layer id in the edit logs!" ) );
341 projectTitle.remove( QRegExp(
" \\(offline\\)$" ) );
348 QgsDebugMsg( QStringLiteral(
"Remote layer is not valid!" ) );
353 QString sql = QStringLiteral(
"UPDATE 'log_indices' SET 'last_index' = 0 WHERE \"name\" = 'commit_no'" );
354 sqlExec( database.get(), sql );
361 void QgsOfflineEditing::initializeSpatialMetadata(
sqlite3 *sqlite_handle )
364 if ( !sqlite_handle )
367 char **results =
nullptr;
369 int ret = sqlite3_get_table( sqlite_handle,
"select count(*) from sqlite_master", &results, &rows, &columns,
nullptr );
370 if ( ret != SQLITE_OK )
375 for (
int i = 1; i <= rows; i++ )
376 count = atoi( results[( i * columns ) + 0] );
379 sqlite3_free_table( results );
384 bool above41 =
false;
385 ret = sqlite3_get_table( sqlite_handle,
"select spatialite_version()", &results, &rows, &columns,
nullptr );
386 if ( ret == SQLITE_OK && rows == 1 && columns == 1 )
388 QString version = QString::fromUtf8( results[1] );
389 QStringList parts = version.split(
' ', QString::SkipEmptyParts );
390 if ( !parts.empty() )
392 QStringList verparts = parts.at( 0 ).split(
'.', QString::SkipEmptyParts );
393 above41 = verparts.size() >= 2 && ( verparts.at( 0 ).toInt() > 4 || ( verparts.at( 0 ).toInt() == 4 && verparts.at( 1 ).toInt() >= 1 ) );
397 sqlite3_free_table( results );
400 char *errMsg =
nullptr;
401 ret = sqlite3_exec( sqlite_handle, above41 ?
"SELECT InitSpatialMetadata(1)" :
"SELECT InitSpatialMetadata()",
nullptr,
nullptr, &errMsg );
403 if ( ret != SQLITE_OK )
405 QString errCause = tr(
"Unable to initialize SpatialMetadata:\n" );
406 errCause += QString::fromUtf8( errMsg );
407 showWarning( errCause );
408 sqlite3_free( errMsg );
411 spatial_ref_sys_init( sqlite_handle, 0 );
414 bool QgsOfflineEditing::createOfflineDb(
const QString &offlineDbPath,
ContainerType containerType )
417 char *errMsg =
nullptr;
418 QFile newDb( offlineDbPath );
419 if ( newDb.exists() )
421 QFile::remove( offlineDbPath );
426 QFileInfo fullPath = QFileInfo( offlineDbPath );
427 QDir path = fullPath.dir();
430 QDir().mkpath( path.absolutePath() );
433 QString dbPath = newDb.fileName();
436 switch ( containerType )
440 OGRSFDriverH hGpkgDriver = OGRGetDriverByName(
"GPKG" );
443 showWarning( tr(
"Creation of database failed. GeoPackage driver not found." ) );
450 showWarning( tr(
"Creation of database failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
462 ret = database.
open_v2( dbPath, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
nullptr );
466 QString errCause = tr(
"Could not create a new database\n" );
468 showWarning( errCause );
472 ret = sqlite3_exec( database.get(),
"PRAGMA foreign_keys = 1",
nullptr,
nullptr, &errMsg );
473 if ( ret != SQLITE_OK )
475 showWarning( tr(
"Unable to activate FOREIGN_KEY constraints" ) );
476 sqlite3_free( errMsg );
479 initializeSpatialMetadata( database.get() );
483 void QgsOfflineEditing::createLoggingTables(
sqlite3 *db )
486 QString sql = QStringLiteral(
"CREATE TABLE 'log_indices' ('name' TEXT, 'last_index' INTEGER)" );
489 sql = QStringLiteral(
"INSERT INTO 'log_indices' VALUES ('commit_no', 0)" );
492 sql = QStringLiteral(
"INSERT INTO 'log_indices' VALUES ('layer_id', 0)" );
496 sql = QStringLiteral(
"CREATE TABLE 'log_layer_ids' ('id' INTEGER, 'qgis_id' TEXT)" );
500 sql = QStringLiteral(
"CREATE TABLE 'log_fids' ('layer_id' INTEGER, 'offline_fid' INTEGER, 'remote_fid' INTEGER)" );
504 sql = QStringLiteral(
"CREATE TABLE 'log_added_attrs' ('layer_id' INTEGER, 'commit_no' INTEGER, " );
505 sql += QLatin1String(
"'name' TEXT, 'type' INTEGER, 'length' INTEGER, 'precision' INTEGER, 'comment' TEXT)" );
509 sql = QStringLiteral(
"CREATE TABLE 'log_added_features' ('layer_id' INTEGER, 'fid' INTEGER)" );
513 sql = QStringLiteral(
"CREATE TABLE 'log_removed_features' ('layer_id' INTEGER, 'fid' INTEGER)" );
517 sql = QStringLiteral(
"CREATE TABLE 'log_feature_updates' ('layer_id' INTEGER, 'commit_no' INTEGER, 'fid' INTEGER, 'attr' INTEGER, 'value' TEXT)" );
521 sql = QStringLiteral(
"CREATE TABLE 'log_geometry_updates' ('layer_id' INTEGER, 'commit_no' INTEGER, 'fid' INTEGER, 'geom_wkt' TEXT)" );
534 QString tableName = layer->
id();
535 QgsDebugMsgLevel( QStringLiteral(
"Creating offline table %1 ..." ).arg( tableName ), 4 );
540 switch ( containerType )
545 QString sql = QStringLiteral(
"CREATE TABLE '%1' (" ).arg( tableName );
548 for (
const auto &field : providerFields )
551 QVariant::Type type = field.type();
552 if ( type == QVariant::Int || type == QVariant::LongLong )
554 dataType = QStringLiteral(
"INTEGER" );
556 else if ( type == QVariant::Double )
558 dataType = QStringLiteral(
"REAL" );
560 else if ( type == QVariant::String )
562 dataType = QStringLiteral(
"TEXT" );
566 showWarning( tr(
"%1: Unknown data type %2. Not using type affinity for the field." ).arg( field.name(), QVariant::typeToName( type ) ) );
569 sql += delim + QStringLiteral(
"'%1' %2" ).arg( field.name(), dataType );
574 int rc = sqlExec( db, sql );
585 geomType = QStringLiteral(
"POINT" );
588 geomType = QStringLiteral(
"MULTIPOINT" );
591 geomType = QStringLiteral(
"LINESTRING" );
594 geomType = QStringLiteral(
"MULTILINESTRING" );
597 geomType = QStringLiteral(
"POLYGON" );
600 geomType = QStringLiteral(
"MULTIPOLYGON" );
607 QString zmInfo = QStringLiteral(
"XY" );
616 if ( layer->
crs().
authid().startsWith( QLatin1String(
"EPSG:" ), Qt::CaseInsensitive ) )
618 epsgCode = layer->
crs().
authid().mid( 5 );
623 showWarning( tr(
"Layer %1 has unsupported Coordinate Reference System (%2)." ).arg( layer->
name(), layer->
crs().
authid() ) );
626 QString sqlAddGeom = QStringLiteral(
"SELECT AddGeometryColumn('%1', 'Geometry', %2, '%3', '%4')" )
627 .arg( tableName, epsgCode, geomType, zmInfo );
630 QString sqlCreateIndex = QStringLiteral(
"SELECT CreateSpatialIndex('%1', 'Geometry')" ).arg( tableName );
632 if ( rc == SQLITE_OK )
634 rc = sqlExec( db, sqlAddGeom );
635 if ( rc == SQLITE_OK )
637 rc = sqlExec( db, sqlCreateIndex );
642 if ( rc != SQLITE_OK )
644 showWarning( tr(
"Filling SpatiaLite for layer %1 failed" ).arg( layer->
name() ) );
649 QString connectionString = QStringLiteral(
"dbname='%1' table='%2'%3 sql=" )
651 tableName, layer->
isSpatial() ?
"(Geometry)" :
"" );
654 layer->
name() +
" (offline)", QStringLiteral(
"spatialite" ), options );
660 char **options =
nullptr;
662 options = CSLSetNameValue( options,
"OVERWRITE",
"YES" );
663 options = CSLSetNameValue( options,
"IDENTIFIER", tr(
"%1 (offline)" ).arg( layer->
id() ).toUtf8().constData() );
664 options = CSLSetNameValue( options,
"DESCRIPTION", layer->
dataComment().toUtf8().constData() );
667 QString fidBase( QStringLiteral(
"fid" ) );
668 QString fid = fidBase;
672 fid = fidBase +
'_' + QString::number( counter );
675 if ( counter == 10000 )
677 showWarning( tr(
"Cannot make FID-name for GPKG " ) );
681 options = CSLSetNameValue( options,
"FID", fid.toUtf8().constData() );
685 options = CSLSetNameValue( options,
"GEOMETRY_COLUMN",
"geom" );
686 options = CSLSetNameValue( options,
"SPATIAL_INDEX",
"YES" );
689 OGRSFDriverH hDriver =
nullptr;
692 OGRLayerH hLayer = OGR_DS_CreateLayer( hDS.get(), tableName.toUtf8().constData(), hSRS,
static_cast<OGRwkbGeometryType
>( layer->
wkbType() ), options );
693 CSLDestroy( options );
698 showWarning( tr(
"Creation of layer failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
703 for (
const auto &field : providerFields )
705 const QString fieldName( field.name() );
706 const QVariant::Type type = field.type();
707 OGRFieldType ogrType( OFTString );
708 if ( type == QVariant::Int )
709 ogrType = OFTInteger;
710 else if ( type == QVariant::LongLong )
711 ogrType = OFTInteger64;
712 else if ( type == QVariant::Double )
714 else if ( type == QVariant::Time )
716 else if ( type == QVariant::Date )
718 else if ( type == QVariant::DateTime )
719 ogrType = OFTDateTime;
723 int ogrWidth = field.length();
726 OGR_Fld_SetWidth( fld.get(), ogrWidth );
728 if ( OGR_L_CreateField( hLayer, fld.get(), true ) != OGRERR_NONE )
730 showWarning( tr(
"Creation of field %1 failed (OGR error: %2)" )
731 .arg( fieldName, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
739 OGR_L_ResetReading( hLayer );
740 if ( CPLGetLastErrorType() != CE_None )
742 QString msg( tr(
"Creation of layer failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
748 QString uri = QStringLiteral(
"%1|layername=%2" ).arg( offlineDbPath, tableName );
750 newLayer =
new QgsVectorLayer( uri, layer->
name() +
" (offline)", QStringLiteral(
"ogr" ), layerOptions );
767 if ( !selectedFids.isEmpty() )
781 int featureCount = 1;
783 QList<QgsFeatureId> remoteFeatureIds;
786 remoteFeatureIds << f.
id();
793 QgsAttributes newAttrs( containerType ==
GPKG ? attrs.count() + 1 : attrs.count() );
794 for (
int it = 0; it < attrs.count(); ++it )
796 newAttrs[column++] = attrs.at( it );
810 int layerId = getOrCreateLayerId( db, newLayer->
id() );
811 QList<QgsFeatureId> offlineFeatureIds;
816 offlineFeatureIds << f.
id();
820 sqlExec( db, QStringLiteral(
"BEGIN" ) );
821 int remoteCount = remoteFeatureIds.size();
822 for (
int i = 0; i < remoteCount; i++ )
825 if ( i < offlineFeatureIds.count() )
827 addFidLookup( db, layerId, offlineFeatureIds.at( i ), remoteFeatureIds.at( i ) );
831 showWarning( tr(
"Feature cannot be copied to the offline layer, please check if the online layer '%1' is still accessible." ).arg( layer->
name() ) );
836 sqlExec( db, QStringLiteral(
"COMMIT" ) );
840 showWarning( newLayer->
commitErrors().join( QStringLiteral(
"\n" ) ) );
852 QList<QgsMapLayer *>() << newLayer );
855 copySymbology( layer, newLayer );
858 const auto fields = layer->
fields();
859 for (
const QgsField &field : fields )
870 if ( layerTreeLayer )
873 if ( parentTreeGroup )
875 int index = parentTreeGroup->
children().indexOf( layerTreeLayer );
878 if ( newLayerTreeLayer )
892 updateRelations( layer, newLayer );
893 updateMapThemes( layer, newLayer );
894 updateLayerOrder( layer, newLayer );
902 void QgsOfflineEditing::applyAttributesAdded(
QgsVectorLayer *remoteLayer,
sqlite3 *db,
int layerId,
int commitNo )
904 QString sql = QStringLiteral(
"SELECT \"name\", \"type\", \"length\", \"precision\", \"comment\" FROM 'log_added_attrs' WHERE \"layer_id\" = %1 AND \"commit_no\" = %2" ).arg( layerId ).arg( commitNo );
905 QList<QgsField> fields = sqlQueryAttributesAdded( db, sql );
908 QList<QgsVectorDataProvider::NativeType> nativeTypes = provider->
nativeTypes();
911 QMap < QVariant::Type, QString > typeNameLookup;
912 for (
int i = 0; i < nativeTypes.size(); i++ )
920 for (
int i = 0; i < fields.size(); i++ )
924 if ( typeNameLookup.contains( field.
type() ) )
932 showWarning( QStringLiteral(
"Could not add attribute '%1' of type %2" ).arg( field.
name() ).arg( field.
type() ) );
941 QString sql = QStringLiteral(
"SELECT \"fid\" FROM 'log_added_features' WHERE \"layer_id\" = %1" ).arg( layerId );
942 const QList<int> featureIdInts = sqlQueryInts( db, sql );
944 for (
int id : featureIdInts )
965 for ( QgsFeatureList::iterator it = features.begin(); it != features.end(); ++it )
969 QMap<int, int> attrLookup = attributeLookup( offlineLayer, remoteLayer );
972 for (
int it = 0; it < attrs.count(); ++it )
974 newAttrs[ attrLookup[ it ] ] = attrs.at( it );
985 void QgsOfflineEditing::applyFeaturesRemoved(
QgsVectorLayer *remoteLayer,
sqlite3 *db,
int layerId )
987 QString sql = QStringLiteral(
"SELECT \"fid\" FROM 'log_removed_features' WHERE \"layer_id\" = %1" ).arg( layerId );
993 for ( QgsFeatureIds::const_iterator it = values.constBegin(); it != values.constEnd(); ++it )
1004 QString sql = QStringLiteral(
"SELECT \"fid\", \"attr\", \"value\" FROM 'log_feature_updates' WHERE \"layer_id\" = %1 AND \"commit_no\" = %2 " ).arg( layerId ).arg( commitNo );
1005 AttributeValueChanges values = sqlQueryAttributeValueChanges( db, sql );
1009 QMap<int, int> attrLookup = attributeLookup( offlineLayer, remoteLayer );
1011 for (
int i = 0; i < values.size(); i++ )
1013 QgsFeatureId fid = remoteFid( db, layerId, values.at( i ).fid );
1014 QgsDebugMsgLevel( QStringLiteral(
"Offline changeAttributeValue %1 = %2" ).arg( QString( attrLookup[ values.at( i ).attr ] ), values.at( i ).value ), 4 );
1015 remoteLayer->
changeAttributeValue( fid, attrLookup[ values.at( i ).attr ], values.at( i ).value );
1021 void QgsOfflineEditing::applyGeometryChanges(
QgsVectorLayer *remoteLayer,
sqlite3 *db,
int layerId,
int commitNo )
1023 QString sql = QStringLiteral(
"SELECT \"fid\", \"geom_wkt\" FROM 'log_geometry_updates' WHERE \"layer_id\" = %1 AND \"commit_no\" = %2" ).arg( layerId ).arg( commitNo );
1024 GeometryChanges values = sqlQueryGeometryChanges( db, sql );
1028 for (
int i = 0; i < values.size(); i++ )
1030 QgsFeatureId fid = remoteFid( db, layerId, values.at( i ).fid );
1054 if ( offlineFid( db, layerId, f.
id() ) == -1 )
1056 newRemoteFids[ f.
id()] =
true;
1064 QString sql = QStringLiteral(
"SELECT \"fid\" FROM 'log_added_features' WHERE \"layer_id\" = %1" ).arg( layerId );
1065 QList<int> newOfflineFids = sqlQueryInts( db, sql );
1067 if ( newRemoteFids.size() != newOfflineFids.size() )
1075 sqlExec( db, QStringLiteral(
"BEGIN" ) );
1076 for ( QMap<QgsFeatureId, bool>::const_iterator it = newRemoteFids.constBegin(); it != newRemoteFids.constEnd(); ++it )
1078 addFidLookup( db, layerId, newOfflineFids.at( i++ ), it.key() );
1080 sqlExec( db, QStringLiteral(
"COMMIT" ) );
1092 if ( error.isEmpty() )
1096 if ( !error.isEmpty() )
1098 showWarning( error );
1105 const QList<QgsRelation> referencedRelations = relationManager->
referencedRelations( sourceLayer );
1107 for (
QgsRelation relation : referencedRelations )
1110 relation.setReferencedLayer( targetLayer->
id() );
1114 const QList<QgsRelation> referencingRelations = relationManager->
referencingRelations( sourceLayer );
1116 for (
QgsRelation relation : referencingRelations )
1119 relation.setReferencingLayer( targetLayer->
id() );
1127 const QStringList mapThemeNames = mapThemeCollection->
mapThemes();
1129 for (
const QString &mapThemeName : mapThemeNames )
1137 if ( layerRecord.layer() == sourceLayer )
1139 layerRecord.setLayer( targetLayer );
1153 auto iterator = layerOrder.begin();
1155 while ( iterator != layerOrder.end() )
1157 if ( *iterator == targetLayer )
1159 iterator = layerOrder.erase( iterator );
1160 if ( iterator == layerOrder.end() )
1164 if ( *iterator == sourceLayer )
1166 *iterator = targetLayer;
1180 QMap <
int ,
int > attrLookup;
1183 for (
int i = 0; i < offlineAttrs.size(); i++ )
1192 void QgsOfflineEditing::showWarning(
const QString &message )
1194 emit
warning( tr(
"Offline Editing Plugin" ), message );
1201 if ( !dbPath.isEmpty() )
1204 int rc = database.
open( absoluteDbPath );
1205 if ( rc != SQLITE_OK )
1207 QgsDebugMsg( QStringLiteral(
"Could not open the SpatiaLite logging database" ) );
1208 showWarning( tr(
"Could not open the SpatiaLite logging database" ) );
1213 QgsDebugMsg( QStringLiteral(
"dbPath is empty!" ) );
1218 int QgsOfflineEditing::getOrCreateLayerId(
sqlite3 *db,
const QString &qgisLayerId )
1220 QString sql = QStringLiteral(
"SELECT \"id\" FROM 'log_layer_ids' WHERE \"qgis_id\" = '%1'" ).arg( qgisLayerId );
1221 int layerId = sqlQueryInt( db, sql, -1 );
1222 if ( layerId == -1 )
1225 sql = QStringLiteral(
"SELECT \"last_index\" FROM 'log_indices' WHERE \"name\" = 'layer_id'" );
1226 int newLayerId = sqlQueryInt( db, sql, -1 );
1229 sql = QStringLiteral(
"INSERT INTO 'log_layer_ids' VALUES (%1, '%2')" ).arg( newLayerId ).arg( qgisLayerId );
1234 sql = QStringLiteral(
"UPDATE 'log_indices' SET 'last_index' = %1 WHERE \"name\" = 'layer_id'" ).arg( newLayerId + 1 );
1237 layerId = newLayerId;
1243 int QgsOfflineEditing::getCommitNo(
sqlite3 *db )
1245 QString sql = QStringLiteral(
"SELECT \"last_index\" FROM 'log_indices' WHERE \"name\" = 'commit_no'" );
1246 return sqlQueryInt( db, sql, -1 );
1249 void QgsOfflineEditing::increaseCommitNo(
sqlite3 *db )
1251 QString sql = QStringLiteral(
"UPDATE 'log_indices' SET 'last_index' = %1 WHERE \"name\" = 'commit_no'" ).arg( getCommitNo( db ) + 1 );
1257 QString sql = QStringLiteral(
"INSERT INTO 'log_fids' VALUES ( %1, %2, %3 )" ).arg( layerId ).arg( offlineFid ).arg( remoteFid );
1263 QString sql = QStringLiteral(
"SELECT \"remote_fid\" FROM 'log_fids' WHERE \"layer_id\" = %1 AND \"offline_fid\" = %2" ).arg( layerId ).arg( offlineFid );
1264 return sqlQueryInt( db, sql, -1 );
1269 QString sql = QStringLiteral(
"SELECT \"offline_fid\" FROM 'log_fids' WHERE \"layer_id\" = %1 AND \"remote_fid\" = %2" ).arg( layerId ).arg( remoteFid );
1270 return sqlQueryInt( db, sql, -1 );
1275 QString sql = QStringLiteral(
"SELECT COUNT(\"fid\") FROM 'log_added_features' WHERE \"layer_id\" = %1 AND \"fid\" = %2" ).arg( layerId ).arg( fid );
1276 return ( sqlQueryInt( db, sql, 0 ) > 0 );
1279 int QgsOfflineEditing::sqlExec(
sqlite3 *db,
const QString &sql )
1281 char *errmsg =
nullptr;
1282 int rc = sqlite3_exec( db, sql.toUtf8(),
nullptr,
nullptr, &errmsg );
1283 if ( rc != SQLITE_OK )
1285 showWarning( errmsg );
1290 int QgsOfflineEditing::sqlQueryInt(
sqlite3 *db,
const QString &sql,
int defaultValue )
1292 sqlite3_stmt *stmt =
nullptr;
1293 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1295 showWarning( sqlite3_errmsg( db ) );
1296 return defaultValue;
1299 int value = defaultValue;
1300 int ret = sqlite3_step( stmt );
1301 if ( ret == SQLITE_ROW )
1303 value = sqlite3_column_int( stmt, 0 );
1305 sqlite3_finalize( stmt );
1310 QList<int> QgsOfflineEditing::sqlQueryInts(
sqlite3 *db,
const QString &sql )
1314 sqlite3_stmt *stmt =
nullptr;
1315 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1317 showWarning( sqlite3_errmsg( db ) );
1321 int ret = sqlite3_step( stmt );
1322 while ( ret == SQLITE_ROW )
1324 values << sqlite3_column_int( stmt, 0 );
1326 ret = sqlite3_step( stmt );
1328 sqlite3_finalize( stmt );
1333 QList<QgsField> QgsOfflineEditing::sqlQueryAttributesAdded(
sqlite3 *db,
const QString &sql )
1335 QList<QgsField> values;
1337 sqlite3_stmt *stmt =
nullptr;
1338 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1340 showWarning( sqlite3_errmsg( db ) );
1344 int ret = sqlite3_step( stmt );
1345 while ( ret == SQLITE_ROW )
1347 QgsField field( QString( reinterpret_cast< const char * >( sqlite3_column_text( stmt, 0 ) ) ),
1348 static_cast< QVariant::Type >( sqlite3_column_int( stmt, 1 ) ),
1350 sqlite3_column_int( stmt, 2 ),
1351 sqlite3_column_int( stmt, 3 ),
1352 QString( reinterpret_cast< const char * >( sqlite3_column_text( stmt, 4 ) ) ) );
1355 ret = sqlite3_step( stmt );
1357 sqlite3_finalize( stmt );
1366 sqlite3_stmt *stmt =
nullptr;
1367 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1369 showWarning( sqlite3_errmsg( db ) );
1373 int ret = sqlite3_step( stmt );
1374 while ( ret == SQLITE_ROW )
1376 values << sqlite3_column_int( stmt, 0 );
1378 ret = sqlite3_step( stmt );
1380 sqlite3_finalize( stmt );
1385 QgsOfflineEditing::AttributeValueChanges QgsOfflineEditing::sqlQueryAttributeValueChanges(
sqlite3 *db,
const QString &sql )
1387 AttributeValueChanges values;
1389 sqlite3_stmt *stmt =
nullptr;
1390 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1392 showWarning( sqlite3_errmsg( db ) );
1396 int ret = sqlite3_step( stmt );
1397 while ( ret == SQLITE_ROW )
1399 AttributeValueChange change;
1400 change.fid = sqlite3_column_int( stmt, 0 );
1401 change.attr = sqlite3_column_int( stmt, 1 );
1402 change.value = QString( reinterpret_cast< const char * >( sqlite3_column_text( stmt, 2 ) ) );
1405 ret = sqlite3_step( stmt );
1407 sqlite3_finalize( stmt );
1412 QgsOfflineEditing::GeometryChanges QgsOfflineEditing::sqlQueryGeometryChanges(
sqlite3 *db,
const QString &sql )
1414 GeometryChanges values;
1416 sqlite3_stmt *stmt =
nullptr;
1417 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1419 showWarning( sqlite3_errmsg( db ) );
1423 int ret = sqlite3_step( stmt );
1424 while ( ret == SQLITE_ROW )
1426 GeometryChange change;
1427 change.fid = sqlite3_column_int( stmt, 0 );
1428 change.geom_wkt = QString( reinterpret_cast< const char * >( sqlite3_column_text( stmt, 1 ) ) );
1431 ret = sqlite3_step( stmt );
1433 sqlite3_finalize( stmt );
1438 void QgsOfflineEditing::committedAttributesAdded(
const QString &qgisLayerId,
const QList<QgsField> &addedAttributes )
1445 int layerId = getOrCreateLayerId( database.get(), qgisLayerId );
1446 int commitNo = getCommitNo( database.get() );
1448 for ( QList<QgsField>::const_iterator it = addedAttributes.begin(); it != addedAttributes.end(); ++it )
1451 QString sql = QStringLiteral(
"INSERT INTO 'log_added_attrs' VALUES ( %1, %2, '%3', %4, %5, %6, '%7' )" )
1454 .arg( field.
name() )
1455 .arg( field.
type() )
1459 sqlExec( database.get(), sql );
1462 increaseCommitNo( database.get() );
1465 void QgsOfflineEditing::committedFeaturesAdded(
const QString &qgisLayerId,
const QgsFeatureList &addedFeatures )
1472 int layerId = getOrCreateLayerId( database.get(), qgisLayerId );
1481 if ( !offlinePath.contains(
".gpkg" ) )
1483 tableName = uri.
table();
1487 tableName = uri.
param( offlinePath +
"|layername" );
1491 QString sql = QStringLiteral(
"SELECT ROWID FROM '%1' ORDER BY ROWID DESC LIMIT %2" ).arg( tableName ).arg( addedFeatures.size() );
1492 QList<int> newFeatureIds = sqlQueryInts( database.get(), sql );
1493 for (
int i = newFeatureIds.size() - 1; i >= 0; i-- )
1495 QString sql = QStringLiteral(
"INSERT INTO 'log_added_features' VALUES ( %1, %2 )" )
1497 .arg( newFeatureIds.at( i ) );
1498 sqlExec( database.get(), sql );
1502 void QgsOfflineEditing::committedFeaturesRemoved(
const QString &qgisLayerId,
const QgsFeatureIds &deletedFeatureIds )
1509 int layerId = getOrCreateLayerId( database.get(), qgisLayerId );
1511 for ( QgsFeatureIds::const_iterator it = deletedFeatureIds.begin(); it != deletedFeatureIds.end(); ++it )
1513 if ( isAddedFeature( database.get(), layerId, *it ) )
1516 QString sql = QStringLiteral(
"DELETE FROM 'log_added_features' WHERE \"layer_id\" = %1 AND \"fid\" = %2" ).arg( layerId ).arg( *it );
1517 sqlExec( database.get(), sql );
1521 QString sql = QStringLiteral(
"INSERT INTO 'log_removed_features' VALUES ( %1, %2)" )
1524 sqlExec( database.get(), sql );
1529 void QgsOfflineEditing::committedAttributeValuesChanges(
const QString &qgisLayerId,
const QgsChangedAttributesMap &changedAttrsMap )
1536 int layerId = getOrCreateLayerId( database.get(), qgisLayerId );
1537 int commitNo = getCommitNo( database.get() );
1539 for ( QgsChangedAttributesMap::const_iterator cit = changedAttrsMap.begin(); cit != changedAttrsMap.end(); ++cit )
1542 if ( isAddedFeature( database.get(), layerId, fid ) )
1548 for ( QgsAttributeMap::const_iterator it = attrMap.constBegin(); it != attrMap.constEnd(); ++it )
1550 QString sql = QStringLiteral(
"INSERT INTO 'log_feature_updates' VALUES ( %1, %2, %3, %4, '%5' )" )
1555 .arg( it.value().toString() );
1556 sqlExec( database.get(), sql );
1560 increaseCommitNo( database.get() );
1563 void QgsOfflineEditing::committedGeometriesChanges(
const QString &qgisLayerId,
const QgsGeometryMap &changedGeometries )
1570 int layerId = getOrCreateLayerId( database.get(), qgisLayerId );
1571 int commitNo = getCommitNo( database.get() );
1573 for ( QgsGeometryMap::const_iterator it = changedGeometries.begin(); it != changedGeometries.end(); ++it )
1576 if ( isAddedFeature( database.get(), layerId, fid ) )
1582 QString sql = QStringLiteral(
"INSERT INTO 'log_geometry_updates' VALUES ( %1, %2, %3, '%4' )" )
1586 .arg( geom.
asWkt() );
1587 sqlExec( database.get(), sql );
1592 increaseCommitNo( database.get() );
1595 void QgsOfflineEditing::startListenFeatureChanges()
1603 this, &QgsOfflineEditing::committedAttributesAdded );
1605 this, &QgsOfflineEditing::committedAttributeValuesChanges );
1607 this, &QgsOfflineEditing::committedGeometriesChanges );
1610 this, &QgsOfflineEditing::committedFeaturesAdded );
1612 this, &QgsOfflineEditing::committedFeaturesRemoved );
1615 void QgsOfflineEditing::stopListenFeatureChanges()
1623 this, &QgsOfflineEditing::committedAttributesAdded );
1625 this, &QgsOfflineEditing::committedAttributeValuesChanges );
1627 this, &QgsOfflineEditing::committedGeometriesChanges );
1630 this, &QgsOfflineEditing::committedFeaturesAdded );
1632 this, &QgsOfflineEditing::committedFeaturesRemoved );
1635 void QgsOfflineEditing::layerAdded(
QgsMapLayer *layer )
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
QString param(const QString &key) const
Returns a generic parameter value corresponding to the specified key.
Layer tree group node serves as a container for layers and further groups.
The class is used as a container of context for various read/write operations on other objects...
Wrapper for iterator of features from vector data provider or vector layer.
QMap< QgsFeatureId, QgsGeometry > QgsGeometryMap
void layerProgressUpdated(int layer, int numLayers)
Emitted whenever a new layer is being processed.
int open(const QString &path)
Opens the database at the specified file path.
bool addJoin(const QgsVectorLayerJoinInfo &joinInfo)
Joins another vector layer to this layer.
int open_v2(const QString &path, int flags, const char *zVfs)
Opens the database at the specified file path.
QList< QgsMapLayer * > addMapLayers(const QList< QgsMapLayer *> &mapLayers, bool addToLegend=true, bool takeOwnership=true)
Add a list of layers to the map of loaded layers.
Base class for all map layer types.
QString table() const
Returns the table name stored in the URI.
Filter using feature IDs.
QSet< QgsFeatureId > QgsFeatureIds
QString readEntry(const QString &scope, const QString &key, const QString &def=QString(), bool *ok=nullptr) const
void removeFieldConstraint(int index, QgsFieldConstraints::Constraint constraint)
Removes a constraint for a specified field index.
virtual bool importNamedStyle(QDomDocument &doc, QString &errorMsg, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Import the properties of this layer from a QDomDocument.
#define PROJECT_ENTRY_KEY_OFFLINE_DB_PATH
void setSnappingConfig(const QgsSnappingConfig &snappingConfig)
The snapping configuration for this project.
QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
Setting options for loading vector layers.
bool deleteFeature(QgsFeatureId fid)
Deletes a feature from the layer (but does not commit it).
void committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)
QList< QgsRelation > referencingRelations(const QgsVectorLayer *layer=nullptr, int fieldIdx=-2) const
Gets all relations where the specified layer (and field) is the referencing part (i.e.
QgsMapThemeCollection::MapThemeRecord mapThemeState(const QString &name) const
Returns the recorded state of a map theme.
QList< QgsFeature > QgsFeatureList
#define CUSTOM_PROPERTY_IS_OFFLINE_EDITABLE
Individual map theme record of visible layers and styles.
bool commitChanges()
Attempts to commit to the underlying data provider any buffered changes made since the last to call t...
QString providerType() const
Returns the provider type (provider key) for this layer.
void update(const QString &name, const QgsMapThemeCollection::MapThemeRecord &state)
Updates a map theme within the collection.
bool startEditing()
Makes the layer editable.
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
#define CUSTOM_PROPERTY_REMOTE_SOURCE
FilterType filterType() const
Returns the filter type which is currently set on this request.
Container of fields for a vector layer.
A geometry is the spatial representation of a feature.
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
void removeChildNode(QgsLayerTreeNode *node)
Remove a child node from this group.
bool isVisible() const
Returns whether a node is really visible (ie checked and all its ancestors checked as well) ...
Individual record of a visible layer in a map theme record.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
QList< QgsVectorDataProvider::NativeType > nativeTypes() const
Returns the names of the supported types.
bool isValid() const
Returns the status of the layer.
bool isOfflineProject() const
Returns true if current project is offline.
void committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)
Emitted when features are deleted from the provider.
int count() const
Returns number of items.
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
QList< QgsMapLayer * > customLayerOrder() const
The order in which layers will be rendered on the canvas.
void setIndividualLayerSettings(QgsVectorLayer *vl, const QgsSnappingConfig::IndividualLayerSettings &individualLayerSettings)
Sets individual layer snappings settings (applied if mode is AdvancedConfiguration) ...
void removeLayerRecord(QgsMapLayer *layer)
Removes a record for layer if present.
int fieldOriginIndex(int fieldIdx) const
Gets field's origin index (its meaning is specific to each type of origin)
bool writeEntry(const QString &scope, const QString &key, bool value)
Write a boolean entry to the project file.
void progressUpdated(int progress)
Emitted with the progress of the current mode.
void committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)
QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on...
Type
The WKB type describes the number of dimensions a geometry has.
const QList< QgsVectorLayerJoinInfo > vectorJoins() const
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QgsMapThemeCollection mapThemeCollection
void progressStopped()
Emitted when the processing of all layers has finished.
const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
bool changeGeometry(QgsFeatureId fid, QgsGeometry &geometry, bool skipDefaultValue=false)
Changes a feature's geometry within the layer's edit buffer (but does not immediately commit the chan...
Unique pointer for spatialite databases, which automatically closes the database when the pointer goe...
#define QgsDebugMsgLevel(str, level)
void reload() FINAL
Synchronises with changes in the datasource.
QString dataComment() const
Returns a description for this layer as defined in the data provider.
QgsFields fields() const override=0
Returns the fields associated with this data provider.
long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
void setTypeName(const QString &typeName)
Set the field type.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsLayerTreeNode * parent()
Gets pointer to the parent. If parent is nullptr, the node is a root node.
void committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)
Emitted when features are added to the provider.
static QgsFeature createFeature(const QgsVectorLayer *layer, const QgsGeometry &geometry=QgsGeometry(), const QgsAttributeMap &attributes=QgsAttributeMap(), QgsExpressionContext *context=nullptr)
Creates a new feature ready for insertion into a layer.
Defines left outer join from our vector layer to some other vector layer.
QMap< int, QVariant > QgsAttributeMap
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer. Properties are stored in a map and saved in project file...
This class wraps a request for features to a vector layer (or directly its vector data provider)...
virtual QString defaultValueClause(int fieldIndex) const
Returns any default value clauses which are present at the provider for a specified field index...
This class is a base class for nodes in a layer tree.
ContainerType
Type of offline database container file.
bool removeEntry(const QString &scope, const QString &key)
Remove the given key.
QgsAttributeMap toMap() const
Returns a QgsAttributeMap of the attribute values.
QgsAttributeList attributeList() const
Returns list of attribute indexes.
QList< QgsRelation > referencedRelations(QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
Encapsulate a field in an attribute table or data source.
QgsRelationManager relationManager
void editingStarted()
Emitted when editing on this layer has started.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
int open(const QString &path)
Opens the database at the specified file path.
QMap< QString, QgsMapLayer * > mapLayers(const bool validOnly=false) const
Returns a map of all registered layers by layer ID.
#define PROJECT_ENTRY_SCOPE_OFFLINE
bool removeLayers(const QList< QgsMapLayer *> &layers)
Removes the specified layers from the individual layer configuration.
virtual void exportNamedStyle(QDomDocument &doc, QString &errorMsg, const QgsReadWriteContext &context=QgsReadWriteContext(), QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const
Export the properties of this layer as named style in a QDomDocument.
QString asWkt(int precision=17) const
Exports the geometry to WKT.
QStringList commitErrors() const
Returns a list containing any error messages generated when attempting to commit changes to the layer...
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
QgsLayerTree * layerTreeRoot() const
Returns pointer to the root (invisible) node of the project's layer tree.
QgsCoordinateTransformContext transformContext
#define CUSTOM_SHOW_FEATURE_COUNT
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
bool convertToOfflineProject(const QString &offlineDataPath, const QString &offlineDbFile, const QStringList &layerIds, bool onlySelected=false, ContainerType containerType=SpatiaLite)
Convert current project for offline editing.
void warning(const QString &title, const QString &message)
Emitted when a warning needs to be displayed.
Custom properties (by plugins for instance)
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
void setCustomLayerOrder(const QList< QgsMapLayer *> &customLayerOrder)
The order in which layers will be rendered on the canvas.
void insertChildNode(int index, QgsLayerTreeNode *node)
Insert existing node at specified position.
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override=0
Query the provider for features specified in request.
QString source() const
Returns the source for the layer.
long featureCount() const override=0
Number of features in the layer.
QList< QgsMapThemeCollection::MapThemeLayerRecord > layerRecords() const
Returns a list of records for all visible layer belonging to the theme.
void synchronize()
Synchronize to remote layers.
This class manages a set of relations between layers.
void committedAttributeValuesChanges(const QString &layerId, const QgsChangedAttributesMap &changedAttributesValues)
static QgsProject * instance()
Returns the QgsProject singleton instance.
std::unique_ptr< std::remove_pointer< OGRFieldDefnH >::type, OGRFldDeleter > ogr_field_def_unique_ptr
Scoped OGR field definition.
void setTitle(const QString &title)
Sets the project's title.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=nullptr) FINAL
Adds a single feature to the sink.
static QString displayString(Type type)
Returns a display string type for a WKB type, e.g., the geometry name used in WKT geometry representa...
void progressModeSet(QgsOfflineEditing::ProgressMode mode, int maximum)
Emitted when the mode for the progress of the current operation is set.
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
void setItemVisibilityChecked(bool checked)
Check or uncheck a node (independently of its ancestors or children)
void removeMapLayers(const QStringList &layerIds)
Remove a set of layers from the registry by layer ID.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
static bool hasM(Type type)
Tests whether a WKB type contains m values.
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false)
Changes an attribute value for a feature (but does not immediately commit the changes).
void removeRelation(const QString &id)
Remove a relation.
Container class that allows storage of map themes consisting of visible map layers and layer styles...
QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QString title() const
Returns the project's title.
This is a container for configuration of the snapping of the project.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
QList< int > QgsAttributeList
QgsLayerTreeLayer * findLayer(QgsMapLayer *layer) const
Find layer node representing the map layer.
QList< QgsVectorLayerJoinInfo > QgsVectorJoinList
bool nextFeature(QgsFeature &f)
This is the base class for vector data providers.
std::unique_ptr< std::remove_pointer< OGRDataSourceH >::type, OGRDataSourceDeleter > ogr_datasource_unique_ptr
Scoped OGR data source.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Class for storing the component parts of a RDBMS data source URI (e.g.
virtual void invalidateConnections(const QString &connection)
Invalidate connections corresponding to specified name.
QHash< QgsVectorLayer *, QgsSnappingConfig::IndividualLayerSettings > individualLayerSettings() const
Returns individual snapping settings for all layers.
Represents a vector layer which manages a vector based data sets.
bool addAttribute(const QgsField &field)
Add an attribute field (but does not commit it) returns true if the field was added.
static Type flatType(Type type)
Returns the flat type for a WKB type.
QgsSnappingConfig snappingConfig
#define CUSTOM_PROPERTY_REMOTE_PROVIDER
void progressStarted()
Emitted when the process has started.
QgsField field(int fieldIdx) const
Gets field at particular index (must be in range 0..N-1)
QgsLayerTreeLayer * clone() const override
Create a copy of the node. Returns new instance.
void addLayerRecord(const QgsMapThemeCollection::MapThemeLayerRecord &record)
Add a new record for a layer.
QString authid() const
Returns the authority identifier for the CRS.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
QgsCoordinateReferenceSystem crs
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
void * OGRSpatialReferenceH
void layerWasAdded(QgsMapLayer *layer)
Emitted when a layer was added to the registry.
void setCustomProperty(const QString &key, const QVariant &value)
Sets a custom property for the node. Properties are stored in a map and saved in project file...
Layer tree node points to a map layer.
void addRelation(const QgsRelation &relation)
Add a relation.
QString errorMessage() const
Returns the most recent error message encountered by the database.