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() )
89 QString dbPath = QDir( offlineDataPath ).absoluteFilePath( offlineDbFile );
90 if ( createOfflineDb( dbPath, containerType ) )
93 int rc = database.
open( dbPath );
94 if ( rc != SQLITE_OK )
96 showWarning( tr(
"Could not open the SpatiaLite database" ) );
101 createLoggingTables( database.get() );
105 QMap<QString, QgsVectorJoinList > joinInfoBuffer;
106 QMap<QString, QgsVectorLayer *> layerIdMapping;
108 for (
const QString &layerId : layerIds )
120 QgsVectorJoinList::iterator joinIt = joins.begin();
121 while ( joinIt != joins.end() )
123 if ( joinIt->prefix().isNull() )
128 joinIt->setPrefix( vl->
name() +
'_' );
132 joinInfoBuffer.insert( vl->
id(), joins );
136 for (
int i = 0; i < layerIds.count(); i++ )
144 QString origLayerId = vl->
id();
145 QgsVectorLayer *newLayer = copyVectorLayer( vl, database.get(), dbPath, onlySelected, containerType );
148 layerIdMapping.insert( origLayerId, newLayer );
151 QStringList() << origLayerId );
157 QMap<QString, QgsVectorJoinList >::ConstIterator it;
158 for ( it = joinInfoBuffer.constBegin(); it != joinInfoBuffer.constEnd(); ++it )
164 const QList<QgsVectorLayerJoinInfo> joins = it.value();
167 QgsVectorLayer *newJoinedLayer = layerIdMapping.value( join.joinLayerId() );
168 if ( newJoinedLayer )
171 join.setJoinLayer( newJoinedLayer );
183 if ( projectTitle.isEmpty() )
187 projectTitle += QLatin1String(
" (offline)" );
216 QList<QgsMapLayer *> offlineLayers;
218 for ( QMap<QString, QgsMapLayer *>::iterator layer_it = mapLayers.begin() ; layer_it != mapLayers.end(); ++layer_it )
223 offlineLayers << layer;
227 QgsDebugMsgLevel( QStringLiteral(
"Found %1 offline layers" ).arg( offlineLayers.count() ), 4 );
228 for (
int l = 0; l < offlineLayers.count(); l++ )
236 QString remoteName = layer->
name();
237 remoteName.remove( QRegExp(
" \\(offline\\)$" ) );
243 if ( remoteLayer->
dataProvider()->
name().contains( QLatin1String(
"WFS" ), Qt::CaseInsensitive ) )
259 copySymbology( offlineLayer, remoteLayer );
260 updateRelations( offlineLayer, remoteLayer );
261 updateMapThemes( offlineLayer, remoteLayer );
262 updateLayerOrder( offlineLayer, remoteLayer );
270 QString qgisLayerId = layer->
id();
271 QString sql = QStringLiteral(
"SELECT \"id\" FROM 'log_layer_ids' WHERE \"qgis_id\" = '%1'" ).arg( qgisLayerId );
272 int layerId = sqlQueryInt( database.get(), sql, -1 );
278 int commitNo = getCommitNo( database.get() );
279 QgsDebugMsgLevel( QStringLiteral(
"Found %1 commits" ).arg( commitNo ), 4 );
280 for (
int i = 0; i < commitNo; i++ )
284 applyAttributesAdded( remoteLayer, database.get(), layerId, i );
285 applyAttributeValueChanges( offlineLayer, remoteLayer, database.get(), layerId, i );
286 applyGeometryChanges( remoteLayer, database.get(), layerId, i );
289 applyFeaturesAdded( offlineLayer, remoteLayer, database.get(), layerId );
290 applyFeaturesRemoved( remoteLayer, database.get(), layerId );
295 updateFidLookup( remoteLayer, database.get(), layerId );
298 sql = QStringLiteral(
"DELETE FROM 'log_added_attrs' WHERE \"layer_id\" = %1" ).arg( layerId );
299 sqlExec( database.get(), sql );
300 sql = QStringLiteral(
"DELETE FROM 'log_added_features' WHERE \"layer_id\" = %1" ).arg( layerId );
301 sqlExec( database.get(), sql );
302 sql = QStringLiteral(
"DELETE FROM 'log_removed_features' WHERE \"layer_id\" = %1" ).arg( layerId );
303 sqlExec( database.get(), sql );
304 sql = QStringLiteral(
"DELETE FROM 'log_feature_updates' WHERE \"layer_id\" = %1" ).arg( layerId );
305 sqlExec( database.get(), sql );
306 sql = QStringLiteral(
"DELETE FROM 'log_geometry_updates' WHERE \"layer_id\" = %1" ).arg( layerId );
307 sqlExec( database.get(), sql );
311 showWarning( remoteLayer->
commitErrors().join( QStringLiteral(
"\n" ) ) );
316 QgsDebugMsg( QStringLiteral(
"Could not find the layer id in the edit logs!" ) );
327 projectTitle.remove( QRegExp(
" \\(offline\\)$" ) );
334 QgsDebugMsg( QStringLiteral(
"Remote layer is not valid!" ) );
339 QString sql = QStringLiteral(
"UPDATE 'log_indices' SET 'last_index' = 0 WHERE \"name\" = 'commit_no'" );
340 sqlExec( database.get(), sql );
345 void QgsOfflineEditing::initializeSpatialMetadata(
sqlite3 *sqlite_handle )
348 if ( !sqlite_handle )
351 char **results =
nullptr;
353 int ret = sqlite3_get_table( sqlite_handle,
"select count(*) from sqlite_master", &results, &rows, &columns,
nullptr );
354 if ( ret != SQLITE_OK )
359 for (
int i = 1; i <= rows; i++ )
360 count = atoi( results[( i * columns ) + 0] );
363 sqlite3_free_table( results );
368 bool above41 =
false;
369 ret = sqlite3_get_table( sqlite_handle,
"select spatialite_version()", &results, &rows, &columns,
nullptr );
370 if ( ret == SQLITE_OK && rows == 1 && columns == 1 )
372 QString version = QString::fromUtf8( results[1] );
373 QStringList parts = version.split(
' ', QString::SkipEmptyParts );
374 if ( !parts.empty() )
376 QStringList verparts = parts.at( 0 ).split(
'.', QString::SkipEmptyParts );
377 above41 = verparts.size() >= 2 && ( verparts.at( 0 ).toInt() > 4 || ( verparts.at( 0 ).toInt() == 4 && verparts.at( 1 ).toInt() >= 1 ) );
381 sqlite3_free_table( results );
384 char *errMsg =
nullptr;
385 ret = sqlite3_exec( sqlite_handle, above41 ?
"SELECT InitSpatialMetadata(1)" :
"SELECT InitSpatialMetadata()",
nullptr,
nullptr, &errMsg );
387 if ( ret != SQLITE_OK )
389 QString errCause = tr(
"Unable to initialize SpatialMetadata:\n" );
390 errCause += QString::fromUtf8( errMsg );
391 showWarning( errCause );
392 sqlite3_free( errMsg );
395 spatial_ref_sys_init( sqlite_handle, 0 );
398 bool QgsOfflineEditing::createOfflineDb(
const QString &offlineDbPath,
ContainerType containerType )
401 char *errMsg =
nullptr;
402 QFile newDb( offlineDbPath );
403 if ( newDb.exists() )
405 QFile::remove( offlineDbPath );
410 QFileInfo fullPath = QFileInfo( offlineDbPath );
411 QDir path = fullPath.dir();
414 QDir().mkpath( path.absolutePath() );
417 QString dbPath = newDb.fileName();
420 switch ( containerType )
424 OGRSFDriverH hGpkgDriver = OGRGetDriverByName(
"GPKG" );
427 showWarning( tr(
"Creation of database failed. GeoPackage driver not found." ) );
434 showWarning( tr(
"Creation of database failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
446 ret = database.
open_v2( dbPath, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
nullptr );
450 QString errCause = tr(
"Could not create a new database\n" );
452 showWarning( errCause );
456 ret = sqlite3_exec( database.get(),
"PRAGMA foreign_keys = 1",
nullptr,
nullptr, &errMsg );
457 if ( ret != SQLITE_OK )
459 showWarning( tr(
"Unable to activate FOREIGN_KEY constraints" ) );
460 sqlite3_free( errMsg );
463 initializeSpatialMetadata( database.get() );
467 void QgsOfflineEditing::createLoggingTables(
sqlite3 *db )
470 QString sql = QStringLiteral(
"CREATE TABLE 'log_indices' ('name' TEXT, 'last_index' INTEGER)" );
473 sql = QStringLiteral(
"INSERT INTO 'log_indices' VALUES ('commit_no', 0)" );
476 sql = QStringLiteral(
"INSERT INTO 'log_indices' VALUES ('layer_id', 0)" );
480 sql = QStringLiteral(
"CREATE TABLE 'log_layer_ids' ('id' INTEGER, 'qgis_id' TEXT)" );
484 sql = QStringLiteral(
"CREATE TABLE 'log_fids' ('layer_id' INTEGER, 'offline_fid' INTEGER, 'remote_fid' INTEGER)" );
488 sql = QStringLiteral(
"CREATE TABLE 'log_added_attrs' ('layer_id' INTEGER, 'commit_no' INTEGER, " );
489 sql += QLatin1String(
"'name' TEXT, 'type' INTEGER, 'length' INTEGER, 'precision' INTEGER, 'comment' TEXT)" );
493 sql = QStringLiteral(
"CREATE TABLE 'log_added_features' ('layer_id' INTEGER, 'fid' INTEGER)" );
497 sql = QStringLiteral(
"CREATE TABLE 'log_removed_features' ('layer_id' INTEGER, 'fid' INTEGER)" );
501 sql = QStringLiteral(
"CREATE TABLE 'log_feature_updates' ('layer_id' INTEGER, 'commit_no' INTEGER, 'fid' INTEGER, 'attr' INTEGER, 'value' TEXT)" );
505 sql = QStringLiteral(
"CREATE TABLE 'log_geometry_updates' ('layer_id' INTEGER, 'commit_no' INTEGER, 'fid' INTEGER, 'geom_wkt' TEXT)" );
518 QString tableName = layer->
id();
519 QgsDebugMsgLevel( QStringLiteral(
"Creating offline table %1 ..." ).arg( tableName ), 4 );
524 switch ( containerType )
529 QString sql = QStringLiteral(
"CREATE TABLE '%1' (" ).arg( tableName );
532 for (
const auto &field : providerFields )
535 QVariant::Type type = field.type();
536 if ( type == QVariant::Int || type == QVariant::LongLong )
538 dataType = QStringLiteral(
"INTEGER" );
540 else if ( type == QVariant::Double )
542 dataType = QStringLiteral(
"REAL" );
544 else if ( type == QVariant::String )
546 dataType = QStringLiteral(
"TEXT" );
550 showWarning( tr(
"%1: Unknown data type %2. Not using type affinity for the field." ).arg( field.name(), QVariant::typeToName( type ) ) );
553 sql += delim + QStringLiteral(
"'%1' %2" ).arg( field.name(), dataType );
558 int rc = sqlExec( db, sql );
569 geomType = QStringLiteral(
"POINT" );
572 geomType = QStringLiteral(
"MULTIPOINT" );
575 geomType = QStringLiteral(
"LINESTRING" );
578 geomType = QStringLiteral(
"MULTILINESTRING" );
581 geomType = QStringLiteral(
"POLYGON" );
584 geomType = QStringLiteral(
"MULTIPOLYGON" );
591 QString zmInfo = QStringLiteral(
"XY" );
600 if ( layer->
crs().
authid().startsWith( QLatin1String(
"EPSG:" ), Qt::CaseInsensitive ) )
602 epsgCode = layer->
crs().
authid().mid( 5 );
607 showWarning( tr(
"Layer %1 has unsupported Coordinate Reference System (%2)." ).arg( layer->
name(), layer->
crs().
authid() ) );
610 QString sqlAddGeom = QStringLiteral(
"SELECT AddGeometryColumn('%1', 'Geometry', %2, '%3', '%4')" )
611 .arg( tableName, epsgCode, geomType, zmInfo );
614 QString sqlCreateIndex = QStringLiteral(
"SELECT CreateSpatialIndex('%1', 'Geometry')" ).arg( tableName );
616 if ( rc == SQLITE_OK )
618 rc = sqlExec( db, sqlAddGeom );
619 if ( rc == SQLITE_OK )
621 rc = sqlExec( db, sqlCreateIndex );
626 if ( rc != SQLITE_OK )
628 showWarning( tr(
"Filling SpatiaLite for layer %1 failed" ).arg( layer->
name() ) );
633 QString connectionString = QStringLiteral(
"dbname='%1' table='%2'%3 sql=" )
635 tableName, layer->
isSpatial() ?
"(Geometry)" :
"" );
638 layer->
name() +
" (offline)", QStringLiteral(
"spatialite" ), options );
644 char **options =
nullptr;
646 options = CSLSetNameValue( options,
"OVERWRITE",
"YES" );
647 options = CSLSetNameValue( options,
"IDENTIFIER", tr(
"%1 (offline)" ).arg( layer->
id() ).toUtf8().constData() );
648 options = CSLSetNameValue( options,
"DESCRIPTION", layer->
dataComment().toUtf8().constData() );
651 QString fidBase( QStringLiteral(
"fid" ) );
652 QString fid = fidBase;
656 fid = fidBase +
'_' + QString::number( counter );
659 if ( counter == 10000 )
661 showWarning( tr(
"Cannot make FID-name for GPKG " ) );
665 options = CSLSetNameValue( options,
"FID", fid.toUtf8().constData() );
669 options = CSLSetNameValue( options,
"GEOMETRY_COLUMN",
"geom" );
670 options = CSLSetNameValue( options,
"SPATIAL_INDEX",
"YES" );
673 OGRSFDriverH hDriver =
nullptr;
676 OGRLayerH hLayer = OGR_DS_CreateLayer( hDS.get(), tableName.toUtf8().constData(), hSRS,
static_cast<OGRwkbGeometryType
>( layer->
wkbType() ), options );
677 CSLDestroy( options );
682 showWarning( tr(
"Creation of layer failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
687 for (
const auto &field : providerFields )
689 const QString fieldName( field.name() );
690 const QVariant::Type type = field.type();
691 OGRFieldType ogrType( OFTString );
692 if ( type == QVariant::Int )
693 ogrType = OFTInteger;
694 else if ( type == QVariant::LongLong )
695 ogrType = OFTInteger64;
696 else if ( type == QVariant::Double )
698 else if ( type == QVariant::Time )
700 else if ( type == QVariant::Date )
702 else if ( type == QVariant::DateTime )
703 ogrType = OFTDateTime;
707 int ogrWidth = field.length();
710 OGR_Fld_SetWidth( fld.get(), ogrWidth );
712 if ( OGR_L_CreateField( hLayer, fld.get(), true ) != OGRERR_NONE )
714 showWarning( tr(
"Creation of field %1 failed (OGR error: %2)" )
715 .arg( fieldName, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
723 OGR_L_ResetReading( hLayer );
724 if ( CPLGetLastErrorType() != CE_None )
726 QString msg( tr(
"Creation of layer failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
732 QString uri = QStringLiteral(
"%1|layername=%2" ).arg( offlineDbPath, tableName );
734 newLayer =
new QgsVectorLayer( uri, layer->
name() +
" (offline)", QStringLiteral(
"ogr" ), layerOptions );
751 if ( !selectedFids.isEmpty() )
765 int featureCount = 1;
767 QList<QgsFeatureId> remoteFeatureIds;
770 remoteFeatureIds << f.
id();
777 QgsAttributes newAttrs( containerType ==
GPKG ? attrs.count() + 1 : attrs.count() );
778 for (
int it = 0; it < attrs.count(); ++it )
780 newAttrs[column++] = attrs.at( it );
794 int layerId = getOrCreateLayerId( db, newLayer->
id() );
795 QList<QgsFeatureId> offlineFeatureIds;
800 offlineFeatureIds << f.
id();
804 sqlExec( db, QStringLiteral(
"BEGIN" ) );
805 int remoteCount = remoteFeatureIds.size();
806 for (
int i = 0; i < remoteCount; i++ )
809 if ( i < offlineFeatureIds.count() )
811 addFidLookup( db, layerId, offlineFeatureIds.at( i ), remoteFeatureIds.at( i ) );
815 showWarning( tr(
"Feature cannot be copied to the offline layer, please check if the online layer '%1' is still accessible." ).arg( layer->
name() ) );
820 sqlExec( db, QStringLiteral(
"COMMIT" ) );
824 showWarning( newLayer->
commitErrors().join( QStringLiteral(
"\n" ) ) );
836 QList<QgsMapLayer *>() << newLayer );
839 copySymbology( layer, newLayer );
842 const auto fields = layer->
fields();
843 for (
const QgsField &field : fields )
854 if ( layerTreeLayer )
857 if ( parentTreeGroup )
859 int index = parentTreeGroup->
children().indexOf( layerTreeLayer );
862 if ( newLayerTreeLayer )
876 updateRelations( layer, newLayer );
877 updateMapThemes( layer, newLayer );
878 updateLayerOrder( layer, newLayer );
886 void QgsOfflineEditing::applyAttributesAdded(
QgsVectorLayer *remoteLayer,
sqlite3 *db,
int layerId,
int commitNo )
888 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 );
889 QList<QgsField> fields = sqlQueryAttributesAdded( db, sql );
892 QList<QgsVectorDataProvider::NativeType> nativeTypes = provider->
nativeTypes();
895 QMap < QVariant::Type, QString > typeNameLookup;
896 for (
int i = 0; i < nativeTypes.size(); i++ )
904 for (
int i = 0; i < fields.size(); i++ )
908 if ( typeNameLookup.contains( field.
type() ) )
916 showWarning( QStringLiteral(
"Could not add attribute '%1' of type %2" ).arg( field.
name() ).arg( field.
type() ) );
925 QString sql = QStringLiteral(
"SELECT \"fid\" FROM 'log_added_features' WHERE \"layer_id\" = %1" ).arg( layerId );
926 const QList<int> featureIdInts = sqlQueryInts( db, sql );
928 for (
int id : featureIdInts )
949 for ( QgsFeatureList::iterator it = features.begin(); it != features.end(); ++it )
953 QMap<int, int> attrLookup = attributeLookup( offlineLayer, remoteLayer );
956 for (
int it = 0; it < attrs.count(); ++it )
958 newAttrs[ attrLookup[ it ] ] = attrs.at( it );
969 void QgsOfflineEditing::applyFeaturesRemoved(
QgsVectorLayer *remoteLayer,
sqlite3 *db,
int layerId )
971 QString sql = QStringLiteral(
"SELECT \"fid\" FROM 'log_removed_features' WHERE \"layer_id\" = %1" ).arg( layerId );
977 for ( QgsFeatureIds::const_iterator it = values.constBegin(); it != values.constEnd(); ++it )
988 QString sql = QStringLiteral(
"SELECT \"fid\", \"attr\", \"value\" FROM 'log_feature_updates' WHERE \"layer_id\" = %1 AND \"commit_no\" = %2 " ).arg( layerId ).arg( commitNo );
989 AttributeValueChanges values = sqlQueryAttributeValueChanges( db, sql );
993 QMap<int, int> attrLookup = attributeLookup( offlineLayer, remoteLayer );
995 for (
int i = 0; i < values.size(); i++ )
997 QgsFeatureId fid = remoteFid( db, layerId, values.at( i ).fid );
998 QgsDebugMsgLevel( QStringLiteral(
"Offline changeAttributeValue %1 = %2" ).arg( QString( attrLookup[ values.at( i ).attr ] ), values.at( i ).value ), 4 );
999 remoteLayer->
changeAttributeValue( fid, attrLookup[ values.at( i ).attr ], values.at( i ).value );
1005 void QgsOfflineEditing::applyGeometryChanges(
QgsVectorLayer *remoteLayer,
sqlite3 *db,
int layerId,
int commitNo )
1007 QString sql = QStringLiteral(
"SELECT \"fid\", \"geom_wkt\" FROM 'log_geometry_updates' WHERE \"layer_id\" = %1 AND \"commit_no\" = %2" ).arg( layerId ).arg( commitNo );
1008 GeometryChanges values = sqlQueryGeometryChanges( db, sql );
1012 for (
int i = 0; i < values.size(); i++ )
1014 QgsFeatureId fid = remoteFid( db, layerId, values.at( i ).fid );
1038 if ( offlineFid( db, layerId, f.
id() ) == -1 )
1040 newRemoteFids[ f.
id()] =
true;
1048 QString sql = QStringLiteral(
"SELECT \"fid\" FROM 'log_added_features' WHERE \"layer_id\" = %1" ).arg( layerId );
1049 QList<int> newOfflineFids = sqlQueryInts( db, sql );
1051 if ( newRemoteFids.size() != newOfflineFids.size() )
1059 sqlExec( db, QStringLiteral(
"BEGIN" ) );
1060 for ( QMap<QgsFeatureId, bool>::const_iterator it = newRemoteFids.constBegin(); it != newRemoteFids.constEnd(); ++it )
1062 addFidLookup( db, layerId, newOfflineFids.at( i++ ), it.key() );
1064 sqlExec( db, QStringLiteral(
"COMMIT" ) );
1076 if ( error.isEmpty() )
1080 if ( !error.isEmpty() )
1082 showWarning( error );
1089 const QList<QgsRelation> referencedRelations = relationManager->
referencedRelations( sourceLayer );
1091 for (
QgsRelation relation : referencedRelations )
1094 relation.setReferencedLayer( targetLayer->
id() );
1098 const QList<QgsRelation> referencingRelations = relationManager->
referencingRelations( sourceLayer );
1100 for (
QgsRelation relation : referencingRelations )
1103 relation.setReferencingLayer( targetLayer->
id() );
1111 const QStringList mapThemeNames = mapThemeCollection->
mapThemes();
1113 for (
const QString &mapThemeName : mapThemeNames )
1121 if ( layerRecord.layer() == sourceLayer )
1123 layerRecord.setLayer( targetLayer );
1137 auto iterator = layerOrder.begin();
1139 while ( iterator != layerOrder.end() )
1141 if ( *iterator == targetLayer )
1143 iterator = layerOrder.erase( iterator );
1144 if ( iterator == layerOrder.end() )
1148 if ( *iterator == sourceLayer )
1150 *iterator = targetLayer;
1164 QMap <
int ,
int > attrLookup;
1167 for (
int i = 0; i < offlineAttrs.size(); i++ )
1176 void QgsOfflineEditing::showWarning(
const QString &message )
1178 emit
warning( tr(
"Offline Editing Plugin" ), message );
1185 if ( !dbPath.isEmpty() )
1188 int rc = database.
open( absoluteDbPath );
1189 if ( rc != SQLITE_OK )
1191 QgsDebugMsg( QStringLiteral(
"Could not open the SpatiaLite logging database" ) );
1192 showWarning( tr(
"Could not open the SpatiaLite logging database" ) );
1197 QgsDebugMsg( QStringLiteral(
"dbPath is empty!" ) );
1202 int QgsOfflineEditing::getOrCreateLayerId(
sqlite3 *db,
const QString &qgisLayerId )
1204 QString sql = QStringLiteral(
"SELECT \"id\" FROM 'log_layer_ids' WHERE \"qgis_id\" = '%1'" ).arg( qgisLayerId );
1205 int layerId = sqlQueryInt( db, sql, -1 );
1206 if ( layerId == -1 )
1209 sql = QStringLiteral(
"SELECT \"last_index\" FROM 'log_indices' WHERE \"name\" = 'layer_id'" );
1210 int newLayerId = sqlQueryInt( db, sql, -1 );
1213 sql = QStringLiteral(
"INSERT INTO 'log_layer_ids' VALUES (%1, '%2')" ).arg( newLayerId ).arg( qgisLayerId );
1218 sql = QStringLiteral(
"UPDATE 'log_indices' SET 'last_index' = %1 WHERE \"name\" = 'layer_id'" ).arg( newLayerId + 1 );
1221 layerId = newLayerId;
1227 int QgsOfflineEditing::getCommitNo(
sqlite3 *db )
1229 QString sql = QStringLiteral(
"SELECT \"last_index\" FROM 'log_indices' WHERE \"name\" = 'commit_no'" );
1230 return sqlQueryInt( db, sql, -1 );
1233 void QgsOfflineEditing::increaseCommitNo(
sqlite3 *db )
1235 QString sql = QStringLiteral(
"UPDATE 'log_indices' SET 'last_index' = %1 WHERE \"name\" = 'commit_no'" ).arg( getCommitNo( db ) + 1 );
1241 QString sql = QStringLiteral(
"INSERT INTO 'log_fids' VALUES ( %1, %2, %3 )" ).arg( layerId ).arg( offlineFid ).arg( remoteFid );
1247 QString sql = QStringLiteral(
"SELECT \"remote_fid\" FROM 'log_fids' WHERE \"layer_id\" = %1 AND \"offline_fid\" = %2" ).arg( layerId ).arg( offlineFid );
1248 return sqlQueryInt( db, sql, -1 );
1253 QString sql = QStringLiteral(
"SELECT \"offline_fid\" FROM 'log_fids' WHERE \"layer_id\" = %1 AND \"remote_fid\" = %2" ).arg( layerId ).arg( remoteFid );
1254 return sqlQueryInt( db, sql, -1 );
1259 QString sql = QStringLiteral(
"SELECT COUNT(\"fid\") FROM 'log_added_features' WHERE \"layer_id\" = %1 AND \"fid\" = %2" ).arg( layerId ).arg( fid );
1260 return ( sqlQueryInt( db, sql, 0 ) > 0 );
1263 int QgsOfflineEditing::sqlExec(
sqlite3 *db,
const QString &sql )
1265 char *errmsg =
nullptr;
1266 int rc = sqlite3_exec( db, sql.toUtf8(),
nullptr,
nullptr, &errmsg );
1267 if ( rc != SQLITE_OK )
1269 showWarning( errmsg );
1274 int QgsOfflineEditing::sqlQueryInt(
sqlite3 *db,
const QString &sql,
int defaultValue )
1276 sqlite3_stmt *stmt =
nullptr;
1277 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1279 showWarning( sqlite3_errmsg( db ) );
1280 return defaultValue;
1283 int value = defaultValue;
1284 int ret = sqlite3_step( stmt );
1285 if ( ret == SQLITE_ROW )
1287 value = sqlite3_column_int( stmt, 0 );
1289 sqlite3_finalize( stmt );
1294 QList<int> QgsOfflineEditing::sqlQueryInts(
sqlite3 *db,
const QString &sql )
1298 sqlite3_stmt *stmt =
nullptr;
1299 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1301 showWarning( sqlite3_errmsg( db ) );
1305 int ret = sqlite3_step( stmt );
1306 while ( ret == SQLITE_ROW )
1308 values << sqlite3_column_int( stmt, 0 );
1310 ret = sqlite3_step( stmt );
1312 sqlite3_finalize( stmt );
1317 QList<QgsField> QgsOfflineEditing::sqlQueryAttributesAdded(
sqlite3 *db,
const QString &sql )
1319 QList<QgsField> values;
1321 sqlite3_stmt *stmt =
nullptr;
1322 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1324 showWarning( sqlite3_errmsg( db ) );
1328 int ret = sqlite3_step( stmt );
1329 while ( ret == SQLITE_ROW )
1331 QgsField field( QString( reinterpret_cast< const char * >( sqlite3_column_text( stmt, 0 ) ) ),
1332 static_cast< QVariant::Type >( sqlite3_column_int( stmt, 1 ) ),
1334 sqlite3_column_int( stmt, 2 ),
1335 sqlite3_column_int( stmt, 3 ),
1336 QString( reinterpret_cast< const char * >( sqlite3_column_text( stmt, 4 ) ) ) );
1339 ret = sqlite3_step( stmt );
1341 sqlite3_finalize( stmt );
1350 sqlite3_stmt *stmt =
nullptr;
1351 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1353 showWarning( sqlite3_errmsg( db ) );
1357 int ret = sqlite3_step( stmt );
1358 while ( ret == SQLITE_ROW )
1360 values << sqlite3_column_int( stmt, 0 );
1362 ret = sqlite3_step( stmt );
1364 sqlite3_finalize( stmt );
1369 QgsOfflineEditing::AttributeValueChanges QgsOfflineEditing::sqlQueryAttributeValueChanges(
sqlite3 *db,
const QString &sql )
1371 AttributeValueChanges values;
1373 sqlite3_stmt *stmt =
nullptr;
1374 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1376 showWarning( sqlite3_errmsg( db ) );
1380 int ret = sqlite3_step( stmt );
1381 while ( ret == SQLITE_ROW )
1383 AttributeValueChange change;
1384 change.fid = sqlite3_column_int( stmt, 0 );
1385 change.attr = sqlite3_column_int( stmt, 1 );
1386 change.value = QString( reinterpret_cast< const char * >( sqlite3_column_text( stmt, 2 ) ) );
1389 ret = sqlite3_step( stmt );
1391 sqlite3_finalize( stmt );
1396 QgsOfflineEditing::GeometryChanges QgsOfflineEditing::sqlQueryGeometryChanges(
sqlite3 *db,
const QString &sql )
1398 GeometryChanges values;
1400 sqlite3_stmt *stmt =
nullptr;
1401 if ( sqlite3_prepare_v2( db, sql.toUtf8().constData(), -1, &stmt, nullptr ) != SQLITE_OK )
1403 showWarning( sqlite3_errmsg( db ) );
1407 int ret = sqlite3_step( stmt );
1408 while ( ret == SQLITE_ROW )
1410 GeometryChange change;
1411 change.fid = sqlite3_column_int( stmt, 0 );
1412 change.geom_wkt = QString( reinterpret_cast< const char * >( sqlite3_column_text( stmt, 1 ) ) );
1415 ret = sqlite3_step( stmt );
1417 sqlite3_finalize( stmt );
1422 void QgsOfflineEditing::committedAttributesAdded(
const QString &qgisLayerId,
const QList<QgsField> &addedAttributes )
1429 int layerId = getOrCreateLayerId( database.get(), qgisLayerId );
1430 int commitNo = getCommitNo( database.get() );
1432 for ( QList<QgsField>::const_iterator it = addedAttributes.begin(); it != addedAttributes.end(); ++it )
1435 QString sql = QStringLiteral(
"INSERT INTO 'log_added_attrs' VALUES ( %1, %2, '%3', %4, %5, %6, '%7' )" )
1438 .arg( field.
name() )
1439 .arg( field.
type() )
1443 sqlExec( database.get(), sql );
1446 increaseCommitNo( database.get() );
1449 void QgsOfflineEditing::committedFeaturesAdded(
const QString &qgisLayerId,
const QgsFeatureList &addedFeatures )
1456 int layerId = getOrCreateLayerId( database.get(), qgisLayerId );
1465 if ( !offlinePath.contains(
".gpkg" ) )
1467 tableName = uri.
table();
1471 tableName = uri.
param( offlinePath +
"|layername" );
1475 QString sql = QStringLiteral(
"SELECT ROWID FROM '%1' ORDER BY ROWID DESC LIMIT %2" ).arg( tableName ).arg( addedFeatures.size() );
1476 QList<int> newFeatureIds = sqlQueryInts( database.get(), sql );
1477 for (
int i = newFeatureIds.size() - 1; i >= 0; i-- )
1479 QString sql = QStringLiteral(
"INSERT INTO 'log_added_features' VALUES ( %1, %2 )" )
1481 .arg( newFeatureIds.at( i ) );
1482 sqlExec( database.get(), sql );
1486 void QgsOfflineEditing::committedFeaturesRemoved(
const QString &qgisLayerId,
const QgsFeatureIds &deletedFeatureIds )
1493 int layerId = getOrCreateLayerId( database.get(), qgisLayerId );
1495 for ( QgsFeatureIds::const_iterator it = deletedFeatureIds.begin(); it != deletedFeatureIds.end(); ++it )
1497 if ( isAddedFeature( database.get(), layerId, *it ) )
1500 QString sql = QStringLiteral(
"DELETE FROM 'log_added_features' WHERE \"layer_id\" = %1 AND \"fid\" = %2" ).arg( layerId ).arg( *it );
1501 sqlExec( database.get(), sql );
1505 QString sql = QStringLiteral(
"INSERT INTO 'log_removed_features' VALUES ( %1, %2)" )
1508 sqlExec( database.get(), sql );
1513 void QgsOfflineEditing::committedAttributeValuesChanges(
const QString &qgisLayerId,
const QgsChangedAttributesMap &changedAttrsMap )
1520 int layerId = getOrCreateLayerId( database.get(), qgisLayerId );
1521 int commitNo = getCommitNo( database.get() );
1523 for ( QgsChangedAttributesMap::const_iterator cit = changedAttrsMap.begin(); cit != changedAttrsMap.end(); ++cit )
1526 if ( isAddedFeature( database.get(), layerId, fid ) )
1532 for ( QgsAttributeMap::const_iterator it = attrMap.constBegin(); it != attrMap.constEnd(); ++it )
1534 QString sql = QStringLiteral(
"INSERT INTO 'log_feature_updates' VALUES ( %1, %2, %3, %4, '%5' )" )
1539 .arg( it.value().toString() );
1540 sqlExec( database.get(), sql );
1544 increaseCommitNo( database.get() );
1547 void QgsOfflineEditing::committedGeometriesChanges(
const QString &qgisLayerId,
const QgsGeometryMap &changedGeometries )
1554 int layerId = getOrCreateLayerId( database.get(), qgisLayerId );
1555 int commitNo = getCommitNo( database.get() );
1557 for ( QgsGeometryMap::const_iterator it = changedGeometries.begin(); it != changedGeometries.end(); ++it )
1560 if ( isAddedFeature( database.get(), layerId, fid ) )
1566 QString sql = QStringLiteral(
"INSERT INTO 'log_geometry_updates' VALUES ( %1, %2, %3, '%4' )" )
1570 .arg( geom.
asWkt() );
1571 sqlExec( database.get(), sql );
1576 increaseCommitNo( database.get() );
1579 void QgsOfflineEditing::startListenFeatureChanges()
1587 this, &QgsOfflineEditing::committedAttributesAdded );
1589 this, &QgsOfflineEditing::committedAttributeValuesChanges );
1591 this, &QgsOfflineEditing::committedGeometriesChanges );
1594 this, &QgsOfflineEditing::committedFeaturesAdded );
1596 this, &QgsOfflineEditing::committedFeaturesRemoved );
1599 void QgsOfflineEditing::stopListenFeatureChanges()
1607 this, &QgsOfflineEditing::committedAttributesAdded );
1609 this, &QgsOfflineEditing::committedAttributeValuesChanges );
1611 this, &QgsOfflineEditing::committedGeometriesChanges );
1614 this, &QgsOfflineEditing::committedFeaturesAdded );
1616 this, &QgsOfflineEditing::committedFeaturesRemoved );
1619 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
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.
virtual QString name() const =0
Returns a provider name.
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
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.
QString toWkt() const
Returns a WKT representation of this CRS.
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.
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.
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.
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.
#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
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.