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 OGRFieldSubType ogrSubType = OFSTNone;
709 if ( type == QVariant::Int )
710 ogrType = OFTInteger;
711 else if ( type == QVariant::LongLong )
712 ogrType = OFTInteger64;
713 else if ( type == QVariant::Double )
715 else if ( type == QVariant::Time )
717 else if ( type == QVariant::Date )
719 else if ( type == QVariant::DateTime )
720 ogrType = OFTDateTime;
721 else if ( type == QVariant::Bool )
723 ogrType = OFTInteger;
724 ogrSubType = OFSTBoolean;
729 int ogrWidth = field.length();
732 OGR_Fld_SetWidth( fld.get(), ogrWidth );
733 if ( ogrSubType != OFSTNone )
734 OGR_Fld_SetSubType( fld.get(), ogrSubType );
736 if ( OGR_L_CreateField( hLayer, fld.get(), true ) != OGRERR_NONE )
738 showWarning( tr(
"Creation of field %1 failed (OGR error: %2)" )
739 .arg( fieldName, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
747 OGR_L_ResetReading( hLayer );
748 if ( CPLGetLastErrorType() != CE_None )
750 QString msg( tr(
"Creation of layer failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
756 QString uri = QStringLiteral(
"%1|layername=%2" ).arg( offlineDbPath, tableName );
758 newLayer =
new QgsVectorLayer( uri, layer->
name() +
" (offline)", QStringLiteral(
"ogr" ), layerOptions );
775 if ( !selectedFids.isEmpty() )
789 int featureCount = 1;
791 QList<QgsFeatureId> remoteFeatureIds;
794 remoteFeatureIds << f.
id();
801 QgsAttributes newAttrs( containerType ==
GPKG ? attrs.count() + 1 : attrs.count() );
802 for (
int it = 0; it < attrs.count(); ++it )
804 newAttrs[column++] = attrs.at( it );
818 int layerId = getOrCreateLayerId( db, newLayer->
id() );
819 QList<QgsFeatureId> offlineFeatureIds;
824 offlineFeatureIds << f.
id();
828 sqlExec( db, QStringLiteral(
"BEGIN" ) );
829 int remoteCount = remoteFeatureIds.size();
830 for (
int i = 0; i < remoteCount; i++ )
833 if ( i < offlineFeatureIds.count() )
835 addFidLookup( db, layerId, offlineFeatureIds.at( i ), remoteFeatureIds.at( i ) );
839 showWarning( tr(
"Feature cannot be copied to the offline layer, please check if the online layer '%1' is still accessible." ).arg( layer->
name() ) );
844 sqlExec( db, QStringLiteral(
"COMMIT" ) );
848 showWarning( newLayer->
commitErrors().join( QStringLiteral(
"\n" ) ) );
860 QList<QgsMapLayer *>() << newLayer );
863 copySymbology( layer, newLayer );
866 const auto fields = layer->
fields();
867 for (
const QgsField &field : fields )
878 if ( layerTreeLayer )
881 if ( parentTreeGroup )
883 int index = parentTreeGroup->
children().indexOf( layerTreeLayer );
886 if ( newLayerTreeLayer )
900 updateRelations( layer, newLayer );
901 updateMapThemes( layer, newLayer );
902 updateLayerOrder( layer, newLayer );
910 void QgsOfflineEditing::applyAttributesAdded(
QgsVectorLayer *remoteLayer,
sqlite3 *db,
int layerId,
int commitNo )
912 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 );
913 QList<QgsField> fields = sqlQueryAttributesAdded( db, sql );
916 QList<QgsVectorDataProvider::NativeType> nativeTypes = provider->
nativeTypes();
919 QMap < QVariant::Type, QString > typeNameLookup;
920 for (
int i = 0; i < nativeTypes.size(); i++ )
928 for (
int i = 0; i < fields.size(); i++ )
932 if ( typeNameLookup.contains( field.
type() ) )
940 showWarning( QStringLiteral(
"Could not add attribute '%1' of type %2" ).arg( field.
name() ).arg( field.
type() ) );
949 QString sql = QStringLiteral(
"SELECT \"fid\" FROM 'log_added_features' WHERE \"layer_id\" = %1" ).arg( layerId );
950 const QList<int> featureIdInts = sqlQueryInts( db, sql );
952 for (
int id : featureIdInts )
973 for ( QgsFeatureList::iterator it = features.begin(); it != features.end(); ++it )
977 QMap<int, int> attrLookup = attributeLookup( offlineLayer, remoteLayer );
980 for (
int it = 0; it < attrs.count(); ++it )
982 newAttrs[ attrLookup[ it ] ] = attrs.at( it );
993 void QgsOfflineEditing::applyFeaturesRemoved(
QgsVectorLayer *remoteLayer,
sqlite3 *db,
int layerId )
995 QString sql = QStringLiteral(
"SELECT \"fid\" FROM 'log_removed_features' WHERE \"layer_id\" = %1" ).arg( layerId );
1001 for ( QgsFeatureIds::const_iterator it = values.constBegin(); it != values.constEnd(); ++it )
1012 QString sql = QStringLiteral(
"SELECT \"fid\", \"attr\", \"value\" FROM 'log_feature_updates' WHERE \"layer_id\" = %1 AND \"commit_no\" = %2 " ).arg( layerId ).arg( commitNo );
1013 AttributeValueChanges values = sqlQueryAttributeValueChanges( db, sql );
1017 QMap<int, int> attrLookup = attributeLookup( offlineLayer, remoteLayer );
1019 for (
int i = 0; i < values.size(); i++ )
1021 QgsFeatureId fid = remoteFid( db, layerId, values.at( i ).fid );
1022 QgsDebugMsgLevel( QStringLiteral(
"Offline changeAttributeValue %1 = %2" ).arg( QString( attrLookup[ values.at( i ).attr ] ), values.at( i ).value ), 4 );
1023 remoteLayer->
changeAttributeValue( fid, attrLookup[ values.at( i ).attr ], values.at( i ).value );
1029 void QgsOfflineEditing::applyGeometryChanges(
QgsVectorLayer *remoteLayer,
sqlite3 *db,
int layerId,
int commitNo )
1031 QString sql = QStringLiteral(
"SELECT \"fid\", \"geom_wkt\" FROM 'log_geometry_updates' WHERE \"layer_id\" = %1 AND \"commit_no\" = %2" ).arg( layerId ).arg( commitNo );
1032 GeometryChanges values = sqlQueryGeometryChanges( db, sql );
1036 for (
int i = 0; i < values.size(); i++ )
1038 QgsFeatureId fid = remoteFid( db, layerId, values.at( i ).fid );
1062 if ( offlineFid( db, layerId, f.
id() ) == -1 )
1064 newRemoteFids[ f.
id()] =
true;
1072 QString sql = QStringLiteral(
"SELECT \"fid\" FROM 'log_added_features' WHERE \"layer_id\" = %1" ).arg( layerId );
1073 QList<int> newOfflineFids = sqlQueryInts( db, sql );
1075 if ( newRemoteFids.size() != newOfflineFids.size() )
1083 sqlExec( db, QStringLiteral(
"BEGIN" ) );
1084 for ( QMap<QgsFeatureId, bool>::const_iterator it = newRemoteFids.constBegin(); it != newRemoteFids.constEnd(); ++it )
1086 addFidLookup( db, layerId, newOfflineFids.at( i++ ), it.key() );
1088 sqlExec( db, QStringLiteral(
"COMMIT" ) );
1100 if ( error.isEmpty() )
1104 if ( !error.isEmpty() )
1106 showWarning( error );
1113 const QList<QgsRelation> referencedRelations = relationManager->
referencedRelations( sourceLayer );
1115 for (
QgsRelation relation : referencedRelations )
1118 relation.setReferencedLayer( targetLayer->
id() );
1122 const QList<QgsRelation> referencingRelations = relationManager->
referencingRelations( sourceLayer );
1124 for (
QgsRelation relation : referencingRelations )
1127 relation.setReferencingLayer( targetLayer->
id() );
1135 const QStringList mapThemeNames = mapThemeCollection->
mapThemes();
1137 for (
const QString &mapThemeName : mapThemeNames )
1145 if ( layerRecord.layer() == sourceLayer )
1147 layerRecord.setLayer( targetLayer );
1161 auto iterator = layerOrder.begin();
1163 while ( iterator != layerOrder.end() )
1165 if ( *iterator == targetLayer )
1167 iterator = layerOrder.erase( iterator );
1168 if ( iterator == layerOrder.end() )
1172 if ( *iterator == sourceLayer )
1174 *iterator = targetLayer;
1188 QMap <
int ,
int > attrLookup;
1191 for (
int i = 0; i < offlineAttrs.size(); i++ )
1200 void QgsOfflineEditing::showWarning(
const QString &message )
1202 emit
warning( tr(
"Offline Editing Plugin" ), message );
1209 if ( !dbPath.isEmpty() )
1212 int rc = database.
open( absoluteDbPath );
1213 if ( rc != SQLITE_OK )
1215 QgsDebugMsg( QStringLiteral(
"Could not open the SpatiaLite logging database" ) );
1216 showWarning( tr(
"Could not open the SpatiaLite logging database" ) );
1221 QgsDebugMsg( QStringLiteral(
"dbPath is empty!" ) );
1226 int QgsOfflineEditing::getOrCreateLayerId(
sqlite3 *db,
const QString &qgisLayerId )
1228 QString sql = QStringLiteral(
"SELECT \"id\" FROM 'log_layer_ids' WHERE \"qgis_id\" = '%1'" ).arg( qgisLayerId );
1229 int layerId = sqlQueryInt( db, sql, -1 );
1230 if ( layerId == -1 )
1233 sql = QStringLiteral(
"SELECT \"last_index\" FROM 'log_indices' WHERE \"name\" = 'layer_id'" );
1234 int newLayerId = sqlQueryInt( db, sql, -1 );
1237 sql = QStringLiteral(
"INSERT INTO 'log_layer_ids' VALUES (%1, '%2')" ).arg( newLayerId ).arg( qgisLayerId );
1242 sql = QStringLiteral(
"UPDATE 'log_indices' SET 'last_index' = %1 WHERE \"name\" = 'layer_id'" ).arg( newLayerId + 1 );
1245 layerId = newLayerId;
1251 int QgsOfflineEditing::getCommitNo(
sqlite3 *db )
1253 QString sql = QStringLiteral(
"SELECT \"last_index\" FROM 'log_indices' WHERE \"name\" = 'commit_no'" );
1254 return sqlQueryInt( db, sql, -1 );
1257 void QgsOfflineEditing::increaseCommitNo(
sqlite3 *db )
1259 QString sql = QStringLiteral(
"UPDATE 'log_indices' SET 'last_index' = %1 WHERE \"name\" = 'commit_no'" ).arg( getCommitNo( db ) + 1 );
1265 QString sql = QStringLiteral(
"INSERT INTO 'log_fids' VALUES ( %1, %2, %3 )" ).arg( layerId ).arg( offlineFid ).arg( remoteFid );
1271 QString sql = QStringLiteral(
"SELECT \"remote_fid\" FROM 'log_fids' WHERE \"layer_id\" = %1 AND \"offline_fid\" = %2" ).arg( layerId ).arg( offlineFid );
1272 return sqlQueryInt( db, sql, -1 );
1277 QString sql = QStringLiteral(
"SELECT \"offline_fid\" FROM 'log_fids' WHERE \"layer_id\" = %1 AND \"remote_fid\" = %2" ).arg( layerId ).arg( remoteFid );
1278 return sqlQueryInt( db, sql, -1 );
1283 QString sql = QStringLiteral(
"SELECT COUNT(\"fid\") FROM 'log_added_features' WHERE \"layer_id\" = %1 AND \"fid\" = %2" ).arg( layerId ).arg( fid );
1284 return ( sqlQueryInt( db, sql, 0 ) > 0 );
1287 int QgsOfflineEditing::sqlExec(
sqlite3 *db,
const QString &sql )
1289 char *errmsg =
nullptr;
1290 int rc = sqlite3_exec( db, sql.toUtf8(),
nullptr,
nullptr, &errmsg );
1291 if ( rc != SQLITE_OK )
1293 showWarning( errmsg );
1298 int QgsOfflineEditing::sqlQueryInt(
sqlite3 *db,
const QString &sql,
int defaultValue )
1300 sqlite3_stmt *stmt =
nullptr;
1301 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1303 showWarning( sqlite3_errmsg( db ) );
1304 return defaultValue;
1307 int value = defaultValue;
1308 int ret = sqlite3_step( stmt );
1309 if ( ret == SQLITE_ROW )
1311 value = sqlite3_column_int( stmt, 0 );
1313 sqlite3_finalize( stmt );
1318 QList<int> QgsOfflineEditing::sqlQueryInts(
sqlite3 *db,
const QString &sql )
1322 sqlite3_stmt *stmt =
nullptr;
1323 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1325 showWarning( sqlite3_errmsg( db ) );
1329 int ret = sqlite3_step( stmt );
1330 while ( ret == SQLITE_ROW )
1332 values << sqlite3_column_int( stmt, 0 );
1334 ret = sqlite3_step( stmt );
1336 sqlite3_finalize( stmt );
1341 QList<QgsField> QgsOfflineEditing::sqlQueryAttributesAdded(
sqlite3 *db,
const QString &sql )
1343 QList<QgsField> values;
1345 sqlite3_stmt *stmt =
nullptr;
1346 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1348 showWarning( sqlite3_errmsg( db ) );
1352 int ret = sqlite3_step( stmt );
1353 while ( ret == SQLITE_ROW )
1355 QgsField field( QString( reinterpret_cast< const char * >( sqlite3_column_text( stmt, 0 ) ) ),
1356 static_cast< QVariant::Type >( sqlite3_column_int( stmt, 1 ) ),
1358 sqlite3_column_int( stmt, 2 ),
1359 sqlite3_column_int( stmt, 3 ),
1360 QString( reinterpret_cast< const char * >( sqlite3_column_text( stmt, 4 ) ) ) );
1363 ret = sqlite3_step( stmt );
1365 sqlite3_finalize( stmt );
1374 sqlite3_stmt *stmt =
nullptr;
1375 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1377 showWarning( sqlite3_errmsg( db ) );
1381 int ret = sqlite3_step( stmt );
1382 while ( ret == SQLITE_ROW )
1384 values << sqlite3_column_int( stmt, 0 );
1386 ret = sqlite3_step( stmt );
1388 sqlite3_finalize( stmt );
1393 QgsOfflineEditing::AttributeValueChanges QgsOfflineEditing::sqlQueryAttributeValueChanges(
sqlite3 *db,
const QString &sql )
1395 AttributeValueChanges values;
1397 sqlite3_stmt *stmt =
nullptr;
1398 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1400 showWarning( sqlite3_errmsg( db ) );
1404 int ret = sqlite3_step( stmt );
1405 while ( ret == SQLITE_ROW )
1407 AttributeValueChange change;
1408 change.fid = sqlite3_column_int( stmt, 0 );
1409 change.attr = sqlite3_column_int( stmt, 1 );
1410 change.value = QString( reinterpret_cast< const char * >( sqlite3_column_text( stmt, 2 ) ) );
1413 ret = sqlite3_step( stmt );
1415 sqlite3_finalize( stmt );
1420 QgsOfflineEditing::GeometryChanges QgsOfflineEditing::sqlQueryGeometryChanges(
sqlite3 *db,
const QString &sql )
1422 GeometryChanges values;
1424 sqlite3_stmt *stmt =
nullptr;
1425 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1427 showWarning( sqlite3_errmsg( db ) );
1431 int ret = sqlite3_step( stmt );
1432 while ( ret == SQLITE_ROW )
1434 GeometryChange change;
1435 change.fid = sqlite3_column_int( stmt, 0 );
1436 change.geom_wkt = QString( reinterpret_cast< const char * >( sqlite3_column_text( stmt, 1 ) ) );
1439 ret = sqlite3_step( stmt );
1441 sqlite3_finalize( stmt );
1446 void QgsOfflineEditing::committedAttributesAdded(
const QString &qgisLayerId,
const QList<QgsField> &addedAttributes )
1453 int layerId = getOrCreateLayerId( database.get(), qgisLayerId );
1454 int commitNo = getCommitNo( database.get() );
1456 for ( QList<QgsField>::const_iterator it = addedAttributes.begin(); it != addedAttributes.end(); ++it )
1459 QString sql = QStringLiteral(
"INSERT INTO 'log_added_attrs' VALUES ( %1, %2, '%3', %4, %5, %6, '%7' )" )
1462 .arg( field.
name() )
1463 .arg( field.
type() )
1467 sqlExec( database.get(), sql );
1470 increaseCommitNo( database.get() );
1473 void QgsOfflineEditing::committedFeaturesAdded(
const QString &qgisLayerId,
const QgsFeatureList &addedFeatures )
1480 int layerId = getOrCreateLayerId( database.get(), qgisLayerId );
1489 if ( !offlinePath.contains(
".gpkg" ) )
1491 tableName = uri.
table();
1495 tableName = uri.
param( offlinePath +
"|layername" );
1499 QString sql = QStringLiteral(
"SELECT ROWID FROM '%1' ORDER BY ROWID DESC LIMIT %2" ).arg( tableName ).arg( addedFeatures.size() );
1500 QList<int> newFeatureIds = sqlQueryInts( database.get(), sql );
1501 for (
int i = newFeatureIds.size() - 1; i >= 0; i-- )
1503 QString sql = QStringLiteral(
"INSERT INTO 'log_added_features' VALUES ( %1, %2 )" )
1505 .arg( newFeatureIds.at( i ) );
1506 sqlExec( database.get(), sql );
1510 void QgsOfflineEditing::committedFeaturesRemoved(
const QString &qgisLayerId,
const QgsFeatureIds &deletedFeatureIds )
1517 int layerId = getOrCreateLayerId( database.get(), qgisLayerId );
1519 for ( QgsFeatureIds::const_iterator it = deletedFeatureIds.begin(); it != deletedFeatureIds.end(); ++it )
1521 if ( isAddedFeature( database.get(), layerId, *it ) )
1524 QString sql = QStringLiteral(
"DELETE FROM 'log_added_features' WHERE \"layer_id\" = %1 AND \"fid\" = %2" ).arg( layerId ).arg( *it );
1525 sqlExec( database.get(), sql );
1529 QString sql = QStringLiteral(
"INSERT INTO 'log_removed_features' VALUES ( %1, %2)" )
1532 sqlExec( database.get(), sql );
1537 void QgsOfflineEditing::committedAttributeValuesChanges(
const QString &qgisLayerId,
const QgsChangedAttributesMap &changedAttrsMap )
1544 int layerId = getOrCreateLayerId( database.get(), qgisLayerId );
1545 int commitNo = getCommitNo( database.get() );
1547 for ( QgsChangedAttributesMap::const_iterator cit = changedAttrsMap.begin(); cit != changedAttrsMap.end(); ++cit )
1550 if ( isAddedFeature( database.get(), layerId, fid ) )
1556 for ( QgsAttributeMap::const_iterator it = attrMap.constBegin(); it != attrMap.constEnd(); ++it )
1558 QString sql = QStringLiteral(
"INSERT INTO 'log_feature_updates' VALUES ( %1, %2, %3, %4, '%5' )" )
1563 .arg( it.value().toString() );
1564 sqlExec( database.get(), sql );
1568 increaseCommitNo( database.get() );
1571 void QgsOfflineEditing::committedGeometriesChanges(
const QString &qgisLayerId,
const QgsGeometryMap &changedGeometries )
1578 int layerId = getOrCreateLayerId( database.get(), qgisLayerId );
1579 int commitNo = getCommitNo( database.get() );
1581 for ( QgsGeometryMap::const_iterator it = changedGeometries.begin(); it != changedGeometries.end(); ++it )
1584 if ( isAddedFeature( database.get(), layerId, fid ) )
1590 QString sql = QStringLiteral(
"INSERT INTO 'log_geometry_updates' VALUES ( %1, %2, %3, '%4' )" )
1594 .arg( geom.
asWkt() );
1595 sqlExec( database.get(), sql );
1600 increaseCommitNo( database.get() );
1603 void QgsOfflineEditing::startListenFeatureChanges()
1611 this, &QgsOfflineEditing::committedAttributesAdded );
1613 this, &QgsOfflineEditing::committedAttributeValuesChanges );
1615 this, &QgsOfflineEditing::committedGeometriesChanges );
1618 this, &QgsOfflineEditing::committedFeaturesAdded );
1620 this, &QgsOfflineEditing::committedFeaturesRemoved );
1623 void QgsOfflineEditing::stopListenFeatureChanges()
1631 this, &QgsOfflineEditing::committedAttributesAdded );
1633 this, &QgsOfflineEditing::committedAttributeValuesChanges );
1635 this, &QgsOfflineEditing::committedGeometriesChanges );
1638 this, &QgsOfflineEditing::committedFeaturesAdded );
1640 this, &QgsOfflineEditing::committedFeaturesRemoved );
1643 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.
Q_INVOKABLE 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.
Q_INVOKABLE 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.
Q_INVOKABLE bool startEditing()
Makes the layer editable.
Q_INVOKABLE 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< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
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)
Q_INVOKABLE QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on...
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)
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.
Q_INVOKABLE 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.
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.
Full WKT2 string, conforming to ISO 19162:2018 / OGC 18-010, with all possible nodes and new keyword ...
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...
Q_INVOKABLE 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.