QGIS API Documentation 4.1.0-Master (26185ffb827)
Loading...
Searching...
No Matches
qgsvectorlayer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvectorlayer.cpp
3 --------------------
4 begin : Oct 29, 2003
5 copyright : (C) 2003 by Gary E.Sherman
6 email : sherman at mrcc.com
7
8 This class implements a generic means to display vector layers. The features
9 and attributes are read from the data store using a "data provider" plugin.
10 QgsVectorLayer can be used with any data store for which an appropriate
11 plugin is available.
12
13***************************************************************************/
14
15/***************************************************************************
16 * *
17 * This program is free software; you can redistribute it and/or modify *
18 * it under the terms of the GNU General Public License as published by *
19 * the Free Software Foundation; either version 2 of the License, or *
20 * (at your option) any later version. *
21 * *
22 ***************************************************************************/
23
24#include "qgsvectorlayer.h"
25
26#include <limits>
27#include <memory>
28#include <optional>
29
30#include "qgis.h"
31#include "qgsactionmanager.h"
32#include "qgsapplication.h"
33#include "qgsauxiliarystorage.h"
34#include "qgsconditionalstyle.h"
36#include "qgscurve.h"
37#include "qgsdatasourceuri.h"
38#include "qgsdiagramrenderer.h"
43#include "qgsfeature.h"
45#include "qgsfeaturerequest.h"
46#include "qgsfeedback.h"
47#include "qgsfields.h"
48#include "qgsgeometry.h"
49#include "qgsgeometryoptions.h"
51#include "qgslogger.h"
52#include "qgsmaplayerfactory.h"
53#include "qgsmaplayerlegend.h"
55#include "qgsmessagelog.h"
57#include "qgsobjectvisitor.h"
58#include "qgsogcutils.h"
59#include "qgspainting.h"
60#include "qgspallabeling.h"
61#include "qgspoint.h"
62#include "qgspointxy.h"
63#include "qgsprofilerequest.h"
64#include "qgsproject.h"
65#include "qgsproviderregistry.h"
66#include "qgsrectangle.h"
67#include "qgsrelationmanager.h"
68#include "qgsrendercontext.h"
69#include "qgsrenderer.h"
71#include "qgsruntimeprofiler.h"
74#include "qgssettingstree.h"
75#include "qgssldexportcontext.h"
77#include "qgssymbollayer.h"
78#include "qgssymbollayerutils.h"
79#include "qgstaskmanager.h"
80#include "qgsthreadingutils.h"
81#include "qgstransaction.h"
95#include "qgsvectorlayerutils.h"
96#include "qgsweakrelation.h"
97#include "qgsxmlutils.h"
98
99#include <QDir>
100#include <QDomNode>
101#include <QFile>
102#include <QImage>
103#include <QPainter>
104#include <QPainterPath>
105#include <QPolygonF>
106#include <QProgressDialog>
107#include <QRegularExpression>
108#include <QString>
109#include <QStringBuilder>
110#include <QTimer>
111#include <QUndoCommand>
112#include <QUrl>
113#include <QUrlQuery>
114#include <QUuid>
115#include <QVector>
116
117#include "moc_qgsvectorlayer.cpp"
118
119using namespace Qt::StringLiterals;
120
128
129
130#ifdef TESTPROVIDERLIB
131#include <dlfcn.h>
132#endif
133
134typedef bool saveStyle_t(
135 const QString &uri, const QString &qmlStyle, const QString &sldStyle, const QString &styleName, const QString &styleDescription, const QString &uiFileContent, bool useAsDefault, QString &errCause
136);
137
138typedef QString loadStyle_t( const QString &uri, QString &errCause );
139
140typedef int listStyles_t( const QString &uri, QStringList &ids, QStringList &names, QStringList &descriptions, QString &errCause );
141
142typedef QString getStyleById_t( const QString &uri, QString styleID, QString &errCause );
143
144typedef bool deleteStyleById_t( const QString &uri, QString styleID, QString &errCause );
145
146
147QgsVectorLayer::QgsVectorLayer( const QString &vectorLayerPath, const QString &baseName, const QString &providerKey, const QgsVectorLayer::LayerOptions &options )
148 : QgsMapLayer( Qgis::LayerType::Vector, baseName, vectorLayerPath )
149 , mSelectionProperties( new QgsVectorLayerSelectionProperties( this ) )
150 , mTemporalProperties( new QgsVectorLayerTemporalProperties( this ) )
151 , mElevationProperties( new QgsVectorLayerElevationProperties( this ) )
152 , mAuxiliaryLayer( nullptr )
153 , mAuxiliaryLayerKey( QString() )
154 , mReadExtentFromXml( options.readExtentFromXml )
155 , mRefreshRendererTimer( new QTimer( this ) )
156{
158 mLoadAllStoredStyle = options.loadAllStoredStyles;
159
160 if ( options.fallbackCrs.isValid() )
161 setCrs( options.fallbackCrs, false );
162 mWkbType = options.fallbackWkbType;
163
164 setProviderType( providerKey );
165
166 mGeometryOptions = std::make_unique<QgsGeometryOptions>();
167 mActions = new QgsActionManager( this );
168 mConditionalStyles = new QgsConditionalLayerStyles( this );
169 mStoredExpressionManager = new QgsStoredExpressionManager();
170 mStoredExpressionManager->setParent( this );
171
172 mJoinBuffer = new QgsVectorLayerJoinBuffer( this );
173 mJoinBuffer->setParent( this );
174 connect( mJoinBuffer, &QgsVectorLayerJoinBuffer::joinedFieldsChanged, this, &QgsVectorLayer::onJoinedFieldsChanged );
175
176 mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
177 // if we're given a provider type, try to create and bind one to this layer
178 if ( !vectorLayerPath.isEmpty() && !mProviderKey.isEmpty() )
179 {
180 QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
181 Qgis::DataProviderReadFlags providerFlags;
182 if ( options.loadDefaultStyle )
183 {
185 }
186 if ( options.forceReadOnly )
187 {
189 mDataSourceReadOnly = true;
190 }
191 setDataSource( vectorLayerPath, baseName, providerKey, providerOptions, providerFlags );
192 }
193
194 for ( const QgsField &field : std::as_const( mFields ) )
195 {
196 if ( !mAttributeAliasMap.contains( field.name() ) )
197 mAttributeAliasMap.insert( field.name(), QString() );
198 }
199
200 if ( isValid() )
201 {
202 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
203 if ( !mTemporalProperties->isActive() )
204 {
205 // didn't populate temporal properties from provider metadata, so at least try to setup some initially nice
206 // selections
207 mTemporalProperties->guessDefaultsFromFields( mFields );
208 }
209
210 mElevationProperties->setDefaultsFromLayer( this );
211 }
212
213 connect( this, &QgsVectorLayer::selectionChanged, this, [this] { triggerRepaint(); } );
214 connect( QgsProject::instance()->relationManager(), &QgsRelationManager::relationsLoaded, this, &QgsVectorLayer::onRelationsLoaded ); // skip-keyword-check
215
219
220 // Default simplify drawing settings
221 mSimplifyMethod.setSimplifyHints( QgsVectorLayer::settingsSimplifyDrawingHints->valueWithDefaultOverride( mSimplifyMethod.simplifyHints() ) );
222 mSimplifyMethod.setSimplifyAlgorithm( QgsVectorLayer::settingsSimplifyAlgorithm->valueWithDefaultOverride( mSimplifyMethod.simplifyAlgorithm() ) );
223 mSimplifyMethod.setThreshold( QgsVectorLayer::settingsSimplifyDrawingTol->valueWithDefaultOverride( mSimplifyMethod.threshold() ) );
224 mSimplifyMethod.setForceLocalOptimization( QgsVectorLayer::settingsSimplifyLocal->valueWithDefaultOverride( mSimplifyMethod.forceLocalOptimization() ) );
225 mSimplifyMethod.setMaximumScale( QgsVectorLayer::settingsSimplifyMaxScale->valueWithDefaultOverride( mSimplifyMethod.maximumScale() ) );
226
227 connect( mRefreshRendererTimer, &QTimer::timeout, this, [this] { triggerRepaint( true ); } );
228}
229
231{
232 emit willBeDeleted();
233
234 setValid( false );
235
236 delete mDataProvider;
237 delete mEditBuffer;
238 delete mJoinBuffer;
239 delete mExpressionFieldBuffer;
240 delete mLabeling;
241 delete mDiagramLayerSettings;
242 delete mDiagramRenderer;
243
244 delete mActions;
245
246 delete mRenderer;
247 delete mConditionalStyles;
248 delete mStoredExpressionManager;
249
250 if ( mFeatureCounter )
251 mFeatureCounter->cancel();
252
253 qDeleteAll( mRendererGenerators );
254}
255
257{
259
261 // We get the data source string from the provider when
262 // possible because some providers may have changed it
263 // directly (memory provider does that).
264 QString dataSource;
265 if ( mDataProvider )
266 {
267 dataSource = mDataProvider->dataSourceUri();
268 options.transformContext = mDataProvider->transformContext();
269 }
270 else
271 {
272 dataSource = source();
273 }
274 options.forceReadOnly = mDataSourceReadOnly;
275 QgsVectorLayer *layer = new QgsVectorLayer( dataSource, name(), mProviderKey, options );
276 if ( mDataProvider && layer->dataProvider() )
277 {
278 layer->dataProvider()->handlePostCloneOperations( mDataProvider );
279 }
280 QgsMapLayer::clone( layer );
281 layer->mXmlExtent2D = mXmlExtent2D;
282 layer->mLazyExtent2D = mLazyExtent2D;
283 layer->mValidExtent2D = mValidExtent2D;
284 layer->mXmlExtent3D = mXmlExtent3D;
285 layer->mLazyExtent3D = mLazyExtent3D;
286 layer->mValidExtent3D = mValidExtent3D;
287
288 QList<QgsVectorLayerJoinInfo> joins = vectorJoins();
289 const auto constJoins = joins;
290 for ( const QgsVectorLayerJoinInfo &join : constJoins )
291 {
292 // do not copy join information for auxiliary layer
293 if ( !auxiliaryLayer() || ( auxiliaryLayer() && auxiliaryLayer()->id() != join.joinLayerId() ) )
294 layer->addJoin( join );
295 }
296
297 if ( mDataProvider )
298 layer->setProviderEncoding( mDataProvider->encoding() );
299 layer->setSubsetString( subsetString() );
303 layer->setReadOnly( isReadOnly() );
308
309 const auto constActions = actions()->actions();
310 for ( const QgsAction &action : constActions )
311 {
312 layer->actions()->addAction( action );
313 }
314
315 if ( auto *lRenderer = renderer() )
316 {
317 layer->setRenderer( lRenderer->clone() );
318 }
319
320 if ( auto *lLabeling = labeling() )
321 {
322 layer->setLabeling( lLabeling->clone() );
323 }
325
327
328 if ( auto *lDiagramRenderer = diagramRenderer() )
329 {
330 layer->setDiagramRenderer( lDiagramRenderer->clone() );
331 }
332
333 if ( auto *lDiagramLayerSettings = diagramLayerSettings() )
334 {
335 layer->setDiagramLayerSettings( *lDiagramLayerSettings );
336 }
337
338 for ( int i = 0; i < fields().count(); i++ )
339 {
340 layer->setFieldAlias( i, attributeAlias( i ) );
342 layer->setEditorWidgetSetup( i, editorWidgetSetup( i ) );
345
346 QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength> constraints = fieldConstraintsAndStrength( i );
347 auto constraintIt = constraints.constBegin();
348 for ( ; constraintIt != constraints.constEnd(); ++constraintIt )
349 {
350 layer->setFieldConstraint( i, constraintIt.key(), constraintIt.value() );
351 }
352
353 if ( fields().fieldOrigin( i ) == Qgis::FieldOrigin::Expression )
354 {
355 layer->addExpressionField( expressionField( i ), fields().at( i ) );
356 }
357 }
358
360
361 if ( auto *lAuxiliaryLayer = auxiliaryLayer() )
362 layer->setAuxiliaryLayer( lAuxiliaryLayer->clone( layer ) );
363
364 layer->mElevationProperties = mElevationProperties->clone();
365 layer->mElevationProperties->setParent( layer );
366
367 layer->mSelectionProperties = mSelectionProperties->clone();
368 layer->mSelectionProperties->setParent( layer );
369
370 return layer;
371}
372
374{
376
377 if ( mDataProvider )
378 {
379 return mDataProvider->storageType();
380 }
381 return QString();
382}
383
384
386{
388
389 if ( mDataProvider )
390 {
391 return mDataProvider->capabilitiesString();
392 }
393 return QString();
394}
395
397{
399
400 return mDataProvider && mDataProvider->isSqlQuery();
401}
402
404{
406
407 return mDataProvider ? mDataProvider->vectorLayerTypeFlags() : Qgis::VectorLayerTypeFlags();
408}
409
411{
413
414 if ( mDataProvider )
415 {
416 return mDataProvider->dataComment();
417 }
418 return QString();
419}
420
427
429{
431
432 return name();
433}
434
436{
437 // non fatal for now -- the QgsVirtualLayerTask class is not thread safe and calls this
439
440 if ( mDataProvider )
441 {
442 mDataProvider->reloadData();
443 updateFields();
444 }
445}
446
448{
449 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
451
452 return new QgsVectorLayerRenderer( this, rendererContext );
453}
454
455
456void QgsVectorLayer::drawVertexMarker( double x, double y, QPainter &p, Qgis::VertexMarkerType type, int m )
457{
458 switch ( type )
459 {
461 p.setPen( QColor( 50, 100, 120, 200 ) );
462 p.setBrush( QColor( 200, 200, 210, 120 ) );
463 p.drawEllipse( x - m, y - m, m * 2 + 1, m * 2 + 1 );
464 break;
465
467 p.setPen( QColor( 255, 0, 0 ) );
468 p.drawLine( x - m, y + m, x + m, y - m );
469 p.drawLine( x - m, y - m, x + m, y + m );
470 break;
471
473 break;
474 }
475}
476
478{
480
481 mSelectedFeatureIds.insert( fid );
482 mPreviousSelectedFeatureIds.clear();
483
484 emit selectionChanged( QgsFeatureIds() << fid, QgsFeatureIds(), false );
485}
486
487void QgsVectorLayer::select( const QgsFeatureIds &featureIds )
488{
490
491 mSelectedFeatureIds.unite( featureIds );
492 mPreviousSelectedFeatureIds.clear();
493
494 emit selectionChanged( featureIds, QgsFeatureIds(), false );
495}
496
498{
500
501 mSelectedFeatureIds.remove( fid );
502 mPreviousSelectedFeatureIds.clear();
503
504 emit selectionChanged( QgsFeatureIds(), QgsFeatureIds() << fid, false );
505}
506
508{
510
511 mSelectedFeatureIds.subtract( featureIds );
512 mPreviousSelectedFeatureIds.clear();
513
514 emit selectionChanged( QgsFeatureIds(), featureIds, false );
515}
516
518{
520
521 // normalize the rectangle
522 QgsRectangle normalizedRect = rect;
523 normalizedRect.normalize();
524
525 QgsFeatureIds newSelection;
526
529 );
530
531 QgsFeature feat;
532 while ( features.nextFeature( feat ) )
533 {
534 newSelection << feat.id();
535 }
536 features.close();
537
538 selectByIds( newSelection, behavior );
539}
540
541void QgsVectorLayer::selectByExpression( const QString &expression, Qgis::SelectBehavior behavior, QgsExpressionContext *context )
542{
544
545 QgsFeatureIds newSelection;
546
547 std::optional< QgsExpressionContext > defaultContext;
548 if ( !context )
549 {
550 defaultContext.emplace( QgsExpressionContextUtils::globalProjectLayerScopes( this ) );
551 context = &defaultContext.value();
552 }
553 else
554 {
556 }
557
558 QgsExpression exp( expression );
559 exp.prepare( context );
560
562 {
565
566 if ( !exp.needsGeometry() )
568
569 QgsFeatureIterator features = getFeatures( request );
570
571 if ( behavior == Qgis::SelectBehavior::AddToSelection )
572 {
573 newSelection = selectedFeatureIds();
574 }
575 QgsFeature feat;
576 while ( features.nextFeature( feat ) )
577 {
578 newSelection << feat.id();
579 }
580 features.close();
581 }
583 {
584 QgsFeatureIds oldSelection = selectedFeatureIds();
585 QgsFeatureRequest request = QgsFeatureRequest().setFilterFids( oldSelection );
586
587 //refine request
588 if ( !exp.needsGeometry() )
591
592 QgsFeatureIterator features = getFeatures( request );
593 QgsFeature feat;
594 while ( features.nextFeature( feat ) )
595 {
596 context->setFeature( feat );
597 bool matches = exp.evaluate( context ).toBool();
598
599 if ( matches && behavior == Qgis::SelectBehavior::IntersectSelection )
600 {
601 newSelection << feat.id();
602 }
603 else if ( !matches && behavior == Qgis::SelectBehavior::RemoveFromSelection )
604 {
605 newSelection << feat.id();
606 }
607 }
608 }
610 selectByIds( newSelection );
611}
612
613void QgsVectorLayer::selectByIds( const QgsFeatureIds &ids, Qgis::SelectBehavior behavior, bool validateIds )
614{
616
617 // Opt-in validation: filter invalid IDs if requested
618 QgsFeatureIds idsToSelect = ids;
619 if ( validateIds )
620 {
621 idsToSelect = QgsVectorLayerUtils::filterValidFeatureIds( this, ids );
622 }
623
624 QgsFeatureIds newSelection;
625
626 switch ( behavior )
627 {
629 newSelection = idsToSelect;
630 break;
631
633 newSelection = mSelectedFeatureIds + idsToSelect;
634 break;
635
637 newSelection = mSelectedFeatureIds - idsToSelect;
638 break;
639
641 newSelection = mSelectedFeatureIds.intersect( idsToSelect );
642 break;
643 }
644
645 QgsFeatureIds deselectedFeatures = mSelectedFeatureIds - newSelection;
646 mSelectedFeatureIds = newSelection;
647 mPreviousSelectedFeatureIds.clear();
648
649 emit selectionChanged( newSelection, deselectedFeatures, true );
650}
651
652void QgsVectorLayer::modifySelection( const QgsFeatureIds &selectIds, const QgsFeatureIds &deselectIds )
653{
655
656 QgsFeatureIds intersectingIds = selectIds & deselectIds;
657 if ( !intersectingIds.isEmpty() )
658 {
659 QgsDebugMsgLevel( u"Trying to select and deselect the same item at the same time. Unsure what to do. Selecting dubious items."_s, 3 );
660 }
661
662 mSelectedFeatureIds -= deselectIds;
663 mSelectedFeatureIds += selectIds;
664 mPreviousSelectedFeatureIds.clear();
665
666 emit selectionChanged( selectIds, deselectIds - intersectingIds, false );
667}
668
670{
672
674 ids.subtract( mSelectedFeatureIds );
675 selectByIds( ids );
676}
677
684
686{
688
689 // normalize the rectangle
690 QgsRectangle normalizedRect = rect;
691 normalizedRect.normalize();
692
694
695 QgsFeatureIds selectIds;
696 QgsFeatureIds deselectIds;
697
698 QgsFeature fet;
699 while ( fit.nextFeature( fet ) )
700 {
701 if ( mSelectedFeatureIds.contains( fet.id() ) )
702 {
703 deselectIds << fet.id();
704 }
705 else
706 {
707 selectIds << fet.id();
708 }
709 }
710
711 modifySelection( selectIds, deselectIds );
712}
713
715{
717
718 if ( mSelectedFeatureIds.isEmpty() )
719 return;
720
721 const QgsFeatureIds previous = mSelectedFeatureIds;
723 mPreviousSelectedFeatureIds = previous;
724}
725
727{
729
730 if ( mPreviousSelectedFeatureIds.isEmpty() || !mSelectedFeatureIds.empty() )
731 return;
732
733 selectByIds( mPreviousSelectedFeatureIds );
734}
735
737{
738 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
740
741 return mDataProvider;
742}
743
745{
746 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
748
749 return mDataProvider;
750}
751
753{
754 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
756
757 return mSelectionProperties;
758}
759
766
773
775{
777
778 QgsProfileRequest modifiedRequest( request );
779 modifiedRequest.expressionContext().appendScope( createExpressionContextScope() );
780 return new QgsVectorLayerProfileGenerator( this, modifiedRequest );
781}
782
783void QgsVectorLayer::setProviderEncoding( const QString &encoding )
784{
786
787 if ( isValid() && mDataProvider && mDataProvider->encoding() != encoding )
788 {
789 mDataProvider->setEncoding( encoding );
790 updateFields();
791 }
792}
793
795{
797
798 delete mDiagramRenderer;
799 mDiagramRenderer = r;
800 emit rendererChanged();
801 emit styleChanged();
802}
803
805{
806 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
808
809 return QgsWkbTypes::geometryType( mWkbType );
810}
811
813{
815
816 return mWkbType;
817}
818
820{
822
823 if ( !isValid() || !isSpatial() || mSelectedFeatureIds.isEmpty() || !mDataProvider ) //no selected features
824 {
825 return QgsRectangle( 0, 0, 0, 0 );
826 }
827
828 QgsRectangle r, retval;
829 retval.setNull();
830
831 QgsFeature fet;
832 if ( mDataProvider->capabilities() & Qgis::VectorProviderCapability::SelectAtId )
833 {
834 QgsFeatureIterator fit = getFeatures( QgsFeatureRequest().setFilterFids( mSelectedFeatureIds ).setNoAttributes() );
835
836 while ( fit.nextFeature( fet ) )
837 {
838 if ( !fet.hasGeometry() )
839 continue;
840 r = fet.geometry().boundingBox();
841 retval.combineExtentWith( r );
842 }
843 }
844 else
845 {
846 QgsFeatureIterator fit = getFeatures( QgsFeatureRequest().setNoAttributes() );
847
848 while ( fit.nextFeature( fet ) )
849 {
850 if ( mSelectedFeatureIds.contains( fet.id() ) )
851 {
852 if ( fet.hasGeometry() )
853 {
854 r = fet.geometry().boundingBox();
855 retval.combineExtentWith( r );
856 }
857 }
858 }
859 }
860
861 if ( retval.width() == 0.0 || retval.height() == 0.0 )
862 {
863 // If all of the features are at the one point, buffer the
864 // rectangle a bit. If they are all at zero, do something a bit
865 // more crude.
866
867 if ( retval.xMinimum() == 0.0 && retval.xMaximum() == 0.0 && retval.yMinimum() == 0.0 && retval.yMaximum() == 0.0 )
868 {
869 retval.set( -1.0, -1.0, 1.0, 1.0 );
870 }
871 }
872
873 return retval;
874}
875
877{
878 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
880
881 return mLabelsEnabled && static_cast< bool >( mLabeling );
882}
883
885{
887
888 mLabelsEnabled = enabled;
889}
890
892{
893 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
895
896 if ( !mDiagramRenderer || !mDiagramLayerSettings )
897 return false;
898
899 QList<QgsDiagramSettings> settingList = mDiagramRenderer->diagramSettings();
900 if ( !settingList.isEmpty() )
901 {
902 return settingList.at( 0 ).enabled;
903 }
904 return false;
905}
906
907long long QgsVectorLayer::featureCount( const QString &legendKey ) const
908{
910
911 if ( !mSymbolFeatureCounted )
912 return -1;
913
914 return mSymbolFeatureCountMap.value( legendKey, -1 );
915}
916
917QgsFeatureIds QgsVectorLayer::symbolFeatureIds( const QString &legendKey ) const
918{
920
921 if ( !mSymbolFeatureCounted )
922 return QgsFeatureIds();
923
924 return mSymbolFeatureIdMap.value( legendKey, QgsFeatureIds() );
925}
927{
929
930 if ( ( mSymbolFeatureCounted || mFeatureCounter ) && !( storeSymbolFids && mSymbolFeatureIdMap.isEmpty() ) )
931 return mFeatureCounter;
932
933 mSymbolFeatureCountMap.clear();
934 mSymbolFeatureIdMap.clear();
935
936 if ( !isValid() )
937 {
938 QgsDebugMsgLevel( u"invoked with invalid layer"_s, 3 );
939 return mFeatureCounter;
940 }
941 if ( !mDataProvider )
942 {
943 QgsDebugMsgLevel( u"invoked with null mDataProvider"_s, 3 );
944 return mFeatureCounter;
945 }
946 if ( !mRenderer )
947 {
948 QgsDebugMsgLevel( u"invoked with null mRenderer"_s, 3 );
949 return mFeatureCounter;
950 }
951
952 if ( !mFeatureCounter || ( storeSymbolFids && mSymbolFeatureIdMap.isEmpty() ) )
953 {
954 mFeatureCounter = new QgsVectorLayerFeatureCounter( this, QgsExpressionContext(), storeSymbolFids );
955 connect( mFeatureCounter, &QgsTask::taskCompleted, this, &QgsVectorLayer::onFeatureCounterCompleted, Qt::UniqueConnection );
956 connect( mFeatureCounter, &QgsTask::taskTerminated, this, &QgsVectorLayer::onFeatureCounterTerminated, Qt::UniqueConnection );
957 QgsApplication::taskManager()->addTask( mFeatureCounter );
958 }
959
960 return mFeatureCounter;
961}
962
964{
966
967 // do not update extent by default when trust project option is activated
968 if ( force || !mReadExtentFromXml || ( mReadExtentFromXml && mXmlExtent2D.isNull() && mXmlExtent3D.isNull() ) )
969 {
970 mValidExtent2D = false;
971 mValidExtent3D = false;
972 }
973}
974
976{
978
980 mValidExtent2D = true;
981}
982
984{
986
988 mValidExtent3D = true;
989}
990
991void QgsVectorLayer::updateDefaultValues( QgsFeatureId fid, QgsFeature feature, QgsExpressionContext *context )
992{
994
995 if ( !mDefaultValueOnUpdateFields.isEmpty() )
996 {
997 if ( !feature.isValid() )
998 feature = getFeature( fid );
999
1000 int size = mFields.size();
1001 for ( int idx : std::as_const( mDefaultValueOnUpdateFields ) )
1002 {
1003 if ( idx < 0 || idx >= size )
1004 continue;
1005 feature.setAttribute( idx, defaultValue( idx, feature, context ) );
1006 updateFeature( feature, true );
1007 }
1008 }
1009}
1010
1012{
1014
1015 QgsRectangle rect;
1016 rect.setNull();
1017
1018 if ( !isSpatial() )
1019 return rect;
1020
1021 // Don't do lazy extent if the layer is currently in edit mode
1022 if ( mLazyExtent2D && isEditable() )
1023 mLazyExtent2D = false;
1024
1025 if ( mDataProvider && mDataProvider->isValid() && ( mDataProvider->flags() & Qgis::DataProviderFlag::FastExtent2D ) )
1026 {
1027 // Provider has a trivial 2D extent calculation => always get extent from provider.
1028 // Things are nice and simple this way, e.g. we can always trust that this extent is
1029 // accurate and up to date.
1030 updateExtent( mDataProvider->extent() );
1031 mValidExtent2D = true;
1032 mLazyExtent2D = false;
1033 }
1034 else
1035 {
1036 if ( !mValidExtent2D && mLazyExtent2D && mReadExtentFromXml && !mXmlExtent2D.isNull() )
1037 {
1038 updateExtent( mXmlExtent2D );
1039 mValidExtent2D = true;
1040 mLazyExtent2D = false;
1041 }
1042
1043 if ( !mValidExtent2D && mLazyExtent2D && mDataProvider && mDataProvider->isValid() )
1044 {
1045 // store the extent
1046 updateExtent( mDataProvider->extent() );
1047 mValidExtent2D = true;
1048 mLazyExtent2D = false;
1049
1050 // show the extent
1051 QgsDebugMsgLevel( u"2D Extent of layer: %1"_s.arg( mExtent2D.toString() ), 3 );
1052 }
1053 }
1054
1055 if ( mValidExtent2D )
1056 return QgsMapLayer::extent();
1057
1058 if ( !isValid() || !mDataProvider )
1059 {
1060 QgsDebugMsgLevel( u"invoked with invalid layer or null mDataProvider"_s, 3 );
1061 return rect;
1062 }
1063
1064 if ( !mEditBuffer
1065 || ( !mDataProvider->transaction() && ( mEditBuffer->deletedFeatureIds().isEmpty() && mEditBuffer->changedGeometries().isEmpty() ) )
1066 || QgsDataSourceUri( mDataProvider->dataSourceUri() ).useEstimatedMetadata() )
1067 {
1068 mDataProvider->updateExtents();
1069
1070 // get the extent of the layer from the provider
1071 // but only when there are some features already
1072 if ( mDataProvider->featureCount() != 0 )
1073 {
1074 const QgsRectangle r = mDataProvider->extent();
1075 rect.combineExtentWith( r );
1076 }
1077
1078 if ( mEditBuffer && !mDataProvider->transaction() )
1079 {
1080 const auto addedFeatures = mEditBuffer->addedFeatures();
1081 for ( QgsFeatureMap::const_iterator it = addedFeatures.constBegin(); it != addedFeatures.constEnd(); ++it )
1082 {
1083 if ( it->hasGeometry() )
1084 {
1085 const QgsRectangle r = it->geometry().boundingBox();
1086 rect.combineExtentWith( r );
1087 }
1088 }
1089 }
1090 }
1091 else
1092 {
1093 QgsFeatureIterator fit = getFeatures( QgsFeatureRequest().setNoAttributes() );
1094
1095 QgsFeature fet;
1096 while ( fit.nextFeature( fet ) )
1097 {
1098 if ( fet.hasGeometry() && fet.geometry().type() != Qgis::GeometryType::Unknown )
1099 {
1100 const QgsRectangle bb = fet.geometry().boundingBox();
1101 rect.combineExtentWith( bb );
1102 }
1103 }
1104 }
1105
1106 if ( rect.xMinimum() > rect.xMaximum() && rect.yMinimum() > rect.yMaximum() )
1107 {
1108 // special case when there are no features in provider nor any added
1109 rect = QgsRectangle(); // use rectangle with zero coordinates
1110 }
1111
1112 updateExtent( rect );
1113 mValidExtent2D = true;
1114
1115 // Send this (hopefully) up the chain to the map canvas
1116 emit recalculateExtents();
1117
1118 return rect;
1119}
1120
1122{
1124
1125 // if data is 2D, redirect to 2D extend computation, and save it as 2D extent (in 3D bbox)
1126 if ( mDataProvider && mDataProvider->elevationProperties() && !mDataProvider->elevationProperties()->containsElevationData() )
1127 {
1128 return QgsBox3D( extent() );
1129 }
1130
1132 extent.setNull();
1133
1134 if ( !isSpatial() )
1135 return extent;
1136
1137 if ( mDataProvider && mDataProvider->isValid() && ( mDataProvider->flags() & Qgis::DataProviderFlag::FastExtent3D ) )
1138 {
1139 // Provider has a trivial 3D extent calculation => always get extent from provider.
1140 // Things are nice and simple this way, e.g. we can always trust that this extent is
1141 // accurate and up to date.
1142 updateExtent( mDataProvider->extent3D() );
1143 mValidExtent3D = true;
1144 mLazyExtent3D = false;
1145 }
1146 else
1147 {
1148 if ( !mValidExtent3D && mLazyExtent3D && mReadExtentFromXml && !mXmlExtent3D.isNull() )
1149 {
1150 updateExtent( mXmlExtent3D );
1151 mValidExtent3D = true;
1152 mLazyExtent3D = false;
1153 }
1154
1155 if ( !mValidExtent3D && mLazyExtent3D && mDataProvider && mDataProvider->isValid() )
1156 {
1157 // store the extent
1158 updateExtent( mDataProvider->extent3D() );
1159 mValidExtent3D = true;
1160 mLazyExtent3D = false;
1161
1162 // show the extent
1163 QgsDebugMsgLevel( u"3D Extent of layer: %1"_s.arg( mExtent3D.toString() ), 3 );
1164 }
1165 }
1166
1167 if ( mValidExtent3D )
1168 return QgsMapLayer::extent3D();
1169
1170 if ( !isValid() || !mDataProvider )
1171 {
1172 QgsDebugMsgLevel( u"invoked with invalid layer or null mDataProvider"_s, 3 );
1173 return extent;
1174 }
1175
1176 if ( !mEditBuffer
1177 || ( !mDataProvider->transaction() && ( mEditBuffer->deletedFeatureIds().isEmpty() && mEditBuffer->changedGeometries().isEmpty() ) )
1178 || QgsDataSourceUri( mDataProvider->dataSourceUri() ).useEstimatedMetadata() )
1179 {
1180 mDataProvider->updateExtents();
1181
1182 // get the extent of the layer from the provider
1183 // but only when there are some features already
1184 if ( mDataProvider->featureCount() != 0 )
1185 {
1186 const QgsBox3D ext = mDataProvider->extent3D();
1187 extent.combineWith( ext );
1188 }
1189
1190 if ( mEditBuffer && !mDataProvider->transaction() )
1191 {
1192 const auto addedFeatures = mEditBuffer->addedFeatures();
1193 for ( QgsFeatureMap::const_iterator it = addedFeatures.constBegin(); it != addedFeatures.constEnd(); ++it )
1194 {
1195 if ( it->hasGeometry() )
1196 {
1197 const QgsBox3D bbox = it->geometry().boundingBox3D();
1198 extent.combineWith( bbox );
1199 }
1200 }
1201 }
1202 }
1203 else
1204 {
1205 QgsFeatureIterator fit = getFeatures( QgsFeatureRequest().setNoAttributes() );
1206
1207 QgsFeature fet;
1208 while ( fit.nextFeature( fet ) )
1209 {
1210 if ( fet.hasGeometry() && fet.geometry().type() != Qgis::GeometryType::Unknown )
1211 {
1212 const QgsBox3D bb = fet.geometry().boundingBox3D();
1213 extent.combineWith( bb );
1214 }
1215 }
1216 }
1217
1218 if ( extent.xMinimum() > extent.xMaximum() && extent.yMinimum() > extent.yMaximum() && extent.zMinimum() > extent.zMaximum() )
1219 {
1220 // special case when there are no features in provider nor any added
1221 extent = QgsBox3D(); // use rectangle with zero coordinates
1222 }
1223
1224 updateExtent( extent );
1225 mValidExtent3D = true;
1226
1227 // Send this (hopefully) up the chain to the map canvas
1228 emit recalculateExtents();
1229
1230 return extent;
1231}
1232
1239
1246
1248{
1250
1251 if ( !isValid() || !mDataProvider )
1252 {
1253 QgsDebugMsgLevel( u"invoked with invalid layer or null mDataProvider"_s, 3 );
1254 return customProperty( u"storedSubsetString"_s ).toString();
1255 }
1256 return mDataProvider->subsetString();
1257}
1258
1259bool QgsVectorLayer::setSubsetString( const QString &subset )
1260{
1262
1263 if ( !isValid() || !mDataProvider )
1264 {
1265 QgsDebugMsgLevel( u"invoked with invalid layer or null mDataProvider or while editing"_s, 3 );
1266 setCustomProperty( u"storedSubsetString"_s, subset );
1267 return false;
1268 }
1269 else if ( mEditBuffer )
1270 {
1271 QgsDebugMsgLevel( u"invoked while editing"_s, 3 );
1272 return false;
1273 }
1274
1275 if ( subset == mDataProvider->subsetString() )
1276 return true;
1277
1278 bool res = mDataProvider->setSubsetString( subset );
1279
1280 // get the updated data source string from the provider
1281 mDataSource = mDataProvider->dataSourceUri();
1282 updateExtents();
1283 updateFields();
1284
1285 if ( res )
1286 {
1287 emit subsetStringChanged();
1289 }
1290
1291 return res;
1292}
1293
1295{
1296 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
1298
1299 if ( isValid()
1300 && mDataProvider
1301 && !mEditBuffer
1303 && ( mSimplifyMethod.simplifyHints() & simplifyHint )
1304 && renderContext.useRenderingOptimization() )
1305 {
1306 double maximumSimplificationScale = mSimplifyMethod.maximumScale();
1307
1308 // check maximum scale at which generalisation should be carried out
1309 return !( maximumSimplificationScale > 1 && renderContext.rendererScale() <= maximumSimplificationScale );
1310 }
1311 return false;
1312}
1313
1315{
1317
1318 return mConditionalStyles;
1319}
1320
1322{
1323 // non fatal for now -- the aggregate expression functions are not thread safe and call this
1325
1326 if ( !isValid() || !mDataProvider )
1327 return QgsFeatureIterator();
1328
1329 return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( new QgsVectorLayerFeatureSource( this ), true, request ) );
1330}
1331
1333{
1335
1336 QgsFeature feature;
1338 if ( feature.isValid() )
1339 return feature.geometry();
1340 else
1341 return QgsGeometry();
1342}
1343
1345{
1347
1348 if ( !isValid() || !mEditBuffer || !mDataProvider )
1349 return false;
1350
1351
1352 if ( mGeometryOptions->isActive() )
1353 {
1354 QgsGeometry geom = feature.geometry();
1355 mGeometryOptions->apply( geom );
1356 feature.setGeometry( geom );
1357 }
1358
1359 bool success = mEditBuffer->addFeature( feature );
1360
1361 if ( success && mJoinBuffer->containsJoins() )
1362 {
1363 success = mJoinBuffer->addFeature( feature );
1364 }
1365
1366 return success;
1367}
1368
1369bool QgsVectorLayer::updateFeature( QgsFeature &updatedFeature, bool skipDefaultValues )
1370{
1372
1373 if ( !mEditBuffer || !mDataProvider )
1374 {
1375 return false;
1376 }
1377
1378 QgsFeature currentFeature = getFeature( updatedFeature.id() );
1379 if ( currentFeature.isValid() )
1380 {
1381 bool hasChanged = false;
1382 bool hasError = false;
1383
1384 if ( ( updatedFeature.hasGeometry() || currentFeature.hasGeometry() ) && !updatedFeature.geometry().isExactlyEqual( currentFeature.geometry() ) )
1385 {
1386 QgsGeometry geometry = updatedFeature.geometry();
1387 if ( changeGeometry( updatedFeature.id(), geometry, true ) )
1388 {
1389 hasChanged = true;
1390 updatedFeature.setGeometry( geometry );
1391 }
1392 else
1393 {
1394 QgsDebugMsgLevel( u"geometry of feature %1 could not be changed."_s.arg( updatedFeature.id() ), 3 );
1395 }
1396 }
1397
1398 QgsAttributes fa = updatedFeature.attributes();
1399 QgsAttributes ca = currentFeature.attributes();
1400
1401 for ( int attr = 0; attr < fa.count(); ++attr )
1402 {
1403 if ( !qgsVariantEqual( fa.at( attr ), ca.at( attr ) ) )
1404 {
1405 if ( changeAttributeValue( updatedFeature.id(), attr, fa.at( attr ), ca.at( attr ), true ) )
1406 {
1407 hasChanged = true;
1408 }
1409 else
1410 {
1411 QgsDebugMsgLevel( u"attribute %1 of feature %2 could not be changed."_s.arg( attr ).arg( updatedFeature.id() ), 3 );
1412 hasError = true;
1413 }
1414 }
1415 }
1416 if ( hasChanged && !mDefaultValueOnUpdateFields.isEmpty() && !skipDefaultValues )
1417 updateDefaultValues( updatedFeature.id(), updatedFeature );
1418
1419 return !hasError;
1420 }
1421 else
1422 {
1423 QgsDebugMsgLevel( u"feature %1 could not be retrieved"_s.arg( updatedFeature.id() ), 3 );
1424 return false;
1425 }
1426}
1427
1428
1429bool QgsVectorLayer::insertVertex( double x, double y, QgsFeatureId atFeatureId, int beforeVertex )
1430{
1432
1433 if ( !isValid() || !mEditBuffer || !mDataProvider )
1434 return false;
1435
1436 QgsVectorLayerEditUtils utils( this );
1437 bool result = utils.insertVertex( x, y, atFeatureId, beforeVertex );
1438 if ( result )
1439 updateExtents();
1440 return result;
1441}
1442
1443
1444bool QgsVectorLayer::insertVertex( const QgsPoint &point, QgsFeatureId atFeatureId, int beforeVertex )
1445{
1447
1448 if ( !isValid() || !mEditBuffer || !mDataProvider )
1449 return false;
1450
1451 QgsVectorLayerEditUtils utils( this );
1452 bool result = utils.insertVertex( point, atFeatureId, beforeVertex );
1453 if ( result )
1454 updateExtents();
1455 return result;
1456}
1457
1458
1459bool QgsVectorLayer::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
1460{
1462
1463 if ( !isValid() || !mEditBuffer || !mDataProvider )
1464 return false;
1465
1466 QgsVectorLayerEditUtils utils( this );
1467 bool result = utils.moveVertex( x, y, atFeatureId, atVertex );
1468
1469 if ( result )
1470 updateExtents();
1471 return result;
1472}
1473
1474bool QgsVectorLayer::moveVertex( const QgsPoint &p, QgsFeatureId atFeatureId, int atVertex )
1475{
1477
1478 if ( !isValid() || !mEditBuffer || !mDataProvider )
1479 return false;
1480
1481 QgsVectorLayerEditUtils utils( this );
1482 bool result = utils.moveVertex( p, atFeatureId, atVertex );
1483
1484 if ( result )
1485 updateExtents();
1486 return result;
1487}
1488
1490{
1492
1493 if ( !isValid() || !mEditBuffer || !mDataProvider )
1495
1496 QgsVectorLayerEditUtils utils( this );
1497 Qgis::VectorEditResult result = utils.deleteVertex( featureId, vertex );
1498
1499 if ( result == Qgis::VectorEditResult::Success )
1500 updateExtents();
1501 return result;
1502}
1503
1505{
1507
1508 if ( !isValid() || !mEditBuffer || !mDataProvider )
1510
1511 QgsVectorLayerEditUtils utils( this );
1512 Qgis::VectorEditResult result = utils.deleteVertices( featureId, vertices );
1513
1515 updateExtents();
1516 return result;
1517}
1518
1520{
1522
1523 if ( !isValid() || !mDataProvider || !( mDataProvider->capabilities() & Qgis::VectorProviderCapability::DeleteFeatures ) )
1524 {
1525 return false;
1526 }
1527
1528 if ( !isEditable() )
1529 {
1530 return false;
1531 }
1532
1533 int deleted = 0;
1534 int count = mSelectedFeatureIds.size();
1535 // Make a copy since deleteFeature modifies mSelectedFeatureIds
1536 QgsFeatureIds selectedFeatures( mSelectedFeatureIds );
1537 for ( QgsFeatureId fid : std::as_const( selectedFeatures ) )
1538 {
1539 deleted += deleteFeature( fid, context ); // removes from selection
1540 }
1541
1543 updateExtents();
1544
1545 if ( deletedCount )
1546 {
1547 *deletedCount = deleted;
1548 }
1549
1550 return deleted == count;
1551}
1552
1553static const QgsPointSequence vectorPointXY2pointSequence( const QVector<QgsPointXY> &points )
1554{
1555 QgsPointSequence pts;
1556 pts.reserve( points.size() );
1557 QVector<QgsPointXY>::const_iterator it = points.constBegin();
1558 while ( it != points.constEnd() )
1559 {
1560 pts.append( QgsPoint( *it ) );
1561 ++it;
1562 }
1563 return pts;
1564}
1565Qgis::GeometryOperationResult QgsVectorLayer::addRing( const QVector<QgsPointXY> &ring, QgsFeatureId *featureId )
1566{
1568
1569 return addRing( vectorPointXY2pointSequence( ring ), featureId );
1570}
1571
1573{
1575
1576 if ( !isValid() || !mEditBuffer || !mDataProvider )
1578
1579 QgsVectorLayerEditUtils utils( this );
1581
1582 //first try with selected features
1583 if ( !mSelectedFeatureIds.isEmpty() )
1584 {
1585 result = utils.addRing( ring, mSelectedFeatureIds, featureId );
1586 }
1587
1589 {
1590 //try with all intersecting features
1591 result = utils.addRing( ring, QgsFeatureIds(), featureId );
1592 }
1593
1594 return result;
1595}
1596
1598{
1600
1601 if ( !isValid() || !mEditBuffer || !mDataProvider )
1602 {
1603 delete ring;
1605 }
1606
1607 if ( !ring )
1608 {
1610 }
1611
1612 if ( !ring->isClosed() )
1613 {
1614 delete ring;
1616 }
1617
1618 QgsVectorLayerEditUtils utils( this );
1620
1621 //first try with selected features
1622 if ( !mSelectedFeatureIds.isEmpty() )
1623 {
1624 result = utils.addRing( static_cast< QgsCurve * >( ring->clone() ), mSelectedFeatureIds, featureId );
1625 }
1626
1628 {
1629 //try with all intersecting features
1630 result = utils.addRing( static_cast< QgsCurve * >( ring->clone() ), QgsFeatureIds(), featureId );
1631 }
1632
1633 delete ring;
1634 return result;
1635}
1636
1638{
1640
1641 QgsPointSequence pts;
1642 pts.reserve( points.size() );
1643 for ( QList<QgsPointXY>::const_iterator it = points.constBegin(); it != points.constEnd(); ++it )
1644 {
1645 pts.append( QgsPoint( *it ) );
1646 }
1647 return addPart( pts );
1648}
1649
1651{
1653
1654 if ( !isValid() || !mEditBuffer || !mDataProvider )
1656
1657 //number of selected features must be 1
1658
1659 if ( mSelectedFeatureIds.empty() )
1660 {
1661 QgsDebugMsgLevel( u"Number of selected features <1"_s, 3 );
1663 }
1664 else if ( mSelectedFeatureIds.size() > 1 )
1665 {
1666 QgsDebugMsgLevel( u"Number of selected features >1"_s, 3 );
1668 }
1669
1670 QgsVectorLayerEditUtils utils( this );
1671 Qgis::GeometryOperationResult result = utils.addPart( points, *mSelectedFeatureIds.constBegin() );
1672
1674 updateExtents();
1675 return result;
1676}
1677
1679{
1681
1682 if ( !isValid() || !mEditBuffer || !mDataProvider )
1684
1685 //number of selected features must be 1
1686
1687 if ( mSelectedFeatureIds.empty() )
1688 {
1689 QgsDebugMsgLevel( u"Number of selected features <1"_s, 3 );
1691 }
1692 else if ( mSelectedFeatureIds.size() > 1 )
1693 {
1694 QgsDebugMsgLevel( u"Number of selected features >1"_s, 3 );
1696 }
1697
1698 QgsVectorLayerEditUtils utils( this );
1699 Qgis::GeometryOperationResult result = utils.addPart( ring, *mSelectedFeatureIds.constBegin() );
1700
1702 updateExtents();
1703 return result;
1704}
1705
1706// TODO QGIS 5.0 -- this should return Qgis::GeometryOperationResult, not int
1707int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double dy )
1708{
1710
1711 if ( !isValid() || !mEditBuffer || !mDataProvider )
1712 return static_cast< int >( Qgis::GeometryOperationResult::LayerNotEditable );
1713
1714 QgsVectorLayerEditUtils utils( this );
1715 int result = utils.translateFeature( featureId, dx, dy );
1716
1717 if ( result == static_cast< int >( Qgis::GeometryOperationResult::Success ) )
1718 updateExtents();
1719 return result;
1720}
1721
1722Qgis::GeometryOperationResult QgsVectorLayer::splitParts( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
1723{
1725
1726 return splitParts( vectorPointXY2pointSequence( splitLine ), topologicalEditing );
1727}
1728
1730{
1732
1733 if ( !isValid() || !mEditBuffer || !mDataProvider )
1735
1736 QgsVectorLayerEditUtils utils( this );
1737 return utils.splitParts( splitLine, topologicalEditing );
1738}
1739
1740Qgis::GeometryOperationResult QgsVectorLayer::splitFeatures( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
1741{
1743
1744 return splitFeatures( vectorPointXY2pointSequence( splitLine ), topologicalEditing );
1745}
1746
1748{
1750
1751 QgsLineString splitLineString( splitLine );
1752 QgsPointSequence topologyTestPoints;
1753 bool preserveCircular = false;
1754 return splitFeatures( &splitLineString, topologyTestPoints, preserveCircular, topologicalEditing );
1755}
1756
1757Qgis::GeometryOperationResult QgsVectorLayer::splitFeatures( const QgsCurve *curve, QgsPointSequence &topologyTestPoints, bool preserveCircular, bool topologicalEditing )
1758{
1760
1761 if ( !isValid() || !mEditBuffer || !mDataProvider )
1763
1764 QgsVectorLayerEditUtils utils( this );
1765 return utils.splitFeatures( curve, topologyTestPoints, preserveCircular, topologicalEditing );
1766}
1767
1769{
1771
1772 if ( !isValid() || !mEditBuffer || !mDataProvider )
1773 return -1;
1774
1775 QgsVectorLayerEditUtils utils( this );
1776 return utils.addTopologicalPoints( geom );
1777}
1778
1785
1787{
1789
1790 if ( !isValid() || !mEditBuffer || !mDataProvider )
1791 return -1;
1792
1793 QgsVectorLayerEditUtils utils( this );
1794 return utils.addTopologicalPoints( p );
1795}
1796
1798{
1800
1801 if ( !mValid || !mEditBuffer || !mDataProvider )
1802 return -1;
1803
1804 QgsVectorLayerEditUtils utils( this );
1805 return utils.addTopologicalPoints( ps );
1806}
1807
1809{
1811
1812 if ( mLabeling == labeling )
1813 return;
1814
1815 delete mLabeling;
1816 mLabeling = labeling;
1817}
1818
1820{
1822
1823 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
1824 return project()->startEditing( this );
1825
1826 if ( !isValid() || !mDataProvider )
1827 {
1828 return false;
1829 }
1830
1831 // allow editing if provider supports any of the capabilities
1832 if ( !supportsEditing() )
1833 {
1834 return false;
1835 }
1836
1837 if ( mEditBuffer )
1838 {
1839 // editing already underway
1840 return false;
1841 }
1842
1843 mDataProvider->enterUpdateMode();
1844
1845 emit beforeEditingStarted();
1846
1847 createEditBuffer();
1848
1849 updateFields();
1850
1851 emit editingStarted();
1852
1853 return true;
1854}
1855
1857{
1859
1860 if ( mDataProvider )
1861 mDataProvider->setTransformContext( transformContext );
1862}
1863
1865{
1867
1868 return mDataProvider ? mDataProvider->hasSpatialIndex() : Qgis::SpatialIndexPresence::Unknown;
1869}
1870
1872{
1874
1875 if ( mRenderer )
1876 if ( !mRenderer->accept( visitor ) )
1877 return false;
1878
1879 if ( mLabeling )
1880 if ( !mLabeling->accept( visitor ) )
1881 return false;
1882
1883 return true;
1884}
1885
1887{
1889
1890 if ( mActions )
1891 {
1892 const QList<QgsAction> actions = mActions->actions();
1893 for ( const QgsAction &action : actions )
1894 {
1895 if ( action.command().isEmpty() )
1896 {
1897 continue;
1898 }
1899
1900 switch ( action.type() )
1901 {
1906 {
1907 QgsEmbeddedScriptEntity entity( Qgis::EmbeddedScriptType::Action, tr( "%1: Action ’%2’" ).arg( name(), action.name() ), action.command() );
1908 if ( !visitor->visitEmbeddedScript( entity, context ) )
1909 {
1910 return false;
1911 }
1912 break;
1913 }
1914
1919 {
1920 break;
1921 }
1922 }
1923 }
1924 }
1925
1926 QString initCode;
1927 switch ( mEditFormConfig.initCodeSource() )
1928 {
1930 {
1931 initCode = u"# Calling function ’%1’\n\n%2"_s.arg( mEditFormConfig.initFunction(), mEditFormConfig.initCode() );
1932 break;
1933 }
1934
1936 {
1937 QFile *inputFile = QgsApplication::networkContentFetcherRegistry()->localFile( mEditFormConfig.initFilePath() );
1938 if ( inputFile && inputFile->open( QFile::ReadOnly ) )
1939 {
1940 // Read it into a string
1941 QTextStream inf( inputFile );
1942 initCode = inf.readAll();
1943 inputFile->close();
1944 initCode = u"# Calling function ’%1’\n# From file %2\n\n"_s.arg( mEditFormConfig.initFunction(), mEditFormConfig.initFilePath() ) + initCode;
1945 }
1946 break;
1947 }
1948
1950 {
1951 initCode = u"# Calling function ’%1’\n# From environment\n\n"_s.arg( mEditFormConfig.initFunction() );
1952 break;
1953 }
1954
1956 {
1957 break;
1958 }
1959 }
1960
1961 if ( !initCode.isEmpty() )
1962 {
1963 QgsEmbeddedScriptEntity entity( Qgis::EmbeddedScriptType::FormInitCode, tr( "%1: Attribute form init code" ).arg( name() ), initCode );
1964 if ( !visitor->visitEmbeddedScript( entity, context ) )
1965 {
1966 return false;
1967 }
1968 }
1969
1970 return true;
1971}
1972
1973bool QgsVectorLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1974{
1976
1977 QgsDebugMsgLevel( u"Datasource in QgsVectorLayer::readXml: %1"_s.arg( mDataSource.toLocal8Bit().data() ), 3 );
1978
1979 //process provider key
1980 QDomNode pkeyNode = layer_node.namedItem( u"provider"_s );
1981
1982 if ( pkeyNode.isNull() )
1983 {
1984 mProviderKey.clear();
1985 }
1986 else
1987 {
1988 QDomElement pkeyElt = pkeyNode.toElement();
1989 mProviderKey = pkeyElt.text();
1990 }
1991
1992 // determine type of vector layer
1993 if ( !mProviderKey.isNull() )
1994 {
1995 // if the provider string isn't empty, then we successfully
1996 // got the stored provider
1997 }
1998 else if ( mDataSource.contains( "dbname="_L1 ) )
1999 {
2000 mProviderKey = u"postgres"_s;
2001 }
2002 else
2003 {
2004 mProviderKey = u"ogr"_s;
2005 }
2006
2007 const QDomElement elem = layer_node.toElement();
2009
2010 mDataSourceReadOnly = mReadFlags & QgsMapLayer::FlagForceReadOnly;
2012
2013 if ( ( mReadFlags & QgsMapLayer::FlagDontResolveLayers ) || !setDataProvider( mProviderKey, options, flags ) )
2014 {
2016 {
2017 QgsDebugError( u"Could not set data provider for layer %1"_s.arg( publicSource() ) );
2018 }
2019
2020 // for invalid layer sources, we fallback to stored wkbType if available
2021 if ( elem.hasAttribute( u"wkbType"_s ) )
2022 mWkbType = qgsEnumKeyToValue( elem.attribute( u"wkbType"_s ), mWkbType );
2023 }
2024
2025 QDomElement pkeyElem = pkeyNode.toElement();
2026 if ( !pkeyElem.isNull() )
2027 {
2028 QString encodingString = pkeyElem.attribute( u"encoding"_s );
2029 if ( mDataProvider && !encodingString.isEmpty() )
2030 {
2031 mDataProvider->setEncoding( encodingString );
2032 }
2033 }
2034
2035 // load vector joins - does not resolve references to layers yet
2036 mJoinBuffer->readXml( layer_node );
2037
2038 updateFields();
2039
2040 // If style doesn't include a legend, we'll need to make a default one later...
2041 mSetLegendFromStyle = false;
2042
2043 QString errorMsg;
2044 if ( !readSymbology( layer_node, errorMsg, context ) )
2045 {
2046 return false;
2047 }
2048
2049 readStyleManager( layer_node );
2050
2051 QDomNode depsNode = layer_node.namedItem( u"dataDependencies"_s );
2052 QDomNodeList depsNodes = depsNode.childNodes();
2053 QSet<QgsMapLayerDependency> sources;
2054 for ( int i = 0; i < depsNodes.count(); i++ )
2055 {
2056 QString source = depsNodes.at( i ).toElement().attribute( u"id"_s );
2057 sources << QgsMapLayerDependency( source );
2058 }
2059 setDependencies( sources );
2060
2061 if ( !mSetLegendFromStyle )
2063
2064 // read extent
2066 {
2067 mReadExtentFromXml = true;
2068 }
2069 if ( mReadExtentFromXml )
2070 {
2071 const QDomNode extentNode = layer_node.namedItem( u"extent"_s );
2072 if ( !extentNode.isNull() )
2073 {
2074 mXmlExtent2D = QgsXmlUtils::readRectangle( extentNode.toElement() );
2075 }
2076 const QDomNode extent3DNode = layer_node.namedItem( u"extent3D"_s );
2077 if ( !extent3DNode.isNull() )
2078 {
2079 mXmlExtent3D = QgsXmlUtils::readBox3D( extent3DNode.toElement() );
2080 }
2081 }
2082
2083 // auxiliary layer
2084 const QDomNode asNode = layer_node.namedItem( u"auxiliaryLayer"_s );
2085 const QDomElement asElem = asNode.toElement();
2086 if ( !asElem.isNull() )
2087 {
2088 mAuxiliaryLayerKey = asElem.attribute( u"key"_s );
2089 }
2090
2091 // QGIS Server WMS Dimensions
2092 mServerProperties->readXml( layer_node );
2093
2094 return isValid(); // should be true if read successfully
2095
2096} // void QgsVectorLayer::readXml
2097
2098
2099void QgsVectorLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
2100{
2102
2103 Qgis::GeometryType geomType = geometryType();
2104
2105 mDataSource = dataSource;
2106 setName( baseName );
2107 setDataProvider( provider, options, flags );
2108
2109 if ( !isValid() )
2110 {
2111 return;
2112 }
2113
2114 // Always set crs
2116
2117 bool loadDefaultStyleFlag = false;
2119 {
2120 loadDefaultStyleFlag = true;
2121 }
2122
2123 // reset style if loading default style, style is missing, or geometry type is has changed (and layer is valid)
2124 if ( !renderer() || !legend() || ( isValid() && geomType != geometryType() ) || loadDefaultStyleFlag )
2125 {
2126 std::unique_ptr< QgsScopedRuntimeProfile > profile;
2127 if ( QgsApplication::profiler()->groupIsActive( u"projectload"_s ) )
2128 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Load layer style" ), u"projectload"_s );
2129
2130 bool defaultLoadedFlag = false;
2131
2132 // defer style changed signal until we've set the renderer, labeling, everything.
2133 // we don't want multiple signals!
2134 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
2135
2136 // need to check whether the default style included a legend, and if not, we need to make a default legend
2137 // later...
2138 mSetLegendFromStyle = false;
2139
2140 // first check if there is a default style / propertysheet defined
2141 // for this layer and if so apply it
2142 // this should take precedence over all
2143 if ( !defaultLoadedFlag && loadDefaultStyleFlag )
2144 {
2145 loadDefaultStyle( defaultLoadedFlag );
2146 }
2147
2148 if ( loadDefaultStyleFlag && !defaultLoadedFlag && isSpatial() && mDataProvider->capabilities() & Qgis::VectorProviderCapability::CreateRenderer )
2149 {
2150 // if we didn't load a default style for this layer, try to create a renderer directly from the data provider
2151 std::unique_ptr< QgsFeatureRenderer > defaultRenderer( mDataProvider->createRenderer() );
2152 if ( defaultRenderer )
2153 {
2154 defaultLoadedFlag = true;
2155 setRenderer( defaultRenderer.release() );
2156 }
2157 }
2158
2159 // if the default style failed to load or was disabled use some very basic defaults
2160 if ( !defaultLoadedFlag )
2161 {
2162 // add single symbol renderer for spatial layers
2164 }
2165
2166 if ( !mSetLegendFromStyle )
2168
2169 if ( mDataProvider->capabilities() & Qgis::VectorProviderCapability::CreateLabeling )
2170 {
2171 std::unique_ptr< QgsAbstractVectorLayerLabeling > defaultLabeling( mDataProvider->createLabeling() );
2172 if ( defaultLabeling )
2173 {
2174 setLabeling( defaultLabeling.release() );
2175 setLabelsEnabled( true );
2176 }
2177 }
2178
2179 styleChangedSignalBlocker.release();
2181 }
2182}
2183
2184QString QgsVectorLayer::loadDefaultStyle( bool &resultFlag )
2185{
2187
2188 // first try to load a user-defined default style - this should always take precedence
2189 QString styleXml = QgsMapLayer::loadDefaultStyle( resultFlag );
2190
2191 if ( resultFlag )
2192 {
2193 // Try to load all stored styles from DB
2194 if ( mLoadAllStoredStyle && mDataProvider && mDataProvider->styleStorageCapabilities().testFlag( Qgis::ProviderStyleStorageCapability::LoadFromDatabase ) )
2195 {
2196 QStringList ids, names, descriptions;
2197 QString errorMessage;
2198 // Get the number of styles related to current layer.
2199 const int relatedStylesCount { listStylesInDatabase( ids, names, descriptions, errorMessage ) };
2200 Q_ASSERT( ids.count() == names.count() );
2201 const QString currentStyleName { mStyleManager->currentStyle() };
2202 for ( int i = 0; i < relatedStylesCount; ++i )
2203 {
2204 if ( names.at( i ) == currentStyleName )
2205 {
2206 continue;
2207 }
2208 errorMessage.clear();
2209 const QString styleXml { getStyleFromDatabase( ids.at( i ), errorMessage ) };
2210 if ( !styleXml.isEmpty() && errorMessage.isEmpty() )
2211 {
2212 mStyleManager->addStyle( names.at( i ), QgsMapLayerStyle( styleXml ) );
2213 }
2214 else
2215 {
2216 QgsDebugMsgLevel( u"Error retrieving style %1 from DB: %2"_s.arg( ids.at( i ), errorMessage ), 2 );
2217 }
2218 }
2219 }
2220 return styleXml;
2221 }
2222
2223 if ( isSpatial() && mDataProvider->capabilities() & Qgis::VectorProviderCapability::CreateRenderer )
2224 {
2225 // otherwise try to create a renderer directly from the data provider
2226 std::unique_ptr< QgsFeatureRenderer > defaultRenderer( mDataProvider->createRenderer() );
2227 if ( defaultRenderer )
2228 {
2229 resultFlag = true;
2230 setRenderer( defaultRenderer.release() );
2231 return QString();
2232 }
2233 }
2234
2235 return QString();
2236}
2237
2238bool QgsVectorLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
2239{
2241
2242 mProviderKey = provider;
2243 delete mDataProvider;
2244
2245 // For Postgres provider primary key unicity is tested at construction time,
2246 // so it has to be set before initializing the provider,
2247 // this manipulation is necessary to preserve default behavior when
2248 // "trust layer metadata" project level option is set and checkPrimaryKeyUnicity
2249 // was not explicitly passed in the uri
2250 if ( provider.compare( "postgres"_L1 ) == 0 )
2251 {
2252 const QString checkUnicityKey { u"checkPrimaryKeyUnicity"_s };
2253 QgsDataSourceUri uri( mDataSource );
2254 if ( !uri.hasParam( checkUnicityKey ) )
2255 {
2256 uri.setParam( checkUnicityKey, mReadExtentFromXml ? "0" : "1" );
2257 mDataSource = uri.uri( false );
2258 }
2259 }
2260
2261 std::unique_ptr< QgsScopedRuntimeProfile > profile;
2262 if ( QgsApplication::profiler()->groupIsActive( u"projectload"_s ) )
2263 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), u"projectload"_s );
2264
2265 if ( mPreloadedProvider )
2266 {
2267 QgsDebugMsgLevel( u"Attaching map layer %1 to preloaded data provider. Provider belongs to thread %2"_s.arg( id(), QgsThreadingUtils::threadDescription( mPreloadedProvider->thread() ) ), 2 );
2268 mDataProvider = qobject_cast< QgsVectorDataProvider * >( mPreloadedProvider.release() );
2269 }
2270 else
2271 {
2272 mDataProvider = qobject_cast<QgsVectorDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, mDataSource, options, flags ) );
2273 }
2274
2275 if ( !mDataProvider )
2276 {
2277 setValid( false );
2278 QgsDebugMsgLevel( u"Unable to get data provider"_s, 2 );
2279 return false;
2280 }
2281
2282 mDataProvider->setParent( this );
2283 connect( mDataProvider, &QgsVectorDataProvider::raiseError, this, &QgsVectorLayer::raiseError );
2284
2285 QgsDebugMsgLevel( u"Instantiated the data provider plugin"_s, 2 );
2286
2287 setValid( mDataProvider->isValid() );
2288 if ( !isValid() )
2289 {
2290 QgsDebugMsgLevel( u"Invalid provider plugin %1"_s.arg( QString( mDataSource.toUtf8() ) ), 2 );
2291 return false;
2292 }
2293
2294 if ( profile )
2295 profile->switchTask( tr( "Read layer metadata" ) );
2296 if ( mDataProvider->capabilities() & Qgis::VectorProviderCapability::ReadLayerMetadata )
2297 {
2298 // we combine the provider metadata with the layer's existing metadata, so as not to reset any user customizations to the metadata
2299 // back to the default if a layer's data source is changed
2300 QgsLayerMetadata newMetadata = mDataProvider->layerMetadata();
2301 // this overwrites the provider metadata with any properties which are non-empty from the existing layer metadata
2302 newMetadata.combine( &mMetadata );
2303
2304 setMetadata( newMetadata );
2305 QgsDebugMsgLevel( u"Set Data provider QgsLayerMetadata identifier[%1]"_s.arg( metadata().identifier() ), 4 );
2306 }
2307
2308 // TODO: Check if the provider has the capability to send fullExtentCalculated
2309 connect( mDataProvider, &QgsVectorDataProvider::fullExtentCalculated, this, [this] { updateExtents(); } );
2310
2311 // get and store the feature type
2312 mWkbType = mDataProvider->wkbType();
2313
2314 // before we update the layer fields from the provider, we first copy any default set alias and
2315 // editor widget config from the data provider fields, if present
2316 const QgsFields providerFields = mDataProvider->fields();
2317 for ( const QgsField &field : providerFields )
2318 {
2319 // we only copy defaults from the provider if we aren't overriding any configuration made in the layer
2320 if ( !field.editorWidgetSetup().isNull() && mFieldWidgetSetups.value( field.name() ).isNull() )
2321 {
2322 mFieldWidgetSetups[field.name()] = field.editorWidgetSetup();
2323 }
2324 if ( !field.alias().isEmpty() && mAttributeAliasMap.value( field.name() ).isEmpty() )
2325 {
2326 mAttributeAliasMap[field.name()] = field.alias();
2327 }
2328 if ( !mAttributeSplitPolicy.contains( field.name() ) )
2329 {
2330 mAttributeSplitPolicy[field.name()] = field.splitPolicy();
2331 }
2332 if ( !mAttributeDuplicatePolicy.contains( field.name() ) )
2333 {
2334 mAttributeDuplicatePolicy[field.name()] = field.duplicatePolicy();
2335 }
2336 if ( !mAttributeMergePolicy.contains( field.name() ) )
2337 {
2338 mAttributeMergePolicy[field.name()] = field.mergePolicy();
2339 }
2340 }
2341
2342 if ( profile )
2343 profile->switchTask( tr( "Read layer fields" ) );
2344 updateFields();
2345
2346 if ( mProviderKey == "postgres"_L1 )
2347 {
2348 // update datasource from data provider computed one
2349 mDataSource = mDataProvider->dataSourceUri( false );
2350
2351 QgsDebugMsgLevel( u"Beautifying layer name %1"_s.arg( name() ), 3 );
2352
2353 // adjust the display name for postgres layers
2354 const thread_local QRegularExpression reg( R"lit("[^"]+"\."([^"] + )"( \‍([^)]+\))?)lit" );
2355 const QRegularExpressionMatch match = reg.match( name() );
2356 if ( match.hasMatch() )
2357 {
2358 QStringList stuff = match.capturedTexts();
2359 QString lName = stuff[1];
2360
2361 const QMap<QString, QgsMapLayer *> &layers = QgsProject::instance()->mapLayers(); // skip-keyword-check
2362
2363 QMap<QString, QgsMapLayer *>::const_iterator it;
2364 for ( it = layers.constBegin(); it != layers.constEnd() && ( *it )->name() != lName; ++it )
2365 ;
2366
2367 if ( it != layers.constEnd() && stuff.size() > 2 )
2368 {
2369 lName += '.' + stuff[2].mid( 2, stuff[2].length() - 3 );
2370 }
2371
2372 if ( !lName.isEmpty() )
2373 setName( lName );
2374 }
2375 QgsDebugMsgLevel( u"Beautified layer name %1"_s.arg( name() ), 3 );
2376 }
2377 else if ( mProviderKey == "osm"_L1 )
2378 {
2379 // make sure that the "observer" has been removed from URI to avoid crashes
2380 mDataSource = mDataProvider->dataSourceUri();
2381 }
2382 else if ( provider == "ogr"_L1 )
2383 {
2384 // make sure that the /vsigzip or /vsizip is added to uri, if applicable
2385 mDataSource = mDataProvider->dataSourceUri();
2386 if ( mDataSource.right( 10 ) == "|layerid=0"_L1 )
2387 mDataSource.chop( 10 );
2388 }
2389 else if ( provider == "memory"_L1 )
2390 {
2391 // required so that source differs between memory layers
2392 mDataSource = mDataSource + u"&uid=%1"_s.arg( QUuid::createUuid().toString() );
2393 }
2394 else if ( provider == "hana"_L1 )
2395 {
2396 // update datasource from data provider computed one
2397 mDataSource = mDataProvider->dataSourceUri( false );
2398 }
2399
2400 connect( mDataProvider, &QgsVectorDataProvider::dataChanged, this, &QgsVectorLayer::emitDataChanged );
2402
2403 return true;
2404} // QgsVectorLayer:: setDataProvider
2405
2406
2407/* virtual */
2408bool QgsVectorLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
2409{
2411
2412 // first get the layer element so that we can append the type attribute
2413
2414 QDomElement mapLayerNode = layer_node.toElement();
2415
2416 if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) )
2417 {
2418 QgsDebugMsgLevel( u"can't find <maplayer>"_s, 2 );
2419 return false;
2420 }
2421
2422 mapLayerNode.setAttribute( u"type"_s, QgsMapLayerFactory::typeToString( Qgis::LayerType::Vector ) );
2423
2424 // set the geometry type
2425 mapLayerNode.setAttribute( u"geometry"_s, QgsWkbTypes::geometryDisplayString( geometryType() ) );
2426 mapLayerNode.setAttribute( u"wkbType"_s, qgsEnumValueToKey( wkbType() ) );
2427
2428 // add provider node
2429 if ( mDataProvider )
2430 {
2431 QDomElement provider = document.createElement( u"provider"_s );
2432 provider.setAttribute( u"encoding"_s, mDataProvider->encoding() );
2433 QDomText providerText = document.createTextNode( providerType() );
2434 provider.appendChild( providerText );
2435 layer_node.appendChild( provider );
2436 }
2437
2438 //save joins
2439 mJoinBuffer->writeXml( layer_node, document );
2440
2441 // dependencies
2442 QDomElement dependenciesElement = document.createElement( u"layerDependencies"_s );
2443 const auto constDependencies = dependencies();
2444 for ( const QgsMapLayerDependency &dep : constDependencies )
2445 {
2447 continue;
2448 QDomElement depElem = document.createElement( u"layer"_s );
2449 depElem.setAttribute( u"id"_s, dep.layerId() );
2450 dependenciesElement.appendChild( depElem );
2451 }
2452 layer_node.appendChild( dependenciesElement );
2453
2454 // change dependencies
2455 QDomElement dataDependenciesElement = document.createElement( u"dataDependencies"_s );
2456 for ( const QgsMapLayerDependency &dep : constDependencies )
2457 {
2458 if ( dep.type() != QgsMapLayerDependency::DataDependency )
2459 continue;
2460 QDomElement depElem = document.createElement( u"layer"_s );
2461 depElem.setAttribute( u"id"_s, dep.layerId() );
2462 dataDependenciesElement.appendChild( depElem );
2463 }
2464 layer_node.appendChild( dataDependenciesElement );
2465
2466 // save expression fields
2467 mExpressionFieldBuffer->writeXml( layer_node, document );
2468
2469 writeStyleManager( layer_node, document );
2470
2471 // auxiliary layer
2472 QDomElement asElem = document.createElement( u"auxiliaryLayer"_s );
2473 if ( mAuxiliaryLayer )
2474 {
2475 const QString pkField = mAuxiliaryLayer->joinInfo().targetFieldName();
2476 asElem.setAttribute( u"key"_s, pkField );
2477 }
2478 layer_node.appendChild( asElem );
2479
2480 // renderer specific settings
2481 QString errorMsg;
2482 return writeSymbology( layer_node, document, errorMsg, context );
2483}
2484
2485QString QgsVectorLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
2486{
2488
2489 if ( providerType() == "memory"_L1 )
2490 {
2491 // Refetch the source from the provider, because adding fields actually changes the source for this provider.
2492 return dataProvider()->dataSourceUri();
2493 }
2494
2496}
2497
2498QString QgsVectorLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
2499{
2501
2502 return QgsProviderRegistry::instance()->relativeToAbsoluteUri( provider, source, context );
2503}
2504
2505
2513
2514
2515bool QgsVectorLayer::readSymbology( const QDomNode &layerNode, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
2516{
2518
2519 if ( categories.testFlag( Fields ) )
2520 {
2521 if ( !mExpressionFieldBuffer )
2522 mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
2523 mExpressionFieldBuffer->readXml( layerNode );
2524
2525 updateFields();
2526 }
2527
2528 if ( categories.testFlag( Relations ) )
2529 {
2530 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Relations" ) );
2531
2532 // Restore referenced layers: relations where "this" is the child layer (the referencing part, that holds the FK)
2533 QDomNodeList referencedLayersNodeList = layerNode.toElement().elementsByTagName( u"referencedLayers"_s );
2534 if ( referencedLayersNodeList.size() > 0 )
2535 {
2536 const QDomNodeList relationNodes { referencedLayersNodeList.at( 0 ).childNodes() };
2537 for ( int i = 0; i < relationNodes.length(); ++i )
2538 {
2539 const QDomElement relationElement = relationNodes.at( i ).toElement();
2540
2541 mWeakRelations.push_back( QgsWeakRelation::readXml( this, QgsWeakRelation::Referencing, relationElement, context.pathResolver() ) );
2542 }
2543 }
2544
2545 // Restore referencing layers: relations where "this" is the parent layer (the referenced part where the FK points to)
2546 QDomNodeList referencingLayersNodeList = layerNode.toElement().elementsByTagName( u"referencingLayers"_s );
2547 if ( referencingLayersNodeList.size() > 0 )
2548 {
2549 const QDomNodeList relationNodes { referencingLayersNodeList.at( 0 ).childNodes() };
2550 for ( int i = 0; i < relationNodes.length(); ++i )
2551 {
2552 const QDomElement relationElement = relationNodes.at( i ).toElement();
2553 mWeakRelations.push_back( QgsWeakRelation::readXml( this, QgsWeakRelation::Referenced, relationElement, context.pathResolver() ) );
2554 }
2555 }
2556 }
2557
2558 QDomElement layerElement = layerNode.toElement();
2559
2560 readCommonStyle( layerElement, context, categories );
2561
2562 readStyle( layerNode, errorMessage, context, categories );
2563
2564 if ( categories.testFlag( MapTips ) )
2565 {
2566 QDomElement mapTipElem = layerNode.namedItem( u"mapTip"_s ).toElement();
2567 setMapTipTemplate( mapTipElem.text() );
2568 setMapTipsEnabled( mapTipElem.attribute( u"enabled"_s, u"1"_s ).toInt() == 1 );
2569 }
2570
2571 if ( categories.testFlag( LayerConfiguration ) )
2572 mDisplayExpression = layerNode.namedItem( u"previewExpression"_s ).toElement().text();
2573
2574 // Try to migrate pre QGIS 3.0 display field property
2575 QString displayField = layerNode.namedItem( u"displayfield"_s ).toElement().text();
2576 if ( mFields.lookupField( displayField ) < 0 )
2577 {
2578 // if it's not a field, it's a maptip
2579 if ( mMapTipTemplate.isEmpty() && categories.testFlag( MapTips ) )
2580 mMapTipTemplate = displayField;
2581 }
2582 else
2583 {
2584 if ( mDisplayExpression.isEmpty() && categories.testFlag( LayerConfiguration ) )
2585 mDisplayExpression = QgsExpression::quotedColumnRef( displayField );
2586 }
2587
2588 // process the attribute actions
2589 if ( categories.testFlag( Actions ) )
2590 mActions->readXml( layerNode, context );
2591
2592 if ( categories.testFlag( Fields ) )
2593 {
2594 // IMPORTANT - we don't clear mAttributeAliasMap here, as it may contain aliases which are coming direct
2595 // from the data provider. Instead we leave any existing aliases and only overwrite them if the style
2596 // has a specific value for that field's alias
2597 QDomNode aliasesNode = layerNode.namedItem( u"aliases"_s );
2598 if ( !aliasesNode.isNull() )
2599 {
2600 QDomElement aliasElem;
2601
2602 QDomNodeList aliasNodeList = aliasesNode.toElement().elementsByTagName( u"alias"_s );
2603 for ( int i = 0; i < aliasNodeList.size(); ++i )
2604 {
2605 aliasElem = aliasNodeList.at( i ).toElement();
2606
2607 QString field;
2608 if ( aliasElem.hasAttribute( u"field"_s ) )
2609 {
2610 field = aliasElem.attribute( u"field"_s );
2611 }
2612 else
2613 {
2614 int index = aliasElem.attribute( u"index"_s ).toInt();
2615
2616 if ( index >= 0 && index < fields().count() )
2617 field = fields().at( index ).name();
2618 }
2619
2620 QString alias;
2621
2622 if ( !aliasElem.attribute( u"name"_s ).isEmpty() )
2623 {
2624 //if it has alias
2625 alias = context.projectTranslator()->translate( u"project:layers:%1:fieldaliases"_s.arg( layerNode.namedItem( u"id"_s ).toElement().text() ), aliasElem.attribute( u"name"_s ) );
2626 QgsDebugMsgLevel( "context" + u"project:layers:%1:fieldaliases"_s.arg( layerNode.namedItem( u"id"_s ).toElement().text() ) + " source " + aliasElem.attribute( u"name"_s ), 3 );
2627 }
2628 else
2629 {
2630 //if it has no alias, it should be the fields translation
2631 alias = context.projectTranslator()->translate( u"project:layers:%1:fieldaliases"_s.arg( layerNode.namedItem( u"id"_s ).toElement().text() ), field );
2632 QgsDebugMsgLevel( "context" + u"project:layers:%1:fieldaliases"_s.arg( layerNode.namedItem( u"id"_s ).toElement().text() ) + " source " + field, 3 );
2633 //if it gets the exact field value, there has been no translation (or not even translation loaded) - so no alias should be generated;
2634 if ( alias == aliasElem.attribute( u"field"_s ) )
2635 alias.clear();
2636 }
2637
2638 QgsDebugMsgLevel( "field " + field + " origalias " + aliasElem.attribute( u"name"_s ) + " trans " + alias, 3 );
2639 mAttributeAliasMap.insert( field, alias );
2640 }
2641 }
2642
2643 // custom comments
2644 // mAttributeCustomCommentMap is cleared, because when a custom comment is null the provider comment should be considered
2645 mAttributeCustomCommentMap.clear();
2646 QDomNode customCommentsNode = layerNode.namedItem( u"customComments"_s );
2647 if ( !customCommentsNode.isNull() )
2648 {
2649 QDomElement customCommentEntryElem;
2650
2651 QDomNodeList customCommentNodeList = customCommentsNode.toElement().elementsByTagName( u"customComment"_s );
2652 for ( int i = 0; i < customCommentNodeList.size(); ++i )
2653 {
2654 customCommentEntryElem = customCommentNodeList.at( i ).toElement();
2655
2656 const QString field = customCommentEntryElem.attribute( u"field"_s );
2657
2658 //empty values are important as well (to override provider comments with nothing)
2659 const QString customComment = customCommentEntryElem.attribute( u"value"_s );
2660
2661 if ( fields().lookupField( field ) < 0 )
2662 {
2663 QgsDebugMsgLevel( u"Warning: Field %1 not found in layer %2 to load custom comment from setting "_s.arg( field, name() ), 2 );
2664 continue;
2665 }
2666 mAttributeCustomCommentMap.insert( field, customComment );
2667 }
2668 }
2669
2670 // IMPORTANT - we don't clear mAttributeSplitPolicy here, as it may contain policies which are coming direct
2671 // from the data provider. Instead we leave any existing policies and only overwrite them if the style
2672 // has a specific value for that field's policy
2673 const QDomNode splitPoliciesNode = layerNode.namedItem( u"splitPolicies"_s );
2674 if ( !splitPoliciesNode.isNull() )
2675 {
2676 const QDomNodeList splitPolicyNodeList = splitPoliciesNode.toElement().elementsByTagName( u"policy"_s );
2677 for ( int i = 0; i < splitPolicyNodeList.size(); ++i )
2678 {
2679 const QDomElement splitPolicyElem = splitPolicyNodeList.at( i ).toElement();
2680 const QString field = splitPolicyElem.attribute( u"field"_s );
2681 const Qgis::FieldDomainSplitPolicy policy = qgsEnumKeyToValue( splitPolicyElem.attribute( u"policy"_s ), Qgis::FieldDomainSplitPolicy::Duplicate );
2682 mAttributeSplitPolicy.insert( field, policy );
2683 }
2684 }
2685
2686 // The duplicate policy is - unlike alias and split policy - never defined by the data provider, so we clear the map
2687 mAttributeDuplicatePolicy.clear();
2688 const QDomNode duplicatePoliciesNode = layerNode.namedItem( u"duplicatePolicies"_s );
2689 if ( !duplicatePoliciesNode.isNull() )
2690 {
2691 const QDomNodeList duplicatePolicyNodeList = duplicatePoliciesNode.toElement().elementsByTagName( u"policy"_s );
2692 for ( int i = 0; i < duplicatePolicyNodeList.size(); ++i )
2693 {
2694 const QDomElement duplicatePolicyElem = duplicatePolicyNodeList.at( i ).toElement();
2695 const QString field = duplicatePolicyElem.attribute( u"field"_s );
2696 const Qgis::FieldDuplicatePolicy policy = qgsEnumKeyToValue( duplicatePolicyElem.attribute( u"policy"_s ), Qgis::FieldDuplicatePolicy::Duplicate );
2697 mAttributeDuplicatePolicy.insert( field, policy );
2698 }
2699 }
2700
2701 const QDomNode mergePoliciesNode = layerNode.namedItem( u"mergePolicies"_s );
2702 if ( !mergePoliciesNode.isNull() )
2703 {
2704 const QDomNodeList mergePolicyNodeList = mergePoliciesNode.toElement().elementsByTagName( u"policy"_s );
2705 for ( int i = 0; i < mergePolicyNodeList.size(); ++i )
2706 {
2707 const QDomElement mergePolicyElem = mergePolicyNodeList.at( i ).toElement();
2708 const QString field = mergePolicyElem.attribute( u"field"_s );
2709 const Qgis::FieldDomainMergePolicy policy = qgsEnumKeyToValue( mergePolicyElem.attribute( u"policy"_s ), Qgis::FieldDomainMergePolicy::UnsetField );
2710 mAttributeMergePolicy.insert( field, policy );
2711 }
2712 }
2713
2714 // default expressions
2715 mDefaultExpressionMap.clear();
2716 QDomNode defaultsNode = layerNode.namedItem( u"defaults"_s );
2717 if ( !defaultsNode.isNull() )
2718 {
2719 QDomNodeList defaultNodeList = defaultsNode.toElement().elementsByTagName( u"default"_s );
2720 for ( int i = 0; i < defaultNodeList.size(); ++i )
2721 {
2722 QDomElement defaultElem = defaultNodeList.at( i ).toElement();
2723
2724 QString field = defaultElem.attribute( u"field"_s, QString() );
2725 QString expression = defaultElem.attribute( u"expression"_s, QString() );
2726 bool applyOnUpdate = defaultElem.attribute( u"applyOnUpdate"_s, u"0"_s ) == "1"_L1;
2727 if ( field.isEmpty() || expression.isEmpty() )
2728 continue;
2729
2730 mDefaultExpressionMap.insert( field, QgsDefaultValue( expression, applyOnUpdate ) );
2731 }
2732 }
2733
2734 // constraints
2735 mFieldConstraints.clear();
2736 mFieldConstraintStrength.clear();
2737 QDomNode constraintsNode = layerNode.namedItem( u"constraints"_s );
2738 if ( !constraintsNode.isNull() )
2739 {
2740 QDomNodeList constraintNodeList = constraintsNode.toElement().elementsByTagName( u"constraint"_s );
2741 for ( int i = 0; i < constraintNodeList.size(); ++i )
2742 {
2743 QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2744
2745 QString field = constraintElem.attribute( u"field"_s, QString() );
2746 int constraints = constraintElem.attribute( u"constraints"_s, u"0"_s ).toInt();
2747 if ( field.isEmpty() || constraints == 0 )
2748 continue;
2749
2750 mFieldConstraints.insert( field, static_cast< QgsFieldConstraints::Constraints >( constraints ) );
2751
2752 int uniqueStrength = constraintElem.attribute( u"unique_strength"_s, u"1"_s ).toInt();
2753 int notNullStrength = constraintElem.attribute( u"notnull_strength"_s, u"1"_s ).toInt();
2754 int expStrength = constraintElem.attribute( u"exp_strength"_s, u"1"_s ).toInt();
2755
2756 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintUnique ), static_cast< QgsFieldConstraints::ConstraintStrength >( uniqueStrength ) );
2757 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintNotNull ), static_cast< QgsFieldConstraints::ConstraintStrength >( notNullStrength ) );
2758 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintExpression ), static_cast< QgsFieldConstraints::ConstraintStrength >( expStrength ) );
2759 }
2760 }
2761 mFieldConstraintExpressions.clear();
2762 QDomNode constraintExpressionsNode = layerNode.namedItem( u"constraintExpressions"_s );
2763 if ( !constraintExpressionsNode.isNull() )
2764 {
2765 QDomNodeList constraintNodeList = constraintExpressionsNode.toElement().elementsByTagName( u"constraint"_s );
2766 for ( int i = 0; i < constraintNodeList.size(); ++i )
2767 {
2768 QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2769
2770 QString field = constraintElem.attribute( u"field"_s, QString() );
2771 QString exp = constraintElem.attribute( u"exp"_s, QString() );
2772 QString desc
2773 = context.projectTranslator()->translate( u"project:layers:%1:constraintdescriptions"_s.arg( layerNode.namedItem( u"id"_s ).toElement().text() ), constraintElem.attribute( u"desc"_s, QString() ) );
2774 QgsDebugMsgLevel( "context" + u"project:layers:%1:constraintdescriptions"_s.arg( layerNode.namedItem( u"id"_s ).toElement().text() ) + " source " + constraintElem.attribute( u"desc"_s, QString() ), 3 );
2775 if ( field.isEmpty() || exp.isEmpty() )
2776 continue;
2777
2778 mFieldConstraintExpressions.insert( field, qMakePair( exp, desc ) );
2779 }
2780 }
2781
2782 updateFields();
2783 }
2784
2785 // load field configuration
2786 if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
2787 {
2788 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Forms" ) );
2789
2790 QDomElement widgetsElem = layerNode.namedItem( u"fieldConfiguration"_s ).toElement();
2791 QDomNodeList fieldConfigurationElementList = widgetsElem.elementsByTagName( u"field"_s );
2792 for ( int i = 0; i < fieldConfigurationElementList.size(); ++i )
2793 {
2794 const QDomElement fieldConfigElement = fieldConfigurationElementList.at( i ).toElement();
2795 const QDomElement fieldWidgetElement = fieldConfigElement.elementsByTagName( u"editWidget"_s ).at( 0 ).toElement();
2796
2797 QString fieldName = fieldConfigElement.attribute( u"name"_s );
2798
2799 if ( categories.testFlag( Fields ) )
2800 mFieldConfigurationFlags[fieldName] = qgsFlagKeysToValue( fieldConfigElement.attribute( u"configurationFlags"_s ), Qgis::FieldConfigurationFlag::NoFlag );
2801
2802 // load editor widget configuration
2803 if ( categories.testFlag( Forms ) )
2804 {
2805 const QString widgetType = fieldWidgetElement.attribute( u"type"_s );
2806 const QDomElement cfgElem = fieldConfigElement.elementsByTagName( u"config"_s ).at( 0 ).toElement();
2807 const QDomElement optionsElem = cfgElem.childNodes().at( 0 ).toElement();
2808 QVariantMap optionsMap = QgsXmlUtils::readVariant( optionsElem ).toMap();
2809 // translate widget configuration strings
2810 if ( widgetType == "ValueRelation"_L1 )
2811 {
2812 optionsMap[u"Value"_s]
2813 = context.projectTranslator()->translate( u"project:layers:%1:fields:%2:valuerelationvalue"_s.arg( layerNode.namedItem( u"id"_s ).toElement().text(), fieldName ), optionsMap[u"Value"_s].toString() );
2814 optionsMap[u"Description"_s]
2815 = context.projectTranslator()
2816 ->translate( u"project:layers:%1:fields:%2:valuerelationdescription"_s.arg( layerNode.namedItem( u"id"_s ).toElement().text(), fieldName ), optionsMap[u"Description"_s].toString() );
2817 }
2818 if ( widgetType == "ValueMap"_L1 )
2819 {
2820 if ( optionsMap[u"map"_s].canConvert<QList<QVariant>>() )
2821 {
2822 QList<QVariant> translatedValueList;
2823 const QList<QVariant> valueList = optionsMap[u"map"_s].toList();
2824 for ( int i = 0; i < valueList.count(); i++ )
2825 {
2826 QMap<QString, QVariant> translatedValueMap;
2827 QString translatedKey
2828 = context.projectTranslator()
2829 ->translate( u"project:layers:%1:fields:%2:valuemapdescriptions"_s.arg( layerNode.namedItem( u"id"_s ).toElement().text(), fieldName ), valueList[i].toMap().constBegin().key() );
2830 translatedValueMap.insert( translatedKey, valueList[i].toMap().constBegin().value() );
2831 translatedValueList.append( translatedValueMap );
2832 }
2833 optionsMap.insert( u"map"_s, translatedValueList );
2834 }
2835 }
2836 QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( widgetType, optionsMap );
2837 mFieldWidgetSetups[fieldName] = setup;
2838 }
2839 }
2840 }
2841
2842 // Legacy reading for QGIS 3.14 and older projects
2843 // Attributes excluded from WMS and WFS
2844 if ( categories.testFlag( Fields ) )
2845 {
2846 const QList<QPair<QString, Qgis::FieldConfigurationFlag>>
2847 legacyConfig { qMakePair( u"excludeAttributesWMS"_s, Qgis::FieldConfigurationFlag::HideFromWms ), qMakePair( u"excludeAttributesWFS"_s, Qgis::FieldConfigurationFlag::HideFromWfs ) };
2848 for ( const auto &config : legacyConfig )
2849 {
2850 QDomNode excludeNode = layerNode.namedItem( config.first );
2851 if ( !excludeNode.isNull() )
2852 {
2853 QDomNodeList attributeNodeList = excludeNode.toElement().elementsByTagName( u"attribute"_s );
2854 for ( int i = 0; i < attributeNodeList.size(); ++i )
2855 {
2856 QString fieldName = attributeNodeList.at( i ).toElement().text();
2857 if ( !mFieldConfigurationFlags.contains( fieldName ) )
2858 mFieldConfigurationFlags[fieldName] = config.second;
2859 else
2860 mFieldConfigurationFlags[fieldName].setFlag( config.second, true );
2861 }
2862 }
2863 }
2864 }
2865
2866 if ( categories.testFlag( GeometryOptions ) )
2867 mGeometryOptions->readXml( layerNode.namedItem( u"geometryOptions"_s ) );
2868
2869 if ( categories.testFlag( Forms ) )
2870 mEditFormConfig.readXml( layerNode, context );
2871
2872 if ( categories.testFlag( AttributeTable ) )
2873 {
2874 mAttributeTableConfig.readXml( layerNode );
2875 mConditionalStyles->readXml( layerNode, context );
2876 mStoredExpressionManager->readXml( layerNode );
2877 }
2878
2879 if ( categories.testFlag( CustomProperties ) )
2880 readCustomProperties( layerNode, u"variable"_s );
2881
2882 QDomElement mapLayerNode = layerNode.toElement();
2883 if ( categories.testFlag( LayerConfiguration ) && mapLayerNode.attribute( u"readOnly"_s, u"0"_s ).toInt() == 1 )
2884 mReadOnly = true;
2885
2886 updateFields();
2887
2888 if ( categories.testFlag( Legend ) )
2889 {
2890 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Legend" ) );
2891
2892 const QDomElement legendElem = layerNode.firstChildElement( u"legend"_s );
2893 if ( !legendElem.isNull() )
2894 {
2895 std::unique_ptr< QgsMapLayerLegend > legend( QgsMapLayerLegend::defaultVectorLegend( this ) );
2896 legend->readXml( legendElem, context );
2897 setLegend( legend.release() );
2898 mSetLegendFromStyle = true;
2899 }
2900 }
2901
2902 return true;
2903}
2904
2905bool QgsVectorLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
2906{
2908
2909 bool result = true;
2910 emit readCustomSymbology( node.toElement(), errorMessage );
2911
2912 // we must try to restore a renderer if our geometry type is unknown
2913 // as this allows the renderer to be correctly restored even for layers
2914 // with broken sources
2915 if ( isSpatial() || mWkbType == Qgis::WkbType::Unknown )
2916 {
2917 // defer style changed signal until we've set the renderer, labeling, everything.
2918 // we don't want multiple signals!
2919 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
2920
2921 // try renderer v2 first
2922 if ( categories.testFlag( Symbology ) )
2923 {
2924 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Symbology" ) );
2925
2926 QDomElement rendererElement = node.firstChildElement( RENDERER_TAG_NAME );
2927 if ( !rendererElement.isNull() )
2928 {
2929 QgsFeatureRenderer *r = QgsFeatureRenderer::load( rendererElement, context );
2930 if ( r )
2931 {
2932 setRenderer( r );
2933 }
2934 else
2935 {
2936 result = false;
2937 }
2938 }
2939 // make sure layer has a renderer - if none exists, fallback to a default renderer
2940 if ( isSpatial() && !renderer() )
2941 {
2943 }
2944
2945 if ( mSelectionProperties )
2946 mSelectionProperties->readXml( node.toElement(), context );
2947 }
2948
2949 // read labeling definition
2950 if ( categories.testFlag( Labeling ) )
2951 {
2952 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Labeling" ) );
2953
2954 QDomElement labelingElement = node.firstChildElement( u"labeling"_s );
2956 if ( labelingElement.isNull() || ( labelingElement.attribute( u"type"_s ) == "simple"_L1 && labelingElement.firstChildElement( u"settings"_s ).isNull() ) )
2957 {
2958 // make sure we have custom properties for labeling for 2.x projects
2959 // (custom properties should be already loaded when reading the whole layer from XML,
2960 // but when reading style, custom properties are not read)
2961 readCustomProperties( node, u"labeling"_s );
2962
2963 // support for pre-QGIS 3 labeling configurations written in custom properties
2964 labeling = readLabelingFromCustomProperties();
2965 }
2966 else
2967 {
2968 labeling = QgsAbstractVectorLayerLabeling::create( labelingElement, context );
2969 }
2971
2972 if ( node.toElement().hasAttribute( u"labelsEnabled"_s ) )
2973 mLabelsEnabled = node.toElement().attribute( u"labelsEnabled"_s ).toInt();
2974 else
2975 mLabelsEnabled = true;
2976 }
2977
2978 if ( categories.testFlag( Symbology ) )
2979 {
2980 // get and set the blend mode if it exists
2981 QDomNode blendModeNode = node.namedItem( u"blendMode"_s );
2982 if ( !blendModeNode.isNull() )
2983 {
2984 QDomElement e = blendModeNode.toElement();
2985 setBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
2986 }
2987
2988 // get and set the feature blend mode if it exists
2989 QDomNode featureBlendModeNode = node.namedItem( u"featureBlendMode"_s );
2990 if ( !featureBlendModeNode.isNull() )
2991 {
2992 QDomElement e = featureBlendModeNode.toElement();
2993 setFeatureBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
2994 }
2995 }
2996
2997 // get and set the layer transparency and scale visibility if they exists
2998 if ( categories.testFlag( Rendering ) )
2999 {
3000 QDomNode layerTransparencyNode = node.namedItem( u"layerTransparency"_s );
3001 if ( !layerTransparencyNode.isNull() )
3002 {
3003 QDomElement e = layerTransparencyNode.toElement();
3004 setOpacity( 1.0 - e.text().toInt() / 100.0 );
3005 }
3006 QDomNode layerOpacityNode = node.namedItem( u"layerOpacity"_s );
3007 if ( !layerOpacityNode.isNull() )
3008 {
3009 QDomElement e = layerOpacityNode.toElement();
3010 setOpacity( e.text().toDouble() );
3011 }
3012
3013 const bool hasScaleBasedVisibiliy { node.attributes().namedItem( u"hasScaleBasedVisibilityFlag"_s ).nodeValue() == '1' };
3014 setScaleBasedVisibility( hasScaleBasedVisibiliy );
3015 bool ok;
3016 const double maxScale { node.attributes().namedItem( u"maxScale"_s ).nodeValue().toDouble( &ok ) };
3017 if ( ok )
3018 {
3019 setMaximumScale( maxScale );
3020 }
3021 const double minScale { node.attributes().namedItem( u"minScale"_s ).nodeValue().toDouble( &ok ) };
3022 if ( ok )
3023 {
3024 setMinimumScale( minScale );
3025 }
3026
3027 QDomElement e = node.toElement();
3028
3029 // get the simplification drawing settings
3030 mSimplifyMethod.setSimplifyHints( static_cast< Qgis::VectorRenderingSimplificationFlags >( e.attribute( u"simplifyDrawingHints"_s, u"1"_s ).toInt() ) );
3031 mSimplifyMethod.setSimplifyAlgorithm( static_cast< Qgis::VectorSimplificationAlgorithm >( e.attribute( u"simplifyAlgorithm"_s, u"0"_s ).toInt() ) );
3032 mSimplifyMethod.setThreshold( e.attribute( u"simplifyDrawingTol"_s, u"1"_s ).toFloat() );
3033 mSimplifyMethod.setForceLocalOptimization( e.attribute( u"simplifyLocal"_s, u"1"_s ).toInt() );
3034 mSimplifyMethod.setMaximumScale( e.attribute( u"simplifyMaxScale"_s, u"1"_s ).toFloat() );
3035
3036 if ( mRenderer )
3037 mRenderer->setReferenceScale( e.attribute( u"symbologyReferenceScale"_s, u"-1"_s ).toDouble() );
3038 }
3039
3040 //diagram renderer and diagram layer settings
3041 if ( categories.testFlag( Diagrams ) )
3042 {
3043 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Diagrams" ) );
3044
3045 delete mDiagramRenderer;
3046 mDiagramRenderer = nullptr;
3047 QDomElement singleCatDiagramElem = node.firstChildElement( u"SingleCategoryDiagramRenderer"_s );
3048 if ( !singleCatDiagramElem.isNull() )
3049 {
3050 mDiagramRenderer = new QgsSingleCategoryDiagramRenderer();
3051 mDiagramRenderer->readXml( singleCatDiagramElem, context );
3052 }
3053 QDomElement linearDiagramElem = node.firstChildElement( u"LinearlyInterpolatedDiagramRenderer"_s );
3054 if ( !linearDiagramElem.isNull() )
3055 {
3056 if ( linearDiagramElem.hasAttribute( u"classificationAttribute"_s ) )
3057 {
3058 // fix project from before QGIS 3.0
3059 int idx = linearDiagramElem.attribute( u"classificationAttribute"_s ).toInt();
3060 if ( idx >= 0 && idx < mFields.count() )
3061 linearDiagramElem.setAttribute( u"classificationField"_s, mFields.at( idx ).name() );
3062 }
3063
3064 mDiagramRenderer = new QgsLinearlyInterpolatedDiagramRenderer();
3065 mDiagramRenderer->readXml( linearDiagramElem, context );
3066 }
3067 QDomElement stackedDiagramElem = node.firstChildElement( u"StackedDiagramRenderer"_s );
3068 if ( !stackedDiagramElem.isNull() )
3069 {
3070 mDiagramRenderer = new QgsStackedDiagramRenderer();
3071 mDiagramRenderer->readXml( stackedDiagramElem, context );
3072 }
3073
3074 if ( mDiagramRenderer )
3075 {
3076 QDomElement diagramSettingsElem = node.firstChildElement( u"DiagramLayerSettings"_s );
3077 if ( !diagramSettingsElem.isNull() )
3078 {
3079 bool oldXPos = diagramSettingsElem.hasAttribute( u"xPosColumn"_s );
3080 bool oldYPos = diagramSettingsElem.hasAttribute( u"yPosColumn"_s );
3081 bool oldShow = diagramSettingsElem.hasAttribute( u"showColumn"_s );
3082 if ( oldXPos || oldYPos || oldShow )
3083 {
3084 // fix project from before QGIS 3.0
3086 if ( oldXPos )
3087 {
3088 int xPosColumn = diagramSettingsElem.attribute( u"xPosColumn"_s ).toInt();
3089 if ( xPosColumn >= 0 && xPosColumn < mFields.count() )
3090 ddp.setProperty( QgsDiagramLayerSettings::Property::PositionX, QgsProperty::fromField( mFields.at( xPosColumn ).name(), true ) );
3091 }
3092 if ( oldYPos )
3093 {
3094 int yPosColumn = diagramSettingsElem.attribute( u"yPosColumn"_s ).toInt();
3095 if ( yPosColumn >= 0 && yPosColumn < mFields.count() )
3096 ddp.setProperty( QgsDiagramLayerSettings::Property::PositionY, QgsProperty::fromField( mFields.at( yPosColumn ).name(), true ) );
3097 }
3098 if ( oldShow )
3099 {
3100 int showColumn = diagramSettingsElem.attribute( u"showColumn"_s ).toInt();
3101 if ( showColumn >= 0 && showColumn < mFields.count() )
3102 ddp.setProperty( QgsDiagramLayerSettings::Property::Show, QgsProperty::fromField( mFields.at( showColumn ).name(), true ) );
3103 }
3104 QDomElement propertiesElem = diagramSettingsElem.ownerDocument().createElement( u"properties"_s );
3106 { static_cast< int >( QgsDiagramLayerSettings::Property::PositionX ), QgsPropertyDefinition( "positionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double ) },
3107 { static_cast< int >( QgsDiagramLayerSettings::Property::PositionY ), QgsPropertyDefinition( "positionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double ) },
3108 { static_cast< int >( QgsDiagramLayerSettings::Property::Show ), QgsPropertyDefinition( "show", QObject::tr( "Show diagram" ), QgsPropertyDefinition::Boolean ) },
3109 };
3110 ddp.writeXml( propertiesElem, defs );
3111 diagramSettingsElem.appendChild( propertiesElem );
3112 }
3113
3114 delete mDiagramLayerSettings;
3115 mDiagramLayerSettings = new QgsDiagramLayerSettings();
3116 mDiagramLayerSettings->readXml( diagramSettingsElem );
3117 }
3118 }
3119 }
3120 // end diagram
3121
3122 styleChangedSignalBlocker.release();
3124 }
3125 return result;
3126}
3127
3128
3129bool QgsVectorLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
3130{
3132
3133 QDomElement layerElement = node.toElement();
3134 writeCommonStyle( layerElement, doc, context, categories );
3135
3136 ( void ) writeStyle( node, doc, errorMessage, context, categories );
3137
3138 if ( categories.testFlag( GeometryOptions ) )
3139 mGeometryOptions->writeXml( node );
3140
3141 if ( categories.testFlag( Legend ) && legend() )
3142 {
3143 QDomElement legendElement = legend()->writeXml( doc, context );
3144 if ( !legendElement.isNull() )
3145 node.appendChild( legendElement );
3146 }
3147
3148 // Relation information for both referenced and referencing sides
3149 if ( categories.testFlag( Relations ) )
3150 {
3151 if ( QgsProject *p = project() )
3152 {
3153 // Store referenced layers: relations where "this" is the child layer (the referencing part, that holds the FK)
3154 QDomElement referencedLayersElement = doc.createElement( u"referencedLayers"_s );
3155 node.appendChild( referencedLayersElement );
3156
3157 const QList<QgsRelation> referencingRelations { p->relationManager()->referencingRelations( this ) };
3158 for ( const QgsRelation &rel : referencingRelations )
3159 {
3160 switch ( rel.type() )
3161 {
3163 QgsWeakRelation::writeXml( this, QgsWeakRelation::Referencing, rel, referencedLayersElement, doc );
3164 break;
3166 break;
3167 }
3168 }
3169
3170 // Store referencing layers: relations where "this" is the parent layer (the referenced part, that holds the FK)
3171 QDomElement referencingLayersElement = doc.createElement( u"referencingLayers"_s );
3172 node.appendChild( referencingLayersElement );
3173
3174 const QList<QgsRelation> referencedRelations { p->relationManager()->referencedRelations( this ) };
3175 for ( const QgsRelation &rel : referencedRelations )
3176 {
3177 switch ( rel.type() )
3178 {
3180 QgsWeakRelation::writeXml( this, QgsWeakRelation::Referenced, rel, referencingLayersElement, doc );
3181 break;
3183 break;
3184 }
3185 }
3186 }
3187 }
3188
3189 // write field configurations
3190 if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
3191 {
3192 QDomElement fieldConfigurationElement;
3193 // field configuration flag
3194 fieldConfigurationElement = doc.createElement( u"fieldConfiguration"_s );
3195 node.appendChild( fieldConfigurationElement );
3196
3197 for ( const QgsField &field : std::as_const( mFields ) )
3198 {
3199 QDomElement fieldElement = doc.createElement( u"field"_s );
3200 fieldElement.setAttribute( u"name"_s, field.name() );
3201 fieldConfigurationElement.appendChild( fieldElement );
3202
3203 if ( categories.testFlag( Fields ) )
3204 {
3205 fieldElement.setAttribute( u"configurationFlags"_s, qgsFlagValueToKeys( field.configurationFlags() ) );
3206 }
3207
3208 if ( categories.testFlag( Forms ) )
3209 {
3210 QgsEditorWidgetSetup widgetSetup = field.editorWidgetSetup();
3211
3212 // TODO : wrap this part in an if to only save if it was user-modified
3213 QDomElement editWidgetElement = doc.createElement( u"editWidget"_s );
3214 fieldElement.appendChild( editWidgetElement );
3215 editWidgetElement.setAttribute( u"type"_s, field.editorWidgetSetup().type() );
3216 QDomElement editWidgetConfigElement = doc.createElement( u"config"_s );
3217
3218 editWidgetConfigElement.appendChild( QgsXmlUtils::writeVariant( widgetSetup.config(), doc ) );
3219 editWidgetElement.appendChild( editWidgetConfigElement );
3220 // END TODO : wrap this part in an if to only save if it was user-modified
3221 }
3222 }
3223 }
3224
3225 if ( categories.testFlag( Fields ) )
3226 {
3227 //attribute aliases
3228 QDomElement aliasElem = doc.createElement( u"aliases"_s );
3229 for ( const QgsField &field : std::as_const( mFields ) )
3230 {
3231 QDomElement aliasEntryElem = doc.createElement( u"alias"_s );
3232 aliasEntryElem.setAttribute( u"field"_s, field.name() );
3233 aliasEntryElem.setAttribute( u"index"_s, mFields.indexFromName( field.name() ) );
3234 aliasEntryElem.setAttribute( u"name"_s, field.alias() );
3235 aliasElem.appendChild( aliasEntryElem );
3236 }
3237 node.appendChild( aliasElem );
3238
3239 //custom comments
3240 QDomElement customCommentElem = doc.createElement( u"customComments"_s );
3241 bool hasCustomComments = false;
3242 for ( const QgsField &field : std::as_const( mFields ) )
3243 {
3244 //if empty ("") we store it, if null we don't store it
3245 const QString customComment = field.customComment();
3246 if ( customComment.isNull() )
3247 continue;
3248
3249 hasCustomComments = true;
3250 QDomElement customCommentEntryElem = doc.createElement( u"customComment"_s );
3251 customCommentEntryElem.setAttribute( u"field"_s, field.name() );
3252 customCommentEntryElem.setAttribute( u"value"_s, customComment );
3253 customCommentElem.appendChild( customCommentEntryElem );
3254 }
3255 if ( hasCustomComments )
3256 {
3257 node.appendChild( customCommentElem );
3258 }
3259
3260 //split policies
3261 {
3262 QDomElement splitPoliciesElement = doc.createElement( u"splitPolicies"_s );
3263 bool hasNonDefaultSplitPolicies = false;
3264 for ( const QgsField &field : std::as_const( mFields ) )
3265 {
3266 if ( field.splitPolicy() != Qgis::FieldDomainSplitPolicy::Duplicate )
3267 {
3268 QDomElement splitPolicyElem = doc.createElement( u"policy"_s );
3269 splitPolicyElem.setAttribute( u"field"_s, field.name() );
3270 splitPolicyElem.setAttribute( u"policy"_s, qgsEnumValueToKey( field.splitPolicy() ) );
3271 splitPoliciesElement.appendChild( splitPolicyElem );
3272 hasNonDefaultSplitPolicies = true;
3273 }
3274 }
3275 if ( hasNonDefaultSplitPolicies )
3276 node.appendChild( splitPoliciesElement );
3277 }
3278
3279 //duplicate policies
3280 {
3281 QDomElement duplicatePoliciesElement = doc.createElement( u"duplicatePolicies"_s );
3282 bool hasNonDefaultDuplicatePolicies = false;
3283 for ( const QgsField &field : std::as_const( mFields ) )
3284 {
3285 if ( field.duplicatePolicy() != Qgis::FieldDuplicatePolicy::Duplicate )
3286 {
3287 QDomElement duplicatePolicyElem = doc.createElement( u"policy"_s );
3288 duplicatePolicyElem.setAttribute( u"field"_s, field.name() );
3289 duplicatePolicyElem.setAttribute( u"policy"_s, qgsEnumValueToKey( field.duplicatePolicy() ) );
3290 duplicatePoliciesElement.appendChild( duplicatePolicyElem );
3291 hasNonDefaultDuplicatePolicies = true;
3292 }
3293 }
3294 if ( hasNonDefaultDuplicatePolicies )
3295 node.appendChild( duplicatePoliciesElement );
3296 }
3297
3298 //merge policies
3299 {
3300 QDomElement mergePoliciesElement = doc.createElement( u"mergePolicies"_s );
3301 bool hasNonDefaultMergePolicies = false;
3302 for ( const QgsField &field : std::as_const( mFields ) )
3303 {
3304 if ( field.mergePolicy() != Qgis::FieldDomainMergePolicy::UnsetField )
3305 {
3306 QDomElement mergePolicyElem = doc.createElement( u"policy"_s );
3307 mergePolicyElem.setAttribute( u"field"_s, field.name() );
3308 mergePolicyElem.setAttribute( u"policy"_s, qgsEnumValueToKey( field.mergePolicy() ) );
3309 mergePoliciesElement.appendChild( mergePolicyElem );
3310 hasNonDefaultMergePolicies = true;
3311 }
3312 }
3313 if ( hasNonDefaultMergePolicies )
3314 node.appendChild( mergePoliciesElement );
3315 }
3316
3317 //default expressions
3318 QDomElement defaultsElem = doc.createElement( u"defaults"_s );
3319 for ( const QgsField &field : std::as_const( mFields ) )
3320 {
3321 QDomElement defaultElem = doc.createElement( u"default"_s );
3322 defaultElem.setAttribute( u"field"_s, field.name() );
3323 defaultElem.setAttribute( u"expression"_s, field.defaultValueDefinition().expression() );
3324 defaultElem.setAttribute( u"applyOnUpdate"_s, field.defaultValueDefinition().applyOnUpdate() ? u"1"_s : u"0"_s );
3325 defaultsElem.appendChild( defaultElem );
3326 }
3327 node.appendChild( defaultsElem );
3328
3329 // constraints
3330 QDomElement constraintsElem = doc.createElement( u"constraints"_s );
3331 for ( const QgsField &field : std::as_const( mFields ) )
3332 {
3333 QDomElement constraintElem = doc.createElement( u"constraint"_s );
3334 constraintElem.setAttribute( u"field"_s, field.name() );
3335 constraintElem.setAttribute( u"constraints"_s, field.constraints().constraints() );
3336 constraintElem.setAttribute( u"unique_strength"_s, field.constraints().constraintStrength( QgsFieldConstraints::ConstraintUnique ) );
3337 constraintElem.setAttribute( u"notnull_strength"_s, field.constraints().constraintStrength( QgsFieldConstraints::ConstraintNotNull ) );
3338 constraintElem.setAttribute( u"exp_strength"_s, field.constraints().constraintStrength( QgsFieldConstraints::ConstraintExpression ) );
3339
3340 constraintsElem.appendChild( constraintElem );
3341 }
3342 node.appendChild( constraintsElem );
3343
3344 // constraint expressions
3345 QDomElement constraintExpressionsElem = doc.createElement( u"constraintExpressions"_s );
3346 for ( const QgsField &field : std::as_const( mFields ) )
3347 {
3348 QDomElement constraintExpressionElem = doc.createElement( u"constraint"_s );
3349 constraintExpressionElem.setAttribute( u"field"_s, field.name() );
3350 constraintExpressionElem.setAttribute( u"exp"_s, field.constraints().constraintExpression() );
3351 constraintExpressionElem.setAttribute( u"desc"_s, field.constraints().constraintDescription() );
3352 constraintExpressionsElem.appendChild( constraintExpressionElem );
3353 }
3354 node.appendChild( constraintExpressionsElem );
3355
3356 // save expression fields
3357 if ( !mExpressionFieldBuffer )
3358 {
3359 // can happen when saving style on a invalid layer
3361 dummy.writeXml( node, doc );
3362 }
3363 else
3364 {
3365 mExpressionFieldBuffer->writeXml( node, doc );
3366 }
3367 }
3368
3369 // add attribute actions
3370 if ( categories.testFlag( Actions ) )
3371 mActions->writeXml( node );
3372
3373 if ( categories.testFlag( AttributeTable ) )
3374 {
3375 mAttributeTableConfig.writeXml( node );
3376 mConditionalStyles->writeXml( node, doc, context );
3377 mStoredExpressionManager->writeXml( node );
3378 }
3379
3380 if ( categories.testFlag( Forms ) )
3381 mEditFormConfig.writeXml( node, context );
3382
3383 // save readonly state
3384 if ( categories.testFlag( LayerConfiguration ) )
3385 node.toElement().setAttribute( u"readOnly"_s, mReadOnly );
3386
3387 // save preview expression
3388 if ( categories.testFlag( LayerConfiguration ) )
3389 {
3390 QDomElement prevExpElem = doc.createElement( u"previewExpression"_s );
3391 QDomText prevExpText = doc.createTextNode( mDisplayExpression );
3392 prevExpElem.appendChild( prevExpText );
3393 node.appendChild( prevExpElem );
3394 }
3395
3396 // save map tip
3397 if ( categories.testFlag( MapTips ) )
3398 {
3399 QDomElement mapTipElem = doc.createElement( u"mapTip"_s );
3400 mapTipElem.setAttribute( u"enabled"_s, mapTipsEnabled() );
3401 QDomText mapTipText = doc.createTextNode( mMapTipTemplate );
3402 mapTipElem.appendChild( mapTipText );
3403 node.toElement().appendChild( mapTipElem );
3404 }
3405
3406 return true;
3407}
3408
3409bool QgsVectorLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
3410{
3412
3413 QDomElement mapLayerNode = node.toElement();
3414
3415 emit writeCustomSymbology( mapLayerNode, doc, errorMessage );
3416
3417 // we must try to write the renderer if our geometry type is unknown
3418 // as this allows the renderer to be correctly restored even for layers
3419 // with broken sources
3420 if ( isSpatial() || mWkbType == Qgis::WkbType::Unknown )
3421 {
3422 if ( categories.testFlag( Symbology ) )
3423 {
3424 if ( mRenderer )
3425 {
3426 QDomElement rendererElement = mRenderer->save( doc, context );
3427 node.appendChild( rendererElement );
3428 }
3429 if ( mSelectionProperties )
3430 {
3431 mSelectionProperties->writeXml( mapLayerNode, doc, context );
3432 }
3433 }
3434
3435 if ( categories.testFlag( Labeling ) )
3436 {
3437 if ( mLabeling )
3438 {
3439 QDomElement labelingElement = mLabeling->save( doc, context );
3440 node.appendChild( labelingElement );
3441 }
3442 mapLayerNode.setAttribute( u"labelsEnabled"_s, mLabelsEnabled ? u"1"_s : u"0"_s );
3443 }
3444
3445 // save the simplification drawing settings
3446 if ( categories.testFlag( Rendering ) )
3447 {
3448 mapLayerNode.setAttribute( u"simplifyDrawingHints"_s, QString::number( static_cast< int >( mSimplifyMethod.simplifyHints() ) ) );
3449 mapLayerNode.setAttribute( u"simplifyAlgorithm"_s, QString::number( static_cast< int >( mSimplifyMethod.simplifyAlgorithm() ) ) );
3450 mapLayerNode.setAttribute( u"simplifyDrawingTol"_s, QString::number( mSimplifyMethod.threshold() ) );
3451 mapLayerNode.setAttribute( u"simplifyLocal"_s, mSimplifyMethod.forceLocalOptimization() ? 1 : 0 );
3452 mapLayerNode.setAttribute( u"simplifyMaxScale"_s, QString::number( mSimplifyMethod.maximumScale() ) );
3453 }
3454
3455 //save customproperties
3456 if ( categories.testFlag( CustomProperties ) )
3457 {
3458 writeCustomProperties( node, doc );
3459 }
3460
3461 if ( categories.testFlag( Symbology ) )
3462 {
3463 // add the blend mode field
3464 QDomElement blendModeElem = doc.createElement( u"blendMode"_s );
3465 QDomText blendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( blendMode() ) ) ) );
3466 blendModeElem.appendChild( blendModeText );
3467 node.appendChild( blendModeElem );
3468
3469 // add the feature blend mode field
3470 QDomElement featureBlendModeElem = doc.createElement( u"featureBlendMode"_s );
3471 QDomText featureBlendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( featureBlendMode() ) ) ) );
3472 featureBlendModeElem.appendChild( featureBlendModeText );
3473 node.appendChild( featureBlendModeElem );
3474 }
3475
3476 // add the layer opacity and scale visibility
3477 if ( categories.testFlag( Rendering ) )
3478 {
3479 QDomElement layerOpacityElem = doc.createElement( u"layerOpacity"_s );
3480 QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
3481 layerOpacityElem.appendChild( layerOpacityText );
3482 node.appendChild( layerOpacityElem );
3483 mapLayerNode.setAttribute( u"hasScaleBasedVisibilityFlag"_s, hasScaleBasedVisibility() ? 1 : 0 );
3484 mapLayerNode.setAttribute( u"maxScale"_s, maximumScale() );
3485 mapLayerNode.setAttribute( u"minScale"_s, minimumScale() );
3486
3487 mapLayerNode.setAttribute( u"symbologyReferenceScale"_s, mRenderer ? mRenderer->referenceScale() : -1 );
3488 }
3489
3490 if ( categories.testFlag( Diagrams ) && mDiagramRenderer )
3491 {
3492 mDiagramRenderer->writeXml( mapLayerNode, doc, context );
3493 if ( mDiagramLayerSettings )
3494 mDiagramLayerSettings->writeXml( mapLayerNode, doc );
3495 }
3496 }
3497 return true;
3498}
3499
3500bool QgsVectorLayer::readSld( const QDomNode &node, QString &errorMessage )
3501{
3503
3504 // get the Name element
3505 QDomElement nameElem = node.firstChildElement( u"Name"_s );
3506 if ( nameElem.isNull() )
3507 {
3508 errorMessage = u"Warning: Name element not found within NamedLayer while it's required."_s;
3509 }
3510
3511 if ( isSpatial() )
3512 {
3513 QgsFeatureRenderer *r = QgsFeatureRenderer::loadSld( node, geometryType(), errorMessage );
3514 if ( !r )
3515 return false;
3516
3517 // defer style changed signal until we've set the renderer, labeling, everything.
3518 // we don't want multiple signals!
3519 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
3520
3521 setRenderer( r );
3522
3523 // labeling
3524 readSldLabeling( node );
3525
3526 styleChangedSignalBlocker.release();
3528 }
3529 return true;
3530}
3531
3532bool QgsVectorLayer::writeSld( QDomNode &node, QDomDocument &doc, QString &, const QVariantMap &props ) const
3533{
3535 QgsSldExportContext context;
3536 context.setExtraProperties( props );
3537 writeSld( node, doc, context );
3538 return true;
3539}
3540
3541bool QgsVectorLayer::writeSld( QDomNode &node, QDomDocument &doc, QgsSldExportContext &context ) const
3542{
3544
3545 QVariantMap localProps = context.extraProperties();
3547 {
3549 }
3550 context.setExtraProperties( localProps );
3551
3552 if ( isSpatial() )
3553 {
3554 // store the Name element
3555 QDomElement nameNode = doc.createElement( u"se:Name"_s );
3556 nameNode.appendChild( doc.createTextNode( name() ) );
3557 node.appendChild( nameNode );
3558
3559 QDomElement userStyleElem = doc.createElement( u"UserStyle"_s );
3560 node.appendChild( userStyleElem );
3561
3562 QDomElement nameElem = doc.createElement( u"se:Name"_s );
3563 nameElem.appendChild( doc.createTextNode( name() ) );
3564
3565 userStyleElem.appendChild( nameElem );
3566
3567 QDomElement featureTypeStyleElem = doc.createElement( u"se:FeatureTypeStyle"_s );
3568 userStyleElem.appendChild( featureTypeStyleElem );
3569
3570 mRenderer->toSld( doc, featureTypeStyleElem, context );
3571 if ( labelsEnabled() )
3572 {
3573 mLabeling->toSld( featureTypeStyleElem, context );
3574 }
3575 }
3576 return true;
3577}
3578
3579bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, QgsGeometry &geom, bool skipDefaultValue )
3580{
3582
3583 if ( !mEditBuffer || !mDataProvider )
3584 {
3585 return false;
3586 }
3587
3588 if ( mGeometryOptions->isActive() )
3589 mGeometryOptions->apply( geom );
3590
3591 updateExtents();
3592
3593 bool result = mEditBuffer->changeGeometry( fid, geom );
3594
3595 if ( result )
3596 {
3597 updateExtents();
3598 if ( !skipDefaultValue && !mDefaultValueOnUpdateFields.isEmpty() )
3599 updateDefaultValues( fid );
3600 }
3601 return result;
3602}
3603
3604
3605bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue, bool skipDefaultValues, QgsVectorLayerToolsContext *context )
3606{
3608
3609 bool result = false;
3610
3611 switch ( fields().fieldOrigin( field ) )
3612 {
3614 result = mJoinBuffer->changeAttributeValue( fid, field, newValue, oldValue );
3615 if ( result )
3616 emit attributeValueChanged( fid, field, newValue );
3617 break;
3618
3622 {
3623 if ( mEditBuffer && mDataProvider )
3624 result = mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
3625 break;
3626 }
3627
3629 break;
3630 }
3631
3632 if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
3633 updateDefaultValues( fid, QgsFeature(), context ? context->expressionContext() : nullptr );
3634
3635 return result;
3636}
3637
3638bool QgsVectorLayer::changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues, bool skipDefaultValues, QgsVectorLayerToolsContext *context )
3639{
3641
3642 bool result = true;
3643
3644 QgsAttributeMap newValuesJoin;
3645 QgsAttributeMap oldValuesJoin;
3646
3647 QgsAttributeMap newValuesNotJoin;
3648 QgsAttributeMap oldValuesNotJoin;
3649
3650 for ( auto it = newValues.constBegin(); it != newValues.constEnd(); ++it )
3651 {
3652 const int field = it.key();
3653 const QVariant newValue = it.value();
3654 QVariant oldValue;
3655
3656 if ( oldValues.contains( field ) )
3657 oldValue = oldValues[field];
3658
3659 switch ( fields().fieldOrigin( field ) )
3660 {
3662 newValuesJoin[field] = newValue;
3663 oldValuesJoin[field] = oldValue;
3664 break;
3665
3669 {
3670 newValuesNotJoin[field] = newValue;
3671 oldValuesNotJoin[field] = oldValue;
3672 break;
3673 }
3674
3676 break;
3677 }
3678 }
3679
3680 if ( !newValuesJoin.isEmpty() && mJoinBuffer )
3681 {
3682 result = mJoinBuffer->changeAttributeValues( fid, newValuesJoin, oldValuesJoin );
3683 }
3684
3685 if ( !newValuesNotJoin.isEmpty() )
3686 {
3687 if ( mEditBuffer && mDataProvider )
3688 result &= mEditBuffer->changeAttributeValues( fid, newValuesNotJoin, oldValues );
3689 else
3690 result = false;
3691 }
3692
3693 if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
3694 {
3695 updateDefaultValues( fid, QgsFeature(), context ? context->expressionContext() : nullptr );
3696 }
3697
3698 return result;
3699}
3700
3702{
3704
3705 if ( !mEditBuffer || !mDataProvider )
3706 return false;
3707
3708 return mEditBuffer->addAttribute( field );
3709}
3710
3712{
3714
3715 if ( attIndex < 0 || attIndex >= fields().count() )
3716 return;
3717
3718 QString name = fields().at( attIndex ).name();
3719 mFields[attIndex].setAlias( QString() );
3720 if ( mAttributeAliasMap.contains( name ) )
3721 {
3722 mAttributeAliasMap.remove( name );
3723 updateFields();
3724 mEditFormConfig.setFields( mFields );
3725 emit layerModified();
3726 }
3727}
3728
3729bool QgsVectorLayer::renameAttribute( int index, const QString &newName )
3730{
3732
3733 if ( index < 0 || index >= fields().count() )
3734 return false;
3735
3736 switch ( mFields.fieldOrigin( index ) )
3737 {
3739 {
3740 if ( mExpressionFieldBuffer )
3741 {
3742 int oi = mFields.fieldOriginIndex( index );
3743 mExpressionFieldBuffer->renameExpression( oi, newName );
3744 updateFields();
3745 return true;
3746 }
3747 else
3748 {
3749 return false;
3750 }
3751 }
3752
3755
3756 if ( !mEditBuffer || !mDataProvider )
3757 return false;
3758
3759 return mEditBuffer->renameAttribute( index, newName );
3760
3763 return false;
3764 }
3765
3766 return false; // avoid warning
3767}
3768
3769void QgsVectorLayer::setFieldAlias( int attIndex, const QString &aliasString )
3770{
3772
3773 if ( attIndex < 0 || attIndex >= fields().count() )
3774 return;
3775
3776 QString name = fields().at( attIndex ).name();
3777
3778 mAttributeAliasMap.insert( name, aliasString );
3779 mFields[attIndex].setAlias( aliasString );
3780 mEditFormConfig.setFields( mFields );
3781 emit layerModified(); // TODO[MD]: should have a different signal?
3782}
3783
3784QString QgsVectorLayer::attributeAlias( int index ) const
3785{
3787
3788 if ( index < 0 || index >= fields().count() )
3789 return QString();
3790
3791 return fields().at( index ).alias();
3792}
3793
3794void QgsVectorLayer::setFieldCustomComment( int attIndex, const QString &customCommentString )
3795{
3797
3798 if ( attIndex < 0 || attIndex >= fields().count() )
3799 return;
3800
3801 QString name = fields().at( attIndex ).name();
3802
3803 mAttributeCustomCommentMap.insert( name, customCommentString );
3804 mFields[attIndex].setCustomComment( customCommentString );
3805 mEditFormConfig.setFields( mFields );
3806 emit layerModified();
3807}
3808
3810{
3812
3813 if ( attIndex < 0 || attIndex >= fields().count() )
3814 return;
3815
3816 QString name = fields().at( attIndex ).name();
3817 mFields[attIndex].setCustomComment( QString() );
3818 if ( mAttributeCustomCommentMap.contains( name ) )
3819 {
3820 mAttributeCustomCommentMap.remove( name );
3821 updateFields();
3822 mEditFormConfig.setFields( mFields );
3823 emit layerModified();
3824 }
3825}
3826
3828{
3830
3831 if ( index < 0 || index >= fields().count() )
3832 return QString();
3833
3834 return fields().at( index ).customComment();
3835}
3836
3838{
3840
3841 return mAttributeCustomCommentMap;
3842}
3843
3845{
3847
3848 if ( index >= 0 && index < mFields.count() )
3849 return mFields.at( index ).displayName();
3850 else
3851 return QString();
3852}
3853
3855{
3857
3858 return mAttributeAliasMap;
3859}
3860
3862{
3864
3865 if ( index < 0 || index >= fields().count() )
3866 return;
3867
3868 const QString name = fields().at( index ).name();
3869
3870 mAttributeSplitPolicy.insert( name, policy );
3871 mFields[index].setSplitPolicy( policy );
3872 mEditFormConfig.setFields( mFields );
3873 emit layerModified(); // TODO[MD]: should have a different signal?
3874}
3875
3877{
3879
3880 if ( index < 0 || index >= fields().count() )
3881 return;
3882
3883 const QString name = fields().at( index ).name();
3884
3885 mAttributeDuplicatePolicy.insert( name, policy );
3886 mFields[index].setDuplicatePolicy( policy );
3887 mEditFormConfig.setFields( mFields );
3888 emit layerModified(); // TODO[MD]: should have a different signal?
3889}
3890
3892{
3894
3895 if ( index < 0 || index >= fields().count() )
3896 return;
3897
3898 const QString name = fields().at( index ).name();
3899
3900 mAttributeMergePolicy.insert( name, policy );
3901 mFields[index].setMergePolicy( policy );
3902 mEditFormConfig.setFields( mFields );
3903 emit layerModified(); // TODO[MD]: should have a different signal?
3904}
3905
3907{
3909
3910 QSet<QString> excludeList;
3911 QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
3912 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
3913 {
3914 if ( flagsIt->testFlag( Qgis::FieldConfigurationFlag::HideFromWms ) )
3915 {
3916 excludeList << flagsIt.key();
3917 }
3918 }
3919 return excludeList;
3920}
3921
3922void QgsVectorLayer::setExcludeAttributesWms( const QSet<QString> &att )
3923{
3925
3926 QMap< QString, Qgis::FieldConfigurationFlags >::iterator flagsIt = mFieldConfigurationFlags.begin();
3927 for ( ; flagsIt != mFieldConfigurationFlags.end(); ++flagsIt )
3928 {
3929 flagsIt->setFlag( Qgis::FieldConfigurationFlag::HideFromWms, att.contains( flagsIt.key() ) );
3930 }
3931 updateFields();
3932}
3933
3935{
3937
3938 QSet<QString> excludeList;
3939 QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
3940 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
3941 {
3942 if ( flagsIt->testFlag( Qgis::FieldConfigurationFlag::HideFromWfs ) )
3943 {
3944 excludeList << flagsIt.key();
3945 }
3946 }
3947 return excludeList;
3948}
3949
3950void QgsVectorLayer::setExcludeAttributesWfs( const QSet<QString> &att )
3951{
3953
3954 QMap< QString, Qgis::FieldConfigurationFlags >::iterator flagsIt = mFieldConfigurationFlags.begin();
3955 for ( ; flagsIt != mFieldConfigurationFlags.end(); ++flagsIt )
3956 {
3957 flagsIt->setFlag( Qgis::FieldConfigurationFlag::HideFromWfs, att.contains( flagsIt.key() ) );
3958 }
3959 updateFields();
3960}
3961
3963{
3965
3966 if ( index < 0 || index >= fields().count() )
3967 return false;
3968
3969 if ( mFields.fieldOrigin( index ) == Qgis::FieldOrigin::Expression )
3970 {
3971 removeExpressionField( index );
3972 return true;
3973 }
3974
3975 if ( !mEditBuffer || !mDataProvider )
3976 return false;
3977
3978 return mEditBuffer->deleteAttribute( index );
3979}
3980
3981bool QgsVectorLayer::deleteAttributes( const QList<int> &attrs )
3982{
3984
3985 bool deleted = false;
3986
3987 // Remove multiple occurrences of same attribute
3988 QList<int> attrList = qgis::setToList( qgis::listToSet( attrs ) );
3989
3990 std::sort( attrList.begin(), attrList.end(), std::greater<int>() );
3991
3992 for ( int attr : std::as_const( attrList ) )
3993 {
3994 if ( deleteAttribute( attr ) )
3995 {
3996 deleted = true;
3997 }
3998 }
3999
4000 return deleted;
4001}
4002
4003bool QgsVectorLayer::deleteFeatureCascade( QgsFeatureId fid, QgsVectorLayer::DeleteContext *context )
4004{
4006
4007 if ( !mEditBuffer )
4008 return false;
4009
4010 if ( context && context->cascade )
4011 {
4012 const QList<QgsRelation> relations = context->project->relationManager()->referencedRelations( this );
4013 const bool hasRelationsOrJoins = !relations.empty() || mJoinBuffer->containsJoins();
4014 if ( hasRelationsOrJoins )
4015 {
4016 if ( context->mHandledFeatures.contains( this ) )
4017 {
4018 QgsFeatureIds &handledFeatureIds = context->mHandledFeatures[this];
4019 if ( handledFeatureIds.contains( fid ) )
4020 {
4021 // avoid endless recursion
4022 return false;
4023 }
4024 else
4025 {
4026 // add feature id
4027 handledFeatureIds << fid;
4028 }
4029 }
4030 else
4031 {
4032 // add layer and feature id
4033 context->mHandledFeatures.insert( this, QgsFeatureIds() << fid );
4034 }
4035
4036 for ( const QgsRelation &relation : relations )
4037 {
4038 //check if composition (and not association)
4039 switch ( relation.strength() )
4040 {
4042 {
4043 //get features connected over this relation
4044 QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( getFeature( fid ) );
4045 QgsFeatureIds childFeatureIds;
4046 QgsFeature childFeature;
4047 while ( relatedFeaturesIt.nextFeature( childFeature ) )
4048 {
4049 childFeatureIds.insert( childFeature.id() );
4050 }
4051 if ( childFeatureIds.count() > 0 )
4052 {
4053 relation.referencingLayer()->startEditing();
4054 relation.referencingLayer()->deleteFeatures( childFeatureIds, context );
4055 }
4056 break;
4057 }
4058
4060 break;
4061 }
4062 }
4063 }
4064 }
4065
4066 if ( mJoinBuffer->containsJoins() )
4067 mJoinBuffer->deleteFeature( fid, context );
4068
4069 bool res = mEditBuffer->deleteFeature( fid );
4070
4071 return res;
4072}
4073
4075{
4077
4078 if ( !mEditBuffer )
4079 return false;
4080
4081 return deleteFeatureCascade( fid, context );
4082}
4083
4085{
4087
4088 bool res = true;
4089
4090 if ( ( context && context->cascade ) || mJoinBuffer->containsJoins() )
4091 {
4092 // should ideally be "deleteFeaturesCascade" for performance!
4093 for ( QgsFeatureId fid : fids )
4094 res = deleteFeatureCascade( fid, context ) && res;
4095 }
4096 else
4097 {
4098 res = mEditBuffer && mEditBuffer->deleteFeatures( fids );
4099 }
4100
4101 if ( res )
4102 {
4103 mSelectedFeatureIds.subtract( fids ); // remove it from selection
4104 updateExtents();
4105 }
4106
4107 return res;
4108}
4109
4111{
4112 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
4114
4115 return mFields;
4116}
4117
4119{
4121
4122 QgsAttributeList pkAttributesList;
4123 if ( !mDataProvider )
4124 return pkAttributesList;
4125
4126 QgsAttributeList providerIndexes = mDataProvider->pkAttributeIndexes();
4127 for ( int i = 0; i < mFields.count(); ++i )
4128 {
4129 if ( mFields.fieldOrigin( i ) == Qgis::FieldOrigin::Provider && providerIndexes.contains( mFields.fieldOriginIndex( i ) ) )
4130 pkAttributesList << i;
4131 }
4132
4133 return pkAttributesList;
4134}
4135
4137{
4139
4140 if ( !mDataProvider )
4141 return static_cast< long long >( Qgis::FeatureCountState::UnknownCount );
4142 return mDataProvider->featureCount() + ( mEditBuffer && !mDataProvider->transaction() ? mEditBuffer->addedFeatures().size() - mEditBuffer->deletedFeatureIds().size() : 0 );
4143}
4144
4146{
4148
4149 const QgsFeatureIds deletedFeatures( mEditBuffer && !mDataProvider->transaction() ? mEditBuffer->deletedFeatureIds() : QgsFeatureIds() );
4150 const QgsFeatureMap addedFeatures( mEditBuffer && !mDataProvider->transaction() ? mEditBuffer->addedFeatures() : QgsFeatureMap() );
4151
4152 if ( mEditBuffer && !deletedFeatures.empty() )
4153 {
4154 if ( addedFeatures.size() > deletedFeatures.size() )
4156 else
4158 }
4159
4160 if ( ( !mEditBuffer || addedFeatures.empty() ) && mDataProvider && mDataProvider->empty() )
4162 else
4164}
4165
4166bool QgsVectorLayer::commitChanges( bool stopEditing )
4167{
4169
4170 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
4171 return project()->commitChanges( mCommitErrors, stopEditing, this );
4172
4173 mCommitErrors.clear();
4174
4175 if ( !mDataProvider )
4176 {
4177 mCommitErrors << tr( "ERROR: no provider" );
4178 return false;
4179 }
4180
4181 if ( !mEditBuffer )
4182 {
4183 mCommitErrors << tr( "ERROR: layer not editable" );
4184 return false;
4185 }
4186
4187 emit beforeCommitChanges( stopEditing );
4188
4189 if ( !mAllowCommit )
4190 return false;
4191
4192 mCommitChangesActive = true;
4193
4194 bool success = false;
4195 if ( mEditBuffer->editBufferGroup() )
4196 success = mEditBuffer->editBufferGroup()->commitChanges( mCommitErrors, stopEditing );
4197 else
4198 success = mEditBuffer->commitChanges( mCommitErrors );
4199
4200 mCommitChangesActive = false;
4201
4202 if ( !mDeletedFids.empty() )
4203 {
4204 emit featuresDeleted( mDeletedFids );
4205 mDeletedFids.clear();
4206 }
4207
4208 if ( success )
4209 {
4210 if ( stopEditing )
4211 {
4212 clearEditBuffer();
4213 }
4214 undoStack()->clear();
4215 emit afterCommitChanges();
4216 if ( stopEditing )
4217 emit editingStopped();
4218 }
4219 else
4220 {
4221 QgsMessageLog::logMessage( tr( "Commit errors:\n %1" ).arg( mCommitErrors.join( "\n "_L1 ) ) );
4222 }
4223
4224 updateFields();
4225
4226 mDataProvider->updateExtents();
4227
4228 if ( stopEditing )
4229 {
4230 mDataProvider->leaveUpdateMode();
4231 }
4232
4233 // This second call is required because OGR provider with JSON
4234 // driver might have changed fields order after the call to
4235 // leaveUpdateMode
4236 if ( mFields.names() != mDataProvider->fields().names() )
4237 {
4238 updateFields();
4239 }
4240
4242
4243 return success;
4244}
4245
4247{
4249
4250 return mCommitErrors;
4251}
4252
4253bool QgsVectorLayer::rollBack( bool deleteBuffer )
4254{
4256
4257 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
4258 return project()->rollBack( mCommitErrors, deleteBuffer, this );
4259
4260 if ( !mEditBuffer )
4261 {
4262 return false;
4263 }
4264
4265 if ( !mDataProvider )
4266 {
4267 mCommitErrors << tr( "ERROR: no provider" );
4268 return false;
4269 }
4270
4271 bool rollbackExtent = !mDataProvider->transaction() && ( !mEditBuffer->deletedFeatureIds().isEmpty() || !mEditBuffer->addedFeatures().isEmpty() || !mEditBuffer->changedGeometries().isEmpty() );
4272
4273 emit beforeRollBack();
4274
4275 mEditBuffer->rollBack();
4276
4277 emit afterRollBack();
4278
4279 if ( isModified() )
4280 {
4281 // new undo stack roll back method
4282 // old method of calling every undo could cause many canvas refreshes
4283 undoStack()->setIndex( 0 );
4284 }
4285
4286 updateFields();
4287
4288 if ( deleteBuffer )
4289 {
4290 delete mEditBuffer;
4291 mEditBuffer = nullptr;
4292 undoStack()->clear();
4293 }
4294 emit editingStopped();
4295
4296 if ( rollbackExtent )
4297 updateExtents();
4298
4299 mDataProvider->leaveUpdateMode();
4300
4302 return true;
4303}
4304
4306{
4308
4309 return mSelectedFeatureIds.size();
4310}
4311
4313{
4314 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
4316
4317 return mSelectedFeatureIds;
4318}
4319
4321{
4323
4324 QgsFeatureList features;
4325 features.reserve( mSelectedFeatureIds.count() );
4326 QgsFeature f;
4327
4329
4330 while ( it.nextFeature( f ) )
4331 {
4332 features.push_back( f );
4333 }
4334
4335 return features;
4336}
4337
4339{
4341
4342 if ( mSelectedFeatureIds.isEmpty() )
4343 return QgsFeatureIterator();
4344
4347
4348 if ( mSelectedFeatureIds.count() == 1 )
4349 request.setFilterFid( *mSelectedFeatureIds.constBegin() );
4350 else
4351 request.setFilterFids( mSelectedFeatureIds );
4352
4353 return getFeatures( request );
4354}
4355
4357{
4359
4360 if ( !mEditBuffer || !mDataProvider )
4361 return false;
4362
4363 if ( mGeometryOptions->isActive() )
4364 {
4365 for ( auto feature = features.begin(); feature != features.end(); ++feature )
4366 {
4367 QgsGeometry geom = feature->geometry();
4368 mGeometryOptions->apply( geom );
4369 feature->setGeometry( geom );
4370 }
4371 }
4372
4373 bool res = mEditBuffer->addFeatures( features );
4374 updateExtents();
4375
4376 if ( res && mJoinBuffer->containsJoins() )
4377 res = mJoinBuffer->addFeatures( features );
4378
4379 return res;
4380}
4381
4383{
4385
4386 // if layer is not spatial, it has not CRS!
4387 setCrs( ( isSpatial() && mDataProvider ) ? mDataProvider->crs() : QgsCoordinateReferenceSystem() );
4388}
4389
4391{
4393
4395 if ( exp.isField() )
4396 {
4397 return static_cast<const QgsExpressionNodeColumnRef *>( exp.rootNode() )->name();
4398 }
4399
4400 return QString();
4401}
4402
4404{
4406
4407 if ( mDisplayExpression == displayExpression )
4408 return;
4409
4410 mDisplayExpression = displayExpression;
4412}
4413
4415{
4417
4418 if ( !mDisplayExpression.isEmpty() || mFields.isEmpty() )
4419 {
4420 return mDisplayExpression;
4421 }
4422 else
4423 {
4424 const QString candidateName = QgsVectorLayerUtils::guessFriendlyIdentifierField( mFields );
4425 if ( !candidateName.isEmpty() )
4426 {
4427 return QgsExpression::quotedColumnRef( candidateName );
4428 }
4429 else
4430 {
4431 return QString();
4432 }
4433 }
4434}
4435
4437{
4439
4440 // display expressions are used as a fallback when no explicit map tip template is set
4441 return mapTipsEnabled() && ( !mapTipTemplate().isEmpty() || !displayExpression().isEmpty() );
4442}
4443
4445{
4447
4448 return ( mEditBuffer && mDataProvider );
4449}
4450
4452{
4453 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
4455
4458}
4459
4460bool QgsVectorLayer::isReadOnly() const
4461{
4463
4464 return mDataSourceReadOnly || mReadOnly;
4465}
4466
4467bool QgsVectorLayer::setReadOnly( bool readonly )
4468{
4470
4471 // exit if the layer is in editing mode
4472 if ( readonly && mEditBuffer )
4473 return false;
4474
4475 // exit if the data source is in read-only mode
4476 if ( !readonly && mDataSourceReadOnly )
4477 return false;
4478
4479 mReadOnly = readonly;
4480 emit readOnlyChanged();
4481 return true;
4482}
4483
4485{
4487
4488 if ( !mDataProvider )
4489 return false;
4490
4491 if ( mDataSourceReadOnly )
4492 return false;
4493
4494 return mDataProvider->capabilities() & QgsVectorDataProvider::EditingCapabilities && !mReadOnly;
4495}
4496
4498{
4500
4501 emit beforeModifiedCheck();
4502 return mEditBuffer && mEditBuffer->isModified();
4503}
4504
4505bool QgsVectorLayer::isAuxiliaryField( int index, int &srcIndex ) const
4506{
4508
4509 bool auxiliaryField = false;
4510 srcIndex = -1;
4511
4512 if ( !auxiliaryLayer() )
4513 return auxiliaryField;
4514
4515 if ( index >= 0 && fields().fieldOrigin( index ) == Qgis::FieldOrigin::Join )
4516 {
4517 const QgsVectorLayerJoinInfo *info = mJoinBuffer->joinForFieldIndex( index, fields(), srcIndex );
4518
4519 if ( info && info->joinLayerId() == auxiliaryLayer()->id() )
4520 auxiliaryField = true;
4521 }
4522
4523 return auxiliaryField;
4524}
4525
4527{
4529
4530 // we must allow setting a renderer if our geometry type is unknown
4531 // as this allows the renderer to be correctly set even for layers
4532 // with broken sources
4533 // (note that we allow REMOVING the renderer for non-spatial layers,
4534 // e.g. to permit removing the renderer when the layer changes from
4535 // a spatial layer to a non-spatial one)
4536 if ( r && !isSpatial() && mWkbType != Qgis::WkbType::Unknown )
4537 return;
4538
4539 if ( r != mRenderer )
4540 {
4541 delete mRenderer;
4542 mRenderer = r;
4543 mSymbolFeatureCounted = false;
4544 mSymbolFeatureCountMap.clear();
4545 mSymbolFeatureIdMap.clear();
4546
4547 if ( mRenderer )
4548 {
4549 const double refreshRate = QgsSymbolLayerUtils::rendererFrameRate( mRenderer );
4550 if ( refreshRate <= 0 )
4551 {
4552 mRefreshRendererTimer->stop();
4553 mRefreshRendererTimer->setInterval( 0 );
4554 }
4555 else
4556 {
4557 mRefreshRendererTimer->setInterval( 1000 / refreshRate );
4558 mRefreshRendererTimer->start();
4559 }
4560 }
4561
4562 emit rendererChanged();
4564 }
4565}
4566
4568{
4570
4571 if ( generator )
4572 {
4573 mRendererGenerators << generator;
4574 }
4575}
4576
4578{
4580
4581 for ( int i = mRendererGenerators.count() - 1; i >= 0; --i )
4582 {
4583 if ( mRendererGenerators.at( i )->id() == id )
4584 {
4585 delete mRendererGenerators.at( i );
4586 mRendererGenerators.removeAt( i );
4587 }
4588 }
4589}
4590
4591QList<const QgsFeatureRendererGenerator *> QgsVectorLayer::featureRendererGenerators() const
4592{
4593 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
4595
4596 QList< const QgsFeatureRendererGenerator * > res;
4597 for ( const QgsFeatureRendererGenerator *generator : mRendererGenerators )
4598 res << generator;
4599 return res;
4600}
4601
4602void QgsVectorLayer::beginEditCommand( const QString &text )
4603{
4605
4606 if ( !mDataProvider )
4607 {
4608 return;
4609 }
4610 if ( mDataProvider->transaction() )
4611 {
4612 QString ignoredError;
4613 mDataProvider->transaction()->createSavepoint( ignoredError );
4614 }
4615 undoStack()->beginMacro( text );
4616 mEditCommandActive = true;
4617 emit editCommandStarted( text );
4618}
4619
4621{
4623
4624 if ( !mDataProvider )
4625 {
4626 return;
4627 }
4628 undoStack()->endMacro();
4629 mEditCommandActive = false;
4630 if ( !mDeletedFids.isEmpty() )
4631 {
4632 if ( selectedFeatureCount() > 0 )
4633 {
4634 mSelectedFeatureIds.subtract( mDeletedFids );
4635 }
4636 emit featuresDeleted( mDeletedFids );
4637 mDeletedFids.clear();
4638 }
4639 emit editCommandEnded();
4640}
4641
4643{
4645
4646 if ( !mDataProvider )
4647 {
4648 return;
4649 }
4650 undoStack()->endMacro();
4651 undoStack()->undo();
4652
4653 // it's not directly possible to pop the last command off the stack (the destroyed one)
4654 // and delete, so we add a dummy obsolete command to force this to occur.
4655 // Pushing the new command deletes the destroyed one, and since the new
4656 // command is obsolete it's automatically deleted by the undo stack.
4657 auto command = std::make_unique< QUndoCommand >();
4658 command->setObsolete( true );
4659 undoStack()->push( command.release() );
4660
4661 mEditCommandActive = false;
4662 mDeletedFids.clear();
4663 emit editCommandDestroyed();
4664}
4665
4667{
4669
4670 return mJoinBuffer->addJoin( joinInfo );
4671}
4672
4673bool QgsVectorLayer::removeJoin( const QString &joinLayerId )
4674{
4676
4677 return mJoinBuffer->removeJoin( joinLayerId );
4678}
4679
4680const QList< QgsVectorLayerJoinInfo > QgsVectorLayer::vectorJoins() const
4681{
4683
4684 return mJoinBuffer->vectorJoins();
4685}
4686
4687int QgsVectorLayer::addExpressionField( const QString &exp, const QgsField &fld )
4688{
4690
4691 emit beforeAddingExpressionField( fld.name() );
4692 mExpressionFieldBuffer->addExpression( exp, fld );
4693 updateFields();
4694 int idx = mFields.indexFromName( fld.name() );
4695 emit attributeAdded( idx );
4696 return idx;
4697}
4698
4700{
4702
4703 emit beforeRemovingExpressionField( index );
4704 int oi = mFields.fieldOriginIndex( index );
4705 mExpressionFieldBuffer->removeExpression( oi );
4706 updateFields();
4707 emit attributeDeleted( index );
4708}
4709
4710QString QgsVectorLayer::expressionField( int index ) const
4711{
4713
4714 if ( mFields.fieldOrigin( index ) != Qgis::FieldOrigin::Expression )
4715 return QString();
4716
4717 int oi = mFields.fieldOriginIndex( index );
4718 if ( oi < 0 || oi >= mExpressionFieldBuffer->expressions().size() )
4719 return QString();
4720
4721 return mExpressionFieldBuffer->expressions().at( oi ).cachedExpression.expression();
4722}
4723
4724void QgsVectorLayer::updateExpressionField( int index, const QString &exp )
4725{
4727
4728 int oi = mFields.fieldOriginIndex( index );
4729 mExpressionFieldBuffer->updateExpression( oi, exp );
4730}
4731
4733{
4734 // non fatal for now -- the QgsVirtualLayerTask class is not thread safe and calls this
4736
4737 if ( !mDataProvider )
4738 return;
4739
4740 QgsFields oldFields = mFields;
4741
4742 mFields = mDataProvider->fields();
4743
4744 // added / removed fields
4745 if ( mEditBuffer )
4746 mEditBuffer->updateFields( mFields );
4747
4748 // joined fields
4749 if ( mJoinBuffer->containsJoins() )
4750 mJoinBuffer->updateFields( mFields );
4751
4752 if ( mExpressionFieldBuffer )
4753 mExpressionFieldBuffer->updateFields( mFields );
4754
4755 // set aliases and default values
4756 for ( auto aliasIt = mAttributeAliasMap.constBegin(); aliasIt != mAttributeAliasMap.constEnd(); ++aliasIt )
4757 {
4758 int index = mFields.lookupField( aliasIt.key() );
4759 if ( index < 0 )
4760 continue;
4761
4762 mFields[index].setAlias( aliasIt.value() );
4763 }
4764
4765 // set custom comments
4766 for ( auto customCommentIt = mAttributeCustomCommentMap.constBegin(); customCommentIt != mAttributeCustomCommentMap.constEnd(); ++customCommentIt )
4767 {
4768 int index = mFields.lookupField( customCommentIt.key() );
4769 if ( index < 0 )
4770 continue;
4771
4772 mFields[index].setCustomComment( customCommentIt.value() );
4773 }
4774
4775 for ( auto splitPolicyIt = mAttributeSplitPolicy.constBegin(); splitPolicyIt != mAttributeSplitPolicy.constEnd(); ++splitPolicyIt )
4776 {
4777 int index = mFields.lookupField( splitPolicyIt.key() );
4778 if ( index < 0 )
4779 continue;
4780
4781 mFields[index].setSplitPolicy( splitPolicyIt.value() );
4782 }
4783
4784 for ( auto duplicatePolicyIt = mAttributeDuplicatePolicy.constBegin(); duplicatePolicyIt != mAttributeDuplicatePolicy.constEnd(); ++duplicatePolicyIt )
4785 {
4786 int index = mFields.lookupField( duplicatePolicyIt.key() );
4787 if ( index < 0 )
4788 continue;
4789
4790 mFields[index].setDuplicatePolicy( duplicatePolicyIt.value() );
4791 }
4792
4793 for ( auto mergePolicyIt = mAttributeMergePolicy.constBegin(); mergePolicyIt != mAttributeMergePolicy.constEnd(); ++mergePolicyIt )
4794 {
4795 int index = mFields.lookupField( mergePolicyIt.key() );
4796 if ( index < 0 )
4797 continue;
4798
4799 mFields[index].setMergePolicy( mergePolicyIt.value() );
4800 }
4801
4802 // Update configuration flags
4803 QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
4804 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
4805 {
4806 int index = mFields.lookupField( flagsIt.key() );
4807 if ( index < 0 )
4808 continue;
4809
4810 mFields[index].setConfigurationFlags( flagsIt.value() );
4811 }
4812
4813 // Update default values
4814 mDefaultValueOnUpdateFields.clear();
4815 QMap< QString, QgsDefaultValue >::const_iterator defaultIt = mDefaultExpressionMap.constBegin();
4816 for ( ; defaultIt != mDefaultExpressionMap.constEnd(); ++defaultIt )
4817 {
4818 int index = mFields.lookupField( defaultIt.key() );
4819 if ( index < 0 )
4820 continue;
4821
4822 mFields[index].setDefaultValueDefinition( defaultIt.value() );
4823 if ( defaultIt.value().applyOnUpdate() )
4824 mDefaultValueOnUpdateFields.insert( index );
4825 }
4826
4827 QMap< QString, QgsFieldConstraints::Constraints >::const_iterator constraintIt = mFieldConstraints.constBegin();
4828 for ( ; constraintIt != mFieldConstraints.constEnd(); ++constraintIt )
4829 {
4830 int index = mFields.lookupField( constraintIt.key() );
4831 if ( index < 0 )
4832 continue;
4833
4834 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4835
4836 // always keep provider constraints intact
4837 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintNotNull ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintNotNull ) )
4839 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintUnique ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintUnique ) )
4841 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintExpression ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintExpression ) )
4843 mFields[index].setConstraints( constraints );
4844 }
4845
4846 QMap< QString, QPair< QString, QString > >::const_iterator constraintExpIt = mFieldConstraintExpressions.constBegin();
4847 for ( ; constraintExpIt != mFieldConstraintExpressions.constEnd(); ++constraintExpIt )
4848 {
4849 int index = mFields.lookupField( constraintExpIt.key() );
4850 if ( index < 0 )
4851 continue;
4852
4853 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4854
4855 // always keep provider constraints intact
4857 continue;
4858
4859 constraints.setConstraintExpression( constraintExpIt.value().first, constraintExpIt.value().second );
4860 mFields[index].setConstraints( constraints );
4861 }
4862
4863 QMap< QPair< QString, QgsFieldConstraints::Constraint >, QgsFieldConstraints::ConstraintStrength >::const_iterator constraintStrengthIt = mFieldConstraintStrength.constBegin();
4864 for ( ; constraintStrengthIt != mFieldConstraintStrength.constEnd(); ++constraintStrengthIt )
4865 {
4866 int index = mFields.lookupField( constraintStrengthIt.key().first );
4867 if ( index < 0 )
4868 continue;
4869
4870 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4871
4872 // always keep provider constraints intact
4874 continue;
4875
4876 constraints.setConstraintStrength( constraintStrengthIt.key().second, constraintStrengthIt.value() );
4877 mFields[index].setConstraints( constraints );
4878 }
4879
4880 auto fieldWidgetIterator = mFieldWidgetSetups.constBegin();
4881 for ( ; fieldWidgetIterator != mFieldWidgetSetups.constEnd(); ++fieldWidgetIterator )
4882 {
4883 int index = mFields.indexOf( fieldWidgetIterator.key() );
4884 if ( index < 0 )
4885 continue;
4886
4887 mFields[index].setEditorWidgetSetup( fieldWidgetIterator.value() );
4888 }
4889
4890 if ( oldFields != mFields )
4891 {
4892 emit updatedFields();
4893 mEditFormConfig.setFields( mFields );
4894 }
4895}
4896
4897QVariant QgsVectorLayer::defaultValue( int index, const QgsFeature &feature, QgsExpressionContext *context ) const
4898{
4900
4901 if ( index < 0 || index >= mFields.count() || !mDataProvider )
4902 return QVariant();
4903
4904 QString expression = mFields.at( index ).defaultValueDefinition().expression();
4905 if ( expression.isEmpty() )
4906 return mDataProvider->defaultValue( index );
4907
4908 QgsExpressionContext *evalContext = context;
4909 std::unique_ptr< QgsExpressionContext > tempContext;
4910 if ( !evalContext )
4911 {
4912 // no context passed, so we create a default one
4913 tempContext = std::make_unique<QgsExpressionContext>( QgsExpressionContextUtils::globalProjectLayerScopes( this ) );
4914 evalContext = tempContext.get();
4915 }
4916
4917 if ( feature.isValid() )
4918 {
4920 featScope->setFeature( feature );
4921 featScope->setFields( feature.fields() );
4922 evalContext->appendScope( featScope );
4923 }
4924
4925 QVariant val;
4926 QgsExpression exp( expression );
4927 exp.prepare( evalContext );
4928 if ( exp.hasEvalError() )
4929 {
4930 QgsLogger::warning( "Error evaluating default value: " + exp.evalErrorString() );
4931 }
4932 else
4933 {
4934 val = exp.evaluate( evalContext );
4935 }
4936
4937 if ( feature.isValid() )
4938 {
4939 delete evalContext->popScope();
4940 }
4941
4942 return val;
4943}
4944
4946{
4948
4949 if ( index < 0 || index >= mFields.count() )
4950 return;
4951
4952 if ( definition.isValid() )
4953 {
4954 mDefaultExpressionMap.insert( mFields.at( index ).name(), definition );
4955 }
4956 else
4957 {
4958 mDefaultExpressionMap.remove( mFields.at( index ).name() );
4959 }
4960 updateFields();
4961}
4962
4964{
4966
4967 if ( index < 0 || index >= mFields.count() )
4968 return QgsDefaultValue();
4969 else
4970 return mFields.at( index ).defaultValueDefinition();
4971}
4972
4973QSet<QVariant> QgsVectorLayer::uniqueValues( int index, int limit ) const
4974{
4976
4977 QSet<QVariant> uniqueValues;
4978 if ( !mDataProvider )
4979 {
4980 return uniqueValues;
4981 }
4982
4983 Qgis::FieldOrigin origin = mFields.fieldOrigin( index );
4984 switch ( origin )
4985 {
4987 return uniqueValues;
4988
4989 case Qgis::FieldOrigin::Provider: //a provider field
4990 {
4991 uniqueValues = mDataProvider->uniqueValues( index, limit );
4992
4993 if ( mEditBuffer && !mDataProvider->transaction() )
4994 {
4995 QSet<QString> vals;
4996 const auto constUniqueValues = uniqueValues;
4997 for ( const QVariant &v : constUniqueValues )
4998 {
4999 vals << v.toString();
5000 }
5001
5002 QgsFeatureMap added = mEditBuffer->addedFeatures();
5003 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
5004 while ( addedIt.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
5005 {
5006 addedIt.next();
5007 QVariant v = addedIt.value().attribute( index );
5008 if ( v.isValid() )
5009 {
5010 QString vs = v.toString();
5011 if ( !vals.contains( vs ) )
5012 {
5013 vals << vs;
5014 uniqueValues << v;
5015 }
5016 }
5017 }
5018
5019 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
5020 while ( it.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
5021 {
5022 it.next();
5023 QVariant v = it.value().value( index );
5024 if ( v.isValid() )
5025 {
5026 QString vs = v.toString();
5027 if ( !vals.contains( vs ) )
5028 {
5029 vals << vs;
5030 uniqueValues << v;
5031 }
5032 }
5033 }
5034 }
5035
5036 return uniqueValues;
5037 }
5038
5040 // the layer is editable, but in certain cases it can still be avoided going through all features
5041 if ( mDataProvider->transaction()
5042 || ( mEditBuffer->deletedFeatureIds().isEmpty() && mEditBuffer->addedFeatures().isEmpty() && !mEditBuffer->deletedAttributeIds().contains( index ) && mEditBuffer->changedAttributeValues().isEmpty() ) )
5043 {
5044 uniqueValues = mDataProvider->uniqueValues( index, limit );
5045 return uniqueValues;
5046 }
5047 [[fallthrough]];
5048 //we need to go through each feature
5051 {
5052 QgsAttributeList attList;
5053 attList << index;
5054
5056
5057 QgsFeature f;
5058 QVariant currentValue;
5059 QHash<QString, QVariant> val;
5060 while ( fit.nextFeature( f ) )
5061 {
5062 currentValue = f.attribute( index );
5063 val.insert( currentValue.toString(), currentValue );
5064 if ( limit >= 0 && val.size() >= limit )
5065 {
5066 break;
5067 }
5068 }
5069
5070 return qgis::listToSet( val.values() );
5071 }
5072 }
5073
5074 Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
5075 return uniqueValues;
5076}
5077
5078QStringList QgsVectorLayer::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
5079{
5081
5082 QStringList results;
5083 if ( !mDataProvider )
5084 {
5085 return results;
5086 }
5087
5088 Qgis::FieldOrigin origin = mFields.fieldOrigin( index );
5089 switch ( origin )
5090 {
5092 return results;
5093
5094 case Qgis::FieldOrigin::Provider: //a provider field
5095 {
5096 results = mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
5097
5098 if ( mEditBuffer && !mDataProvider->transaction() )
5099 {
5100 QgsFeatureMap added = mEditBuffer->addedFeatures();
5101 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
5102 while ( addedIt.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
5103 {
5104 addedIt.next();
5105 QVariant v = addedIt.value().attribute( index );
5106 if ( v.isValid() )
5107 {
5108 QString vs = v.toString();
5109 if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
5110 {
5111 results << vs;
5112 }
5113 }
5114 }
5115
5116 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
5117 while ( it.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
5118 {
5119 it.next();
5120 QVariant v = it.value().value( index );
5121 if ( v.isValid() )
5122 {
5123 QString vs = v.toString();
5124 if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
5125 {
5126 results << vs;
5127 }
5128 }
5129 }
5130 }
5131
5132 return results;
5133 }
5134
5136 // the layer is editable, but in certain cases it can still be avoided going through all features
5137 if ( mDataProvider->transaction()
5138 || ( mEditBuffer->deletedFeatureIds().isEmpty() && mEditBuffer->addedFeatures().isEmpty() && !mEditBuffer->deletedAttributeIds().contains( index ) && mEditBuffer->changedAttributeValues().isEmpty() ) )
5139 {
5140 return mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
5141 }
5142 [[fallthrough]];
5143 //we need to go through each feature
5146 {
5147 QgsAttributeList attList;
5148 attList << index;
5149
5150 QgsFeatureRequest request;
5151 request.setSubsetOfAttributes( attList );
5153 QString fieldName = mFields.at( index ).name();
5154 request.setFilterExpression( u"\"%1\" ILIKE '%%2%'"_s.arg( fieldName, substring ) );
5155 QgsFeatureIterator fit = getFeatures( request );
5156
5157 QgsFeature f;
5158 QString currentValue;
5159 while ( fit.nextFeature( f ) )
5160 {
5161 currentValue = f.attribute( index ).toString();
5162 if ( !results.contains( currentValue ) )
5163 results << currentValue;
5164
5165 if ( ( limit >= 0 && results.size() >= limit ) || ( feedback && feedback->isCanceled() ) )
5166 {
5167 break;
5168 }
5169 }
5170
5171 return results;
5172 }
5173 }
5174
5175 Q_ASSERT_X( false, "QgsVectorLayer::uniqueStringsMatching()", "Unknown source of the field!" );
5176 return results;
5177}
5178
5179QVariant QgsVectorLayer::minimumValue( int index ) const
5180{
5182
5183 QVariant minimum;
5184 minimumOrMaximumValue( index, &minimum, nullptr );
5185 return minimum;
5186}
5187
5188QVariant QgsVectorLayer::maximumValue( int index ) const
5189{
5191
5192 QVariant maximum;
5193 minimumOrMaximumValue( index, nullptr, &maximum );
5194 return maximum;
5195}
5196
5197void QgsVectorLayer::minimumAndMaximumValue( int index, QVariant &minimum, QVariant &maximum ) const
5198{
5200
5201 minimumOrMaximumValue( index, &minimum, &maximum );
5202}
5203
5204void QgsVectorLayer::minimumOrMaximumValue( int index, QVariant *minimum, QVariant *maximum ) const
5205{
5207
5208 if ( minimum )
5209 *minimum = QVariant();
5210 if ( maximum )
5211 *maximum = QVariant();
5212
5213 if ( !mDataProvider )
5214 {
5215 return;
5216 }
5217
5218 Qgis::FieldOrigin origin = mFields.fieldOrigin( index );
5219
5220 switch ( origin )
5221 {
5223 {
5224 return;
5225 }
5226
5227 case Qgis::FieldOrigin::Provider: //a provider field
5228 {
5229 if ( minimum )
5230 *minimum = mDataProvider->minimumValue( index );
5231 if ( maximum )
5232 *maximum = mDataProvider->maximumValue( index );
5233 if ( mEditBuffer && !mDataProvider->transaction() )
5234 {
5235 const QgsFeatureMap added = mEditBuffer->addedFeatures();
5236 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
5237 while ( addedIt.hasNext() )
5238 {
5239 addedIt.next();
5240 const QVariant v = addedIt.value().attribute( index );
5241 if ( minimum && v.isValid() && qgsVariantLessThan( v, *minimum ) )
5242 *minimum = v;
5243 if ( maximum && v.isValid() && qgsVariantGreaterThan( v, *maximum ) )
5244 *maximum = v;
5245 }
5246
5247 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
5248 while ( it.hasNext() )
5249 {
5250 it.next();
5251 const QVariant v = it.value().value( index );
5252 if ( minimum && v.isValid() && qgsVariantLessThan( v, *minimum ) )
5253 *minimum = v;
5254 if ( maximum && v.isValid() && qgsVariantGreaterThan( v, *maximum ) )
5255 *maximum = v;
5256 }
5257 }
5258 return;
5259 }
5260
5262 {
5263 // the layer is editable, but in certain cases it can still be avoided going through all features
5264 if ( mDataProvider->transaction()
5265 || ( mEditBuffer->deletedFeatureIds().isEmpty() && mEditBuffer->addedFeatures().isEmpty() && !mEditBuffer->deletedAttributeIds().contains( index ) && mEditBuffer->changedAttributeValues().isEmpty() ) )
5266 {
5267 if ( minimum )
5268 *minimum = mDataProvider->minimumValue( index );
5269 if ( maximum )
5270 *maximum = mDataProvider->maximumValue( index );
5271 return;
5272 }
5273 }
5274 [[fallthrough]];
5275 // no choice but to go through all features
5278 {
5279 // we need to go through each feature
5280 QgsAttributeList attList;
5281 attList << index;
5282
5283 QgsFeatureIterator fit = getFeatures( QgsFeatureRequest().setFlags( Qgis::FeatureRequestFlag::NoGeometry ).setSubsetOfAttributes( attList ) );
5284
5285 QgsFeature f;
5286 bool firstValue = true;
5287 while ( fit.nextFeature( f ) )
5288 {
5289 const QVariant currentValue = f.attribute( index );
5290 if ( QgsVariantUtils::isNull( currentValue ) )
5291 continue;
5292
5293 if ( firstValue )
5294 {
5295 if ( minimum )
5296 *minimum = currentValue;
5297 if ( maximum )
5298 *maximum = currentValue;
5299 firstValue = false;
5300 }
5301 else
5302 {
5303 if ( minimum && currentValue.isValid() && qgsVariantLessThan( currentValue, *minimum ) )
5304 *minimum = currentValue;
5305 if ( maximum && currentValue.isValid() && qgsVariantGreaterThan( currentValue, *maximum ) )
5306 *maximum = currentValue;
5307 }
5308 }
5309 return;
5310 }
5311 }
5312
5313 Q_ASSERT_X( false, "QgsVectorLayer::minimumOrMaximumValue()", "Unknown source of the field!" );
5314}
5315
5316void QgsVectorLayer::createEditBuffer()
5317{
5319
5320 if ( mEditBuffer )
5321 clearEditBuffer();
5322
5323 if ( mDataProvider->transaction() )
5324 {
5325 mEditBuffer = new QgsVectorLayerEditPassthrough( this );
5326
5327 connect( mDataProvider->transaction(), &QgsTransaction::dirtied, this, &QgsVectorLayer::onDirtyTransaction, Qt::UniqueConnection );
5328 }
5329 else
5330 {
5331 mEditBuffer = new QgsVectorLayerEditBuffer( this );
5332 }
5333 // forward signals
5334 connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::invalidateSymbolCountedFlag );
5335 connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::layerModified ); // TODO[MD]: necessary?
5336 //connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::triggerRepaint ); // TODO[MD]: works well?
5337 connect( mEditBuffer, &QgsVectorLayerEditBuffer::featureAdded, this, &QgsVectorLayer::onFeatureAdded );
5338 connect( mEditBuffer, &QgsVectorLayerEditBuffer::featureDeleted, this, &QgsVectorLayer::onFeatureDeleted );
5349}
5350
5351void QgsVectorLayer::clearEditBuffer()
5352{
5354
5355 delete mEditBuffer;
5356 mEditBuffer = nullptr;
5357}
5358
5361 const QString &fieldOrExpression,
5363 QgsExpressionContext *context,
5364 bool *ok,
5365 QgsFeatureIds *fids,
5366 QgsFeedback *feedback,
5367 QString *error
5368) const
5369{
5370 // non fatal for now -- the aggregate expression functions are not thread safe and call this
5372
5373 if ( ok )
5374 *ok = false;
5375 if ( error )
5376 error->clear();
5377
5378 if ( !mDataProvider )
5379 {
5380 if ( error )
5381 *error = tr( "Layer is invalid" );
5382 return QVariant();
5383 }
5384
5385 // test if we are calculating based on a field
5386 const int attrIndex = QgsExpression::expressionToLayerFieldIndex( fieldOrExpression, this );
5387 if ( attrIndex >= 0 )
5388 {
5389 // aggregate is based on a field - if it's a provider field, we could possibly hand over the calculation
5390 // to the provider itself
5391 Qgis::FieldOrigin origin = mFields.fieldOrigin( attrIndex );
5392 if ( origin == Qgis::FieldOrigin::Provider )
5393 {
5394 bool providerOk = false;
5395 QVariant val = mDataProvider->aggregate( aggregate, attrIndex, parameters, context, providerOk, fids );
5396 if ( providerOk )
5397 {
5398 // provider handled calculation
5399 if ( ok )
5400 *ok = true;
5401 return val;
5402 }
5403 }
5404 }
5405
5406 // fallback to using aggregate calculator to determine aggregate
5407 QgsAggregateCalculator c( this );
5408 if ( fids )
5409 c.setFidsFilter( *fids );
5410 c.setParameters( parameters );
5411 bool aggregateOk = false;
5412 const QVariant result = c.calculate( aggregate, fieldOrExpression, context, &aggregateOk, feedback );
5413 if ( ok )
5414 *ok = aggregateOk;
5415 if ( !aggregateOk && error )
5416 *error = c.lastError();
5417
5418 return result;
5419}
5420
5422{
5424
5425 if ( mFeatureBlendMode == featureBlendMode )
5426 return;
5427
5428 mFeatureBlendMode = featureBlendMode;
5431}
5432
5433QPainter::CompositionMode QgsVectorLayer::featureBlendMode() const
5434{
5435 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
5437
5438 return mFeatureBlendMode;
5439}
5440
5441void QgsVectorLayer::readSldLabeling( const QDomNode &node )
5442{
5444
5445 setLabeling( nullptr ); // start with no labeling
5446 setLabelsEnabled( false );
5447
5448 QDomElement element = node.toElement();
5449 if ( element.isNull() )
5450 return;
5451
5452 QDomElement userStyleElem = element.firstChildElement( u"UserStyle"_s );
5453 if ( userStyleElem.isNull() )
5454 {
5455 QgsDebugMsgLevel( u"Info: UserStyle element not found."_s, 4 );
5456 return;
5457 }
5458
5459 QDomElement featTypeStyleElem = userStyleElem.firstChildElement( u"FeatureTypeStyle"_s );
5460 if ( featTypeStyleElem.isNull() )
5461 {
5462 QgsDebugMsgLevel( u"Info: FeatureTypeStyle element not found."_s, 4 );
5463 return;
5464 }
5465
5466 // create empty FeatureTypeStyle element to merge TextSymbolizer's Rule's from all FeatureTypeStyle's
5467 QDomElement mergedFeatTypeStyle = featTypeStyleElem.cloneNode( false ).toElement();
5468
5469 // use the RuleRenderer when more rules are present or the rule
5470 // has filters or min/max scale denominators set,
5471 // otherwise use the Simple labeling
5472 bool needRuleBasedLabeling = false;
5473 int ruleCount = 0;
5474
5475 while ( !featTypeStyleElem.isNull() )
5476 {
5477 QDomElement ruleElem = featTypeStyleElem.firstChildElement( u"Rule"_s );
5478 while ( !ruleElem.isNull() )
5479 {
5480 // test rule children element to check if we need to create RuleRenderer
5481 // and if the rule has a symbolizer
5482 bool hasTextSymbolizer = false;
5483 bool hasRuleBased = false;
5484 QDomElement ruleChildElem = ruleElem.firstChildElement();
5485 while ( !ruleChildElem.isNull() )
5486 {
5487 // rule has filter or min/max scale denominator, use the RuleRenderer
5488 if ( ruleChildElem.localName() == "Filter"_L1 || ruleChildElem.localName() == "MinScaleDenominator"_L1 || ruleChildElem.localName() == "MaxScaleDenominator"_L1 )
5489 {
5490 hasRuleBased = true;
5491 }
5492 // rule has a renderer symbolizer, not a text symbolizer
5493 else if ( ruleChildElem.localName() == "TextSymbolizer"_L1 )
5494 {
5495 QgsDebugMsgLevel( u"Info: TextSymbolizer element found"_s, 4 );
5496 hasTextSymbolizer = true;
5497 }
5498
5499 ruleChildElem = ruleChildElem.nextSiblingElement();
5500 }
5501
5502 if ( hasTextSymbolizer )
5503 {
5504 ruleCount++;
5505
5506 // append a clone of all Rules to the merged FeatureTypeStyle element
5507 mergedFeatTypeStyle.appendChild( ruleElem.cloneNode().toElement() );
5508
5509 if ( hasRuleBased )
5510 {
5511 QgsDebugMsgLevel( u"Info: Filter or Min/MaxScaleDenominator element found: need a RuleBasedLabeling"_s, 4 );
5512 needRuleBasedLabeling = true;
5513 }
5514 }
5515
5516 // more rules present, use the RuleRenderer
5517 if ( ruleCount > 1 )
5518 {
5519 QgsDebugMsgLevel( u"Info: More Rule elements found: need a RuleBasedLabeling"_s, 4 );
5520 needRuleBasedLabeling = true;
5521 }
5522
5523 // not use the rule based labeling if no rules with textSymbolizer
5524 if ( ruleCount == 0 )
5525 {
5526 needRuleBasedLabeling = false;
5527 }
5528
5529 ruleElem = ruleElem.nextSiblingElement( u"Rule"_s );
5530 }
5531 featTypeStyleElem = featTypeStyleElem.nextSiblingElement( u"FeatureTypeStyle"_s );
5532 }
5533
5534 if ( ruleCount == 0 )
5535 {
5536 QgsDebugMsgLevel( u"Info: No TextSymbolizer element."_s, 4 );
5537 return;
5538 }
5539
5540 QDomElement ruleElem = mergedFeatTypeStyle.firstChildElement( u"Rule"_s );
5541
5542 if ( needRuleBasedLabeling )
5543 {
5544 QgsDebugMsgLevel( u"Info: rule based labeling"_s, 4 );
5545 QgsRuleBasedLabeling::Rule *rootRule = new QgsRuleBasedLabeling::Rule( nullptr );
5546 while ( !ruleElem.isNull() )
5547 {
5548 QString label, description, filterExp;
5549 int scaleMinDenom = 0, scaleMaxDenom = 0;
5550 QgsPalLayerSettings settings;
5551
5552 // retrieve the Rule element child nodes
5553 QDomElement childElem = ruleElem.firstChildElement();
5554 while ( !childElem.isNull() )
5555 {
5556 if ( childElem.localName() == "Name"_L1 )
5557 {
5558 // <se:Name> tag contains the rule identifier,
5559 // so prefer title tag for the label property value
5560 if ( label.isEmpty() )
5561 label = childElem.firstChild().nodeValue();
5562 }
5563 else if ( childElem.localName() == "Description"_L1 )
5564 {
5565 // <se:Description> can contains a title and an abstract
5566 QDomElement titleElem = childElem.firstChildElement( u"Title"_s );
5567 if ( !titleElem.isNull() )
5568 {
5569 label = titleElem.firstChild().nodeValue();
5570 }
5571
5572 QDomElement abstractElem = childElem.firstChildElement( u"Abstract"_s );
5573 if ( !abstractElem.isNull() )
5574 {
5575 description = abstractElem.firstChild().nodeValue();
5576 }
5577 }
5578 else if ( childElem.localName() == "Abstract"_L1 )
5579 {
5580 // <sld:Abstract> (v1.0)
5581 description = childElem.firstChild().nodeValue();
5582 }
5583 else if ( childElem.localName() == "Title"_L1 )
5584 {
5585 // <sld:Title> (v1.0)
5586 label = childElem.firstChild().nodeValue();
5587 }
5588 else if ( childElem.localName() == "Filter"_L1 )
5589 {
5590 QgsExpression *filter = QgsOgcUtils::expressionFromOgcFilter( childElem );
5591 if ( filter )
5592 {
5593 if ( filter->hasParserError() )
5594 {
5595 QgsDebugMsgLevel( u"SLD Filter parsing error: %1"_s.arg( filter->parserErrorString() ), 3 );
5596 }
5597 else
5598 {
5599 filterExp = filter->expression();
5600 }
5601 delete filter;
5602 }
5603 }
5604 else if ( childElem.localName() == "MinScaleDenominator"_L1 )
5605 {
5606 bool ok;
5607 int v = childElem.firstChild().nodeValue().toInt( &ok );
5608 if ( ok )
5609 scaleMinDenom = v;
5610 }
5611 else if ( childElem.localName() == "MaxScaleDenominator"_L1 )
5612 {
5613 bool ok;
5614 int v = childElem.firstChild().nodeValue().toInt( &ok );
5615 if ( ok )
5616 scaleMaxDenom = v;
5617 }
5618 else if ( childElem.localName() == "TextSymbolizer"_L1 )
5619 {
5620 readSldTextSymbolizer( childElem, settings );
5621 }
5622
5623 childElem = childElem.nextSiblingElement();
5624 }
5625
5626 QgsRuleBasedLabeling::Rule *ruleLabeling = new QgsRuleBasedLabeling::Rule( new QgsPalLayerSettings( settings ), scaleMinDenom, scaleMaxDenom, filterExp, label );
5627 rootRule->appendChild( ruleLabeling );
5628
5629 ruleElem = ruleElem.nextSiblingElement();
5630 }
5631
5632 setLabeling( new QgsRuleBasedLabeling( rootRule ) );
5633 setLabelsEnabled( true );
5634 }
5635 else
5636 {
5637 QgsDebugMsgLevel( u"Info: simple labeling"_s, 4 );
5638 // retrieve the TextSymbolizer element child node
5639 QDomElement textSymbolizerElem = ruleElem.firstChildElement( u"TextSymbolizer"_s );
5640 QgsPalLayerSettings s;
5641 if ( readSldTextSymbolizer( textSymbolizerElem, s ) )
5642 {
5643 setLabeling( new QgsVectorLayerSimpleLabeling( s ) );
5644 setLabelsEnabled( true );
5645 }
5646 }
5647}
5648
5649bool QgsVectorLayer::readSldTextSymbolizer( const QDomNode &node, QgsPalLayerSettings &settings ) const
5650{
5652
5653 if ( node.localName() != "TextSymbolizer"_L1 )
5654 {
5655 QgsDebugMsgLevel( u"Not a TextSymbolizer element: %1"_s.arg( node.localName() ), 3 );
5656 return false;
5657 }
5658 QDomElement textSymbolizerElem = node.toElement();
5659 // Label
5660 QDomElement labelElem = textSymbolizerElem.firstChildElement( u"Label"_s );
5661 if ( !labelElem.isNull() )
5662 {
5663 QDomElement propertyNameElem = labelElem.firstChildElement( u"PropertyName"_s );
5664 if ( !propertyNameElem.isNull() )
5665 {
5666 // set labeling defaults
5667
5668 // label attribute
5669 QString labelAttribute = propertyNameElem.text();
5670 settings.fieldName = labelAttribute;
5671 settings.isExpression = false;
5672
5673 int fieldIndex = mFields.lookupField( labelAttribute );
5674 if ( fieldIndex == -1 )
5675 {
5676 // label attribute is not in columns, check if it is an expression
5677 QgsExpression exp( labelAttribute );
5678 if ( !exp.hasEvalError() )
5679 {
5680 settings.isExpression = true;
5681 }
5682 else
5683 {
5684 QgsDebugMsgLevel( u"SLD label attribute error: %1"_s.arg( exp.evalErrorString() ), 3 );
5685 }
5686 }
5687 }
5688 else
5689 {
5690 QgsDebugMsgLevel( u"Info: PropertyName element not found."_s, 4 );
5691 return false;
5692 }
5693 }
5694 else
5695 {
5696 QgsDebugMsgLevel( u"Info: Label element not found."_s, 4 );
5697 return false;
5698 }
5699
5701 if ( textSymbolizerElem.hasAttribute( u"uom"_s ) )
5702 {
5703 sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( textSymbolizerElem.attribute( u"uom"_s ) );
5704 }
5705
5706 QString fontFamily = u"Sans-Serif"_s;
5707 double fontPointSize = 10;
5709 int fontWeight = -1;
5710 bool fontItalic = false;
5711 bool fontUnderline = false;
5712
5713 // Font
5714 QDomElement fontElem = textSymbolizerElem.firstChildElement( u"Font"_s );
5715 if ( !fontElem.isNull() )
5716 {
5717 QgsStringMap fontSvgParams = QgsSymbolLayerUtils::getSvgParameterList( fontElem );
5718 for ( QgsStringMap::iterator it = fontSvgParams.begin(); it != fontSvgParams.end(); ++it )
5719 {
5720 QgsDebugMsgLevel( u"found fontSvgParams %1: %2"_s.arg( it.key(), it.value() ), 4 );
5721
5722 if ( it.key() == "font-family"_L1 )
5723 {
5724 fontFamily = it.value();
5725 }
5726 else if ( it.key() == "font-style"_L1 )
5727 {
5728 fontItalic = ( it.value() == "italic"_L1 ) || ( it.value() == "Italic"_L1 );
5729 }
5730 else if ( it.key() == "font-size"_L1 )
5731 {
5732 bool ok;
5733 double fontSize = it.value().toDouble( &ok );
5734 if ( ok )
5735 {
5736 fontPointSize = fontSize;
5737 fontUnitSize = sldUnitSize;
5738 }
5739 }
5740 else if ( it.key() == "font-weight"_L1 )
5741 {
5742 if ( ( it.value() == "bold"_L1 ) || ( it.value() == "Bold"_L1 ) )
5743 fontWeight = QFont::Bold;
5744 }
5745 else if ( it.key() == "font-underline"_L1 )
5746 {
5747 fontUnderline = ( it.value() == "underline"_L1 ) || ( it.value() == "Underline"_L1 );
5748 }
5749 }
5750 }
5751
5752 QgsTextFormat format;
5753 QFont font( fontFamily, 1, fontWeight, fontItalic );
5754 font.setUnderline( fontUnderline );
5755 format.setFont( font );
5756 format.setSize( fontPointSize );
5757 format.setSizeUnit( fontUnitSize );
5758
5759 // Fill
5760 QDomElement fillElem = textSymbolizerElem.firstChildElement( u"Fill"_s );
5761 QColor textColor;
5762 Qt::BrushStyle textBrush = Qt::SolidPattern;
5763 QgsSymbolLayerUtils::fillFromSld( fillElem, textBrush, textColor );
5764 if ( textColor.isValid() )
5765 {
5766 QgsDebugMsgLevel( u"Info: textColor %1."_s.arg( QVariant( textColor ).toString() ), 4 );
5767 format.setColor( textColor );
5768 }
5769
5770 QgsTextBufferSettings bufferSettings;
5771
5772 // Halo
5773 QDomElement haloElem = textSymbolizerElem.firstChildElement( u"Halo"_s );
5774 if ( !haloElem.isNull() )
5775 {
5776 bufferSettings.setEnabled( true );
5777 bufferSettings.setSize( 1 );
5778
5779 QDomElement radiusElem = haloElem.firstChildElement( u"Radius"_s );
5780 if ( !radiusElem.isNull() )
5781 {
5782 bool ok;
5783 double bufferSize = radiusElem.text().toDouble( &ok );
5784 if ( ok )
5785 {
5786 bufferSettings.setSize( bufferSize );
5787 bufferSettings.setSizeUnit( sldUnitSize );
5788 }
5789 }
5790
5791 QDomElement haloFillElem = haloElem.firstChildElement( u"Fill"_s );
5792 QColor bufferColor;
5793 Qt::BrushStyle bufferBrush = Qt::SolidPattern;
5794 QgsSymbolLayerUtils::fillFromSld( haloFillElem, bufferBrush, bufferColor );
5795 if ( bufferColor.isValid() )
5796 {
5797 QgsDebugMsgLevel( u"Info: bufferColor %1."_s.arg( QVariant( bufferColor ).toString() ), 4 );
5798 bufferSettings.setColor( bufferColor );
5799 }
5800 }
5801
5802 // LabelPlacement
5803 QDomElement labelPlacementElem = textSymbolizerElem.firstChildElement( u"LabelPlacement"_s );
5804 if ( !labelPlacementElem.isNull() )
5805 {
5806 // PointPlacement
5807 QDomElement pointPlacementElem = labelPlacementElem.firstChildElement( u"PointPlacement"_s );
5808 if ( !pointPlacementElem.isNull() )
5809 {
5812 {
5814 }
5815
5816 QDomElement displacementElem = pointPlacementElem.firstChildElement( u"Displacement"_s );
5817 if ( !displacementElem.isNull() )
5818 {
5819 QDomElement displacementXElem = displacementElem.firstChildElement( u"DisplacementX"_s );
5820 if ( !displacementXElem.isNull() )
5821 {
5822 bool ok;
5823 double xOffset = displacementXElem.text().toDouble( &ok );
5824 if ( ok )
5825 {
5826 settings.xOffset = xOffset;
5827 settings.offsetUnits = sldUnitSize;
5828 }
5829 }
5830 QDomElement displacementYElem = displacementElem.firstChildElement( u"DisplacementY"_s );
5831 if ( !displacementYElem.isNull() )
5832 {
5833 bool ok;
5834 double yOffset = displacementYElem.text().toDouble( &ok );
5835 if ( ok )
5836 {
5837 settings.yOffset = yOffset;
5838 settings.offsetUnits = sldUnitSize;
5839 }
5840 }
5841 }
5842 QDomElement anchorPointElem = pointPlacementElem.firstChildElement( u"AnchorPoint"_s );
5843 if ( !anchorPointElem.isNull() )
5844 {
5845 QDomElement anchorPointXElem = anchorPointElem.firstChildElement( u"AnchorPointX"_s );
5846 if ( !anchorPointXElem.isNull() )
5847 {
5848 bool ok;
5849 double xOffset = anchorPointXElem.text().toDouble( &ok );
5850 if ( ok )
5851 {
5852 settings.xOffset = xOffset;
5853 settings.offsetUnits = sldUnitSize;
5854 }
5855 }
5856 QDomElement anchorPointYElem = anchorPointElem.firstChildElement( u"AnchorPointY"_s );
5857 if ( !anchorPointYElem.isNull() )
5858 {
5859 bool ok;
5860 double yOffset = anchorPointYElem.text().toDouble( &ok );
5861 if ( ok )
5862 {
5863 settings.yOffset = yOffset;
5864 settings.offsetUnits = sldUnitSize;
5865 }
5866 }
5867 }
5868
5869 QDomElement rotationElem = pointPlacementElem.firstChildElement( u"Rotation"_s );
5870 if ( !rotationElem.isNull() )
5871 {
5872 bool ok;
5873 double rotation = rotationElem.text().toDouble( &ok );
5874 if ( ok )
5875 {
5876 settings.angleOffset = 360 - rotation;
5877 }
5878 }
5879 }
5880 else
5881 {
5882 // PointPlacement
5883 QDomElement linePlacementElem = labelPlacementElem.firstChildElement( u"LinePlacement"_s );
5884 if ( !linePlacementElem.isNull() )
5885 {
5887 }
5888 }
5889 }
5890
5891 // read vendor options
5892 QgsStringMap vendorOptions;
5893 QDomElement vendorOptionElem = textSymbolizerElem.firstChildElement( u"VendorOption"_s );
5894 while ( !vendorOptionElem.isNull() && vendorOptionElem.localName() == "VendorOption"_L1 )
5895 {
5896 QString optionName = vendorOptionElem.attribute( u"name"_s );
5897 QString optionValue;
5898 if ( vendorOptionElem.firstChild().nodeType() == QDomNode::TextNode )
5899 {
5900 optionValue = vendorOptionElem.firstChild().nodeValue();
5901 }
5902 else
5903 {
5904 if ( vendorOptionElem.firstChild().nodeType() == QDomNode::ElementNode && vendorOptionElem.firstChild().localName() == "Literal"_L1 )
5905 {
5906 QgsDebugMsgLevel( vendorOptionElem.firstChild().localName(), 2 );
5907 optionValue = vendorOptionElem.firstChild().firstChild().nodeValue();
5908 }
5909 else
5910 {
5911 QgsDebugError( u"unexpected child of %1 named %2"_s.arg( vendorOptionElem.localName(), optionName ) );
5912 }
5913 }
5914
5915 if ( !optionName.isEmpty() && !optionValue.isEmpty() )
5916 {
5917 vendorOptions[optionName] = optionValue;
5918 }
5919
5920 vendorOptionElem = vendorOptionElem.nextSiblingElement();
5921 }
5922 if ( !vendorOptions.isEmpty() )
5923 {
5924 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
5925 {
5926 if ( it.key() == "underlineText"_L1 && it.value() == "true"_L1 )
5927 {
5928 font.setUnderline( true );
5929 format.setFont( font );
5930 }
5931 else if ( it.key() == "strikethroughText"_L1 && it.value() == "true"_L1 )
5932 {
5933 font.setStrikeOut( true );
5934 format.setFont( font );
5935 }
5936 else if ( it.key() == "maxDisplacement"_L1 )
5937 {
5939 }
5940 else if ( it.key() == "followLine"_L1 && it.value() == "true"_L1 )
5941 {
5943 {
5945 }
5946 else
5947 {
5949 }
5950 }
5951 else if ( it.key() == "maxAngleDelta"_L1 )
5952 {
5953 bool ok;
5954 double angle = it.value().toDouble( &ok );
5955 if ( ok )
5956 {
5957 settings.maxCurvedCharAngleIn = angle;
5958 settings.maxCurvedCharAngleOut = angle;
5959 }
5960 }
5961 // miscellaneous options
5962 else if ( it.key() == "conflictResolution"_L1 && it.value() == "false"_L1 )
5963 {
5965 }
5966 else if ( it.key() == "forceLeftToRight"_L1 && it.value() == "false"_L1 )
5967 {
5969 }
5970 else if ( it.key() == "group"_L1 && it.value() == "yes"_L1 )
5971 {
5972 settings.lineSettings().setMergeLines( true );
5973 }
5974 else if ( it.key() == "labelAllGroup"_L1 && it.value() == "true"_L1 )
5975 {
5976 settings.lineSettings().setMergeLines( true );
5977 }
5978 }
5979 }
5980
5981 format.setBuffer( bufferSettings );
5982 settings.setFormat( format );
5983 return true;
5984}
5985
5987{
5989
5990 return mEditFormConfig;
5991}
5992
5994{
5996
5997 if ( mEditFormConfig == editFormConfig )
5998 return;
5999
6000 mEditFormConfig = editFormConfig;
6001 mEditFormConfig.onRelationsLoaded();
6002 emit editFormConfigChanged();
6003}
6004
6006{
6008
6009 QgsAttributeTableConfig config = mAttributeTableConfig;
6010
6011 if ( config.isEmpty() )
6012 config.update( fields() );
6013
6014 return config;
6015}
6016
6018{
6020
6021 if ( mAttributeTableConfig != attributeTableConfig )
6022 {
6023 mAttributeTableConfig = attributeTableConfig;
6024 emit configChanged();
6025 }
6026}
6027
6029{
6030 // called in a non-thread-safe way in some cases when calculating aggregates in a different thread
6032
6034}
6035
6042
6044{
6046
6047 if ( !mDiagramLayerSettings )
6048 mDiagramLayerSettings = new QgsDiagramLayerSettings();
6049 *mDiagramLayerSettings = s;
6050}
6051
6053{
6055
6056 QgsLayerMetadataFormatter htmlFormatter( metadata() );
6057 QString myMetadata = u"<html><head></head>\n<body>\n"_s;
6058
6059 myMetadata += generalHtmlMetadata();
6060
6061 // Begin Provider section
6062 myMetadata += u"<h1>"_s + tr( "Information from provider" ) + u"</h1>\n<hr>\n"_s;
6063 myMetadata += "<table class=\"list-view\">\n"_L1;
6064
6065 // storage type
6066 if ( !storageType().isEmpty() )
6067 {
6068 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Storage" ) + u"</td><td>"_s + storageType() + u"</td></tr>\n"_s;
6069 }
6070
6071 // comment
6072 if ( !dataComment().isEmpty() )
6073 {
6074 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Comment" ) + u"</td><td>"_s + dataComment() + u"</td></tr>\n"_s;
6075 }
6076
6077 // encoding
6078 if ( const QgsVectorDataProvider *provider = dataProvider() )
6079 {
6080 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Encoding" ) + u"</td><td>"_s + provider->encoding() + u"</td></tr>\n"_s;
6081 myMetadata += provider->htmlMetadata();
6082 }
6083
6084 if ( isSpatial() )
6085 {
6086 // geom type
6088 if ( static_cast<int>( type ) < 0 || static_cast< int >( type ) > static_cast< int >( Qgis::GeometryType::Null ) )
6089 {
6090 QgsDebugMsgLevel( u"Invalid vector type"_s, 2 );
6091 }
6092 else
6093 {
6094 QString typeString( u"%1 (%2)"_s.arg( QgsWkbTypes::geometryDisplayString( geometryType() ), QgsWkbTypes::displayString( wkbType() ) ) );
6095 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Geometry type" ) + u"</td><td>"_s + typeString + u"</td></tr>\n"_s;
6096 }
6097
6098 // geom column name
6099 if ( const QgsVectorDataProvider *provider = dataProvider(); provider && !provider->geometryColumnName().isEmpty() )
6100 {
6101 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Geometry column" ) + u"</td><td>"_s + provider->geometryColumnName() + u"</td></tr>\n"_s;
6102 }
6103
6104 // Extent
6105 // Try to display extent 3D by default. If empty (probably because the data is 2D), fallback to the 2D version
6106 const QgsBox3D extentBox3D = extent3D();
6107 const QString extentAsStr = !extentBox3D.isEmpty() ? extentBox3D.toString() : extent().toString();
6108 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Extent" ) + u"</td><td>"_s + extentAsStr + u"</td></tr>\n"_s;
6109 }
6110
6111 // feature count
6112 QLocale locale = QLocale();
6113 locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
6114 myMetadata += u"<tr><td class=\"highlight\">"_s
6115 + tr( "Feature count" )
6116 + u"</td><td>"_s
6117 + ( featureCount() == -1 ? tr( "unknown" ) : locale.toString( static_cast<qlonglong>( featureCount() ) ) )
6118 + u"</td></tr>\n"_s;
6119
6120 // End Provider section
6121 myMetadata += "</table>\n<br><br>"_L1;
6122
6123 if ( isSpatial() )
6124 {
6125 // CRS
6126 myMetadata += crsHtmlMetadata();
6127 }
6128
6129 // identification section
6130 myMetadata += u"<h1>"_s + tr( "Identification" ) + u"</h1>\n<hr>\n"_s;
6131 myMetadata += htmlFormatter.identificationSectionHtml();
6132 myMetadata += "<br><br>\n"_L1;
6133
6134 // extent section
6135 myMetadata += u"<h1>"_s + tr( "Extent" ) + u"</h1>\n<hr>\n"_s;
6136 myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
6137 myMetadata += "<br><br>\n"_L1;
6138
6139 // Start the Access section
6140 myMetadata += u"<h1>"_s + tr( "Access" ) + u"</h1>\n<hr>\n"_s;
6141 myMetadata += htmlFormatter.accessSectionHtml();
6142 myMetadata += "<br><br>\n"_L1;
6143
6144 // Fields section
6145 myMetadata += u"<h1>"_s + tr( "Fields" ) + u"</h1>\n<hr>\n<table class=\"list-view\">\n"_s;
6146
6147 // primary key
6149 if ( !pkAttrList.isEmpty() )
6150 {
6151 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Primary key attributes" ) + u"</td><td>"_s;
6152 const auto constPkAttrList = pkAttrList;
6153 for ( int idx : constPkAttrList )
6154 {
6155 myMetadata += fields().at( idx ).name() + ' ';
6156 }
6157 myMetadata += "</td></tr>\n"_L1;
6158 }
6159
6160 const QgsFields myFields = fields();
6161
6162 // count fields
6163 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Count" ) + u"</td><td>"_s + QString::number( myFields.size() ) + u"</td></tr>\n"_s;
6164
6165 myMetadata += "</table>\n<br><table width=\"100%\" class=\"tabular-view\">\n"_L1;
6166 myMetadata += "<tr><th>"_L1 + tr( "Field" ) + "</th><th>"_L1 + tr( "Type" ) + "</th><th>"_L1 + tr( "Length" ) + "</th><th>"_L1 + tr( "Precision" ) + "</th><th>"_L1 + tr( "Comment" ) + "</th></tr>\n"_L1;
6167
6168 for ( int i = 0; i < myFields.size(); ++i )
6169 {
6170 QgsField myField = myFields.at( i );
6171 QString rowClass;
6172 if ( i % 2 )
6173 rowClass = u"class=\"odd-row\""_s;
6174 myMetadata += "<tr "_L1
6175 + rowClass
6176 + "><td>"_L1
6177 + myField.displayNameWithAlias()
6178 + "</td><td>"_L1
6179 + myField.typeName()
6180 + "</td><td>"_L1
6181 + QString::number( myField.length() )
6182 + "</td><td>"_L1
6183 + QString::number( myField.precision() )
6184 + "</td><td>"_L1
6185 + myField.comment()
6186 + "</td></tr>\n"_L1;
6187 }
6188
6189 //close field list
6190 myMetadata += "</table>\n<br><br>"_L1;
6191
6192 // Start the contacts section
6193 myMetadata += u"<h1>"_s + tr( "Contacts" ) + u"</h1>\n<hr>\n"_s;
6194 myMetadata += htmlFormatter.contactsSectionHtml();
6195 myMetadata += "<br><br>\n"_L1;
6196
6197 // Start the links section
6198 myMetadata += u"<h1>"_s + tr( "Links" ) + u"</h1>\n<hr>\n"_s;
6199 myMetadata += htmlFormatter.linksSectionHtml();
6200 myMetadata += "<br><br>\n"_L1;
6201
6202 // Start the history section
6203 myMetadata += u"<h1>"_s + tr( "History" ) + u"</h1>\n<hr>\n"_s;
6204 myMetadata += htmlFormatter.historySectionHtml();
6205 myMetadata += "<br><br>\n"_L1;
6206
6207 myMetadata += customPropertyHtmlMetadata();
6208
6209 myMetadata += "\n</body>\n</html>\n"_L1;
6210 return myMetadata;
6211}
6212
6213void QgsVectorLayer::invalidateSymbolCountedFlag()
6214{
6216
6217 mSymbolFeatureCounted = false;
6218}
6219
6220void QgsVectorLayer::onFeatureCounterCompleted()
6221{
6223
6224 onSymbolsCounted();
6225 mFeatureCounter = nullptr;
6226}
6227
6228void QgsVectorLayer::onFeatureCounterTerminated()
6229{
6231
6232 mFeatureCounter = nullptr;
6233}
6234
6235void QgsVectorLayer::onJoinedFieldsChanged()
6236{
6238
6239 // some of the fields of joined layers have changed -> we need to update this layer's fields too
6240 updateFields();
6241}
6242
6243void QgsVectorLayer::onFeatureAdded( QgsFeatureId fid )
6244{
6246
6247 updateExtents();
6248
6249 emit featureAdded( fid );
6250}
6251
6252void QgsVectorLayer::onFeatureDeleted( QgsFeatureId fid )
6253{
6255
6256 updateExtents();
6257
6258 if ( mEditCommandActive || mCommitChangesActive )
6259 {
6260 mDeletedFids << fid;
6261 }
6262 else
6263 {
6264 mSelectedFeatureIds.remove( fid );
6265 emit featuresDeleted( QgsFeatureIds() << fid );
6266 }
6267
6268 emit featureDeleted( fid );
6269}
6270
6271void QgsVectorLayer::onRelationsLoaded()
6272{
6274
6275 mEditFormConfig.onRelationsLoaded();
6276}
6277
6278void QgsVectorLayer::onSymbolsCounted()
6279{
6281
6282 if ( mFeatureCounter )
6283 {
6284 mSymbolFeatureCounted = true;
6285 mSymbolFeatureCountMap = mFeatureCounter->symbolFeatureCountMap();
6286 mSymbolFeatureIdMap = mFeatureCounter->symbolFeatureIdMap();
6288 }
6289}
6290
6291QList<QgsRelation> QgsVectorLayer::referencingRelations( int idx ) const
6292{
6294
6295 if ( QgsProject *p = project() )
6296 return p->relationManager()->referencingRelations( this, idx );
6297 else
6298 return {};
6299}
6300
6301QList<QgsWeakRelation> QgsVectorLayer::weakRelations() const
6302{
6304
6305 return mWeakRelations;
6306}
6307
6308void QgsVectorLayer::setWeakRelations( const QList<QgsWeakRelation> &relations )
6309{
6311
6312 mWeakRelations = relations;
6313}
6314
6315bool QgsVectorLayer::loadAuxiliaryLayer( const QgsAuxiliaryStorage &storage, const QString &key )
6316{
6318
6319 bool rc = false;
6320
6321 QString joinKey = mAuxiliaryLayerKey;
6322 if ( !key.isEmpty() )
6323 joinKey = key;
6324
6325 if ( storage.isValid() && !joinKey.isEmpty() )
6326 {
6327 QgsAuxiliaryLayer *alayer = nullptr;
6328
6329 int idx = fields().lookupField( joinKey );
6330
6331 if ( idx >= 0 )
6332 {
6333 alayer = storage.createAuxiliaryLayer( fields().field( idx ), this );
6334
6335 if ( alayer )
6336 {
6337 setAuxiliaryLayer( alayer );
6338 rc = true;
6339 }
6340 }
6341 }
6342
6343 return rc;
6344}
6345
6347{
6349
6350 mAuxiliaryLayerKey.clear();
6351
6352 if ( mAuxiliaryLayer )
6353 removeJoin( mAuxiliaryLayer->id() );
6354
6355 if ( alayer )
6356 {
6357 addJoin( alayer->joinInfo() );
6358
6359 if ( !alayer->isEditable() )
6360 alayer->startEditing();
6361
6362 mAuxiliaryLayerKey = alayer->joinInfo().targetFieldName();
6363 }
6364
6365 mAuxiliaryLayer.reset( alayer );
6366 if ( mAuxiliaryLayer )
6367 mAuxiliaryLayer->setParent( this );
6368 updateFields();
6369}
6370
6372{
6374
6375 return mAuxiliaryLayer.get();
6376}
6377
6379{
6381
6382 return mAuxiliaryLayer.get();
6383}
6384
6385QSet<QgsMapLayerDependency> QgsVectorLayer::dependencies() const
6386{
6388
6389 if ( mDataProvider )
6390 return mDataProvider->dependencies() + mDependencies;
6391 return mDependencies;
6392}
6393
6394void QgsVectorLayer::emitDataChanged()
6395{
6397
6398 if ( mDataChangedFired )
6399 return;
6400
6401 // If we are asked to fire dataChanged from a layer we depend on,
6402 // be sure that this layer is not in the process of committing its changes, because
6403 // we will be asked to fire dataChanged at the end of his commit, and we don't
6404 // want to fire this signal more than necessary.
6405 if ( QgsVectorLayer *layerWeDependUpon = qobject_cast<QgsVectorLayer *>( sender() ); layerWeDependUpon && layerWeDependUpon->mCommitChangesActive )
6406 return;
6407
6408 updateExtents(); // reset cached extent to reflect data changes
6409
6410 mDataChangedFired = true;
6411 emit dataChanged();
6412 mDataChangedFired = false;
6413}
6414
6415void QgsVectorLayer::onDependencyAfterCommitChanges()
6416{
6418
6419 if ( mDataProvider && mDataProvider->capabilities().testFlag( Qgis::VectorProviderCapability::CacheData ) )
6420 mDataProvider->reloadData();
6421 else
6422 emitDataChanged();
6423}
6424
6425bool QgsVectorLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
6426{
6428
6429 QSet<QgsMapLayerDependency> deps;
6430 const auto constODeps = oDeps;
6431 for ( const QgsMapLayerDependency &dep : constODeps )
6432 {
6433 if ( dep.origin() == QgsMapLayerDependency::FromUser )
6434 deps << dep;
6435 }
6436
6437 QSet<QgsMapLayerDependency> toAdd = deps - dependencies();
6438
6439 // disconnect layers that are not present in the list of dependencies anymore
6440 if ( QgsProject *p = project() )
6441 {
6442 for ( const QgsMapLayerDependency &dep : std::as_const( mDependencies ) )
6443 {
6444 QgsVectorLayer *lyr = static_cast<QgsVectorLayer *>( p->mapLayer( dep.layerId() ) );
6445 if ( !lyr )
6446 continue;
6447 disconnect( lyr, &QgsVectorLayer::featureAdded, this, &QgsVectorLayer::emitDataChanged );
6448 disconnect( lyr, &QgsVectorLayer::featureDeleted, this, &QgsVectorLayer::emitDataChanged );
6449 disconnect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
6450 disconnect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );
6452 disconnect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::onDependencyAfterCommitChanges );
6453 }
6454 }
6455
6456 // assign new dependencies
6457 if ( mDataProvider )
6458 mDependencies = mDataProvider->dependencies() + deps;
6459 else
6460 mDependencies = deps;
6461 emit dependenciesChanged();
6462
6463 // connect to new layers
6464 if ( QgsProject *p = project() )
6465 {
6466 for ( const QgsMapLayerDependency &dep : std::as_const( mDependencies ) )
6467 {
6468 QgsVectorLayer *lyr = static_cast<QgsVectorLayer *>( p->mapLayer( dep.layerId() ) );
6469 if ( !lyr )
6470 continue;
6471 connect( lyr, &QgsVectorLayer::featureAdded, this, &QgsVectorLayer::emitDataChanged );
6472 connect( lyr, &QgsVectorLayer::featureDeleted, this, &QgsVectorLayer::emitDataChanged );
6473 connect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
6474 connect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );
6476 connect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::onDependencyAfterCommitChanges );
6477 }
6478 }
6479
6480 // if new layers are present, emit a data change
6481 if ( !toAdd.isEmpty() )
6482 emitDataChanged();
6483
6484 return true;
6485}
6486
6488{
6490
6491 if ( fieldIndex < 0 || fieldIndex >= mFields.count() || !mDataProvider )
6493
6494 QgsFieldConstraints::Constraints constraints = mFields.at( fieldIndex ).constraints().constraints();
6495
6496 // make sure provider constraints are always present!
6497 if ( mFields.fieldOrigin( fieldIndex ) == Qgis::FieldOrigin::Provider )
6498 {
6499 constraints |= mDataProvider->fieldConstraints( mFields.fieldOriginIndex( fieldIndex ) );
6500 }
6501
6502 return constraints;
6503}
6504
6505QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength> QgsVectorLayer::fieldConstraintsAndStrength( int fieldIndex ) const
6506{
6508
6509 QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength > m;
6510
6511 if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
6512 return m;
6513
6514 QString name = mFields.at( fieldIndex ).name();
6515
6516 QMap< QPair< QString, QgsFieldConstraints::Constraint >, QgsFieldConstraints::ConstraintStrength >::const_iterator conIt = mFieldConstraintStrength.constBegin();
6517 for ( ; conIt != mFieldConstraintStrength.constEnd(); ++conIt )
6518 {
6519 if ( conIt.key().first == name )
6520 {
6521 m[conIt.key().second] = mFieldConstraintStrength.value( conIt.key() );
6522 }
6523 }
6524
6525 return m;
6526}
6527
6529{
6531
6532 if ( index < 0 || index >= mFields.count() )
6533 return;
6534
6535 QString name = mFields.at( index ).name();
6536
6537 // add constraint to existing constraints
6538 QgsFieldConstraints::Constraints constraints = mFieldConstraints.value( name, QgsFieldConstraints::Constraints() );
6539 constraints |= constraint;
6540 mFieldConstraints.insert( name, constraints );
6541
6542 mFieldConstraintStrength.insert( qMakePair( name, constraint ), strength );
6543
6544 updateFields();
6545}
6546
6548{
6550
6551 if ( index < 0 || index >= mFields.count() )
6552 return;
6553
6554 QString name = mFields.at( index ).name();
6555
6556 // remove constraint from existing constraints
6557 QgsFieldConstraints::Constraints constraints = mFieldConstraints.value( name, QgsFieldConstraints::Constraints() );
6558 constraints &= ~constraint;
6559 mFieldConstraints.insert( name, constraints );
6560
6561 mFieldConstraintStrength.remove( qMakePair( name, constraint ) );
6562
6563 updateFields();
6564}
6565
6567{
6569
6570 if ( index < 0 || index >= mFields.count() )
6571 return QString();
6572
6573 return mFields.at( index ).constraints().constraintExpression();
6574}
6575
6577{
6579
6580 if ( index < 0 || index >= mFields.count() )
6581 return QString();
6582
6583 return mFields.at( index ).constraints().constraintDescription();
6584}
6585
6586void QgsVectorLayer::setConstraintExpression( int index, const QString &expression, const QString &description )
6587{
6589
6590 if ( index < 0 || index >= mFields.count() )
6591 return;
6592
6593 if ( expression.isEmpty() )
6594 {
6595 mFieldConstraintExpressions.remove( mFields.at( index ).name() );
6596 }
6597 else
6598 {
6599 mFieldConstraintExpressions.insert( mFields.at( index ).name(), qMakePair( expression, description ) );
6600 }
6601 updateFields();
6602}
6603
6605{
6607
6608 if ( index < 0 || index >= mFields.count() )
6609 return;
6610
6611 mFieldConfigurationFlags.insert( mFields.at( index ).name(), flags );
6612 updateFields();
6613}
6614
6616{
6618
6619 if ( index < 0 || index >= mFields.count() )
6620 return;
6621 Qgis::FieldConfigurationFlags flags = mFields.at( index ).configurationFlags();
6622 flags.setFlag( flag, active );
6624}
6625
6627{
6629
6630 if ( index < 0 || index >= mFields.count() )
6632
6633 return mFields.at( index ).configurationFlags();
6634}
6635
6637{
6639
6640 if ( index < 0 || index >= mFields.count() )
6641 return;
6642
6643 if ( setup.isNull() )
6644 mFieldWidgetSetups.remove( mFields.at( index ).name() );
6645 else
6646 mFieldWidgetSetups.insert( mFields.at( index ).name(), setup );
6647 updateFields();
6648}
6649
6651{
6653
6654 if ( index < 0 || index >= mFields.count() )
6655 return QgsEditorWidgetSetup();
6656
6657 return mFields.at( index ).editorWidgetSetup();
6658}
6659
6660QgsAbstractVectorLayerLabeling *QgsVectorLayer::readLabelingFromCustomProperties()
6661{
6663
6665 if ( customProperty( u"labeling"_s ).toString() == "pal"_L1 )
6666 {
6667 if ( customProperty( u"labeling/enabled"_s, QVariant( false ) ).toBool() )
6668 {
6669 // try to load from custom properties
6670 QgsPalLayerSettings settings;
6671 settings.readFromLayerCustomProperties( this );
6672 labeling = new QgsVectorLayerSimpleLabeling( settings );
6673 }
6674
6675 // also clear old-style labeling config
6676 removeCustomProperty( u"labeling"_s );
6677 const auto constCustomPropertyKeys = customPropertyKeys();
6678 for ( const QString &key : constCustomPropertyKeys )
6679 {
6680 if ( key.startsWith( "labeling/"_L1 ) )
6681 removeCustomProperty( key );
6682 }
6683 }
6684
6685 return labeling;
6686}
6687
6689{
6691
6692 return mAllowCommit;
6693}
6694
6696{
6698
6699 if ( mAllowCommit == allowCommit )
6700 return;
6701
6702 mAllowCommit = allowCommit;
6703 emit allowCommitChanged();
6704}
6705
6707{
6709
6710 return mGeometryOptions.get();
6711}
6712
6719
6721{
6723
6724 return mReadExtentFromXml;
6725}
6726
6727void QgsVectorLayer::onDirtyTransaction( const QString &sql, const QString &name )
6728{
6730
6732 if ( tr && mEditBuffer )
6733 {
6734 qobject_cast<QgsVectorLayerEditPassthrough *>( mEditBuffer )->update( tr, sql, name );
6735 }
6736}
6737
6738QList<QgsVectorLayer *> QgsVectorLayer::DeleteContext::handledLayers( bool includeAuxiliaryLayers ) const
6739{
6740 QList<QgsVectorLayer *> layers;
6741 QMap<QgsVectorLayer *, QgsFeatureIds>::const_iterator i;
6742 for ( i = mHandledFeatures.begin(); i != mHandledFeatures.end(); ++i )
6743 {
6744 if ( includeAuxiliaryLayers || !qobject_cast< QgsAuxiliaryLayer * >( i.key() ) )
6745 layers.append( i.key() );
6746 }
6747 return layers;
6748}
6749
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:62
@ Action
Map layers' action.
Definition qgis.h:466
@ FormInitCode
Attribute forms' initiation code.
Definition qgis.h:467
@ SelectAtId
Fast access to features using their ID.
Definition qgis.h:533
@ CacheData
Provider caches source data and should force provider data reloads when dependent layers are committe...
Definition qgis.h:551
@ CreateRenderer
Provider can create feature renderers using backend-specific formatting information....
Definition qgis.h:547
@ CreateLabeling
Provider can set labeling settings using backend-specific formatting information. Since QGIS 3....
Definition qgis.h:548
@ ReadLayerMetadata
Provider can read layer metadata from data store. Since QGIS 3.0. See QgsDataProvider::layerMetadata(...
Definition qgis.h:544
@ DeleteFeatures
Allows deletion of features.
Definition qgis.h:528
QFlags< VectorRenderingSimplificationFlag > VectorRenderingSimplificationFlags
Simplification flags for vector feature rendering.
Definition qgis.h:3212
@ Composition
Fix relation, related elements are part of the parent and a parent copy will copy any children or del...
Definition qgis.h:4784
@ Association
Loose relation, related elements are not part of the parent and a parent copy will not copy any child...
Definition qgis.h:4783
GeometryOperationResult
Success or failure of a geometry operation.
Definition qgis.h:2162
@ InvalidInputGeometryType
The input geometry (ring, part, split line, etc.) has not the correct geometry type.
Definition qgis.h:2166
@ Success
Operation succeeded.
Definition qgis.h:2163
@ SelectionIsEmpty
No features were selected.
Definition qgis.h:2167
@ AddRingNotInExistingFeature
The input ring doesn't have any existing ring to fit into.
Definition qgis.h:2178
@ AddRingNotClosed
The input ring is not closed.
Definition qgis.h:2175
@ SelectionIsGreaterThanOne
More than one features were selected.
Definition qgis.h:2168
@ LayerNotEditable
Cannot edit layer.
Definition qgis.h:2170
SpatialIndexPresence
Enumeration of spatial index presence states.
Definition qgis.h:585
@ Unknown
Spatial index presence cannot be determined, index may or may not exist.
Definition qgis.h:586
VectorRenderingSimplificationFlag
Simplification flags for vector feature rendering.
Definition qgis.h:3197
@ NoSimplification
No simplification can be applied.
Definition qgis.h:3198
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
Definition qgis.h:1275
@ Curved
Arranges candidates following the curvature of a line feature. Applies to line layers only.
Definition qgis.h:1277
@ AroundPoint
Arranges candidates in a circle around a point (or centroid of a polygon). Applies to point or polygo...
Definition qgis.h:1274
@ Line
Arranges candidates parallel to a generalised line representing the feature or parallel to a polygon'...
Definition qgis.h:1276
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
Definition qgis.h:1278
@ PerimeterCurved
Arranges candidates following the curvature of a polygon's boundary. Applies to polygon layers only.
Definition qgis.h:1281
QFlags< VectorLayerTypeFlag > VectorLayerTypeFlags
Vector layer type flags.
Definition qgis.h:440
VectorSimplificationAlgorithm
Simplification algorithms for vector features.
Definition qgis.h:3181
@ Distance
The simplification uses the distance between points to remove duplicate points.
Definition qgis.h:3182
@ File
Load the Python code from an external file.
Definition qgis.h:6119
@ Environment
Use the Python code available in the Python environment.
Definition qgis.h:6121
@ NoSource
Do not use Python code at all.
Definition qgis.h:6118
@ Dialog
Use the Python code provided in the dialog.
Definition qgis.h:6120
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
Definition qgis.h:2331
@ SubsetOfAttributes
Fetch only a subset of attributes (setSubsetOfAttributes sets this flag).
Definition qgis.h:2330
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition qgis.h:2329
@ FastExtent3D
Provider's 3D extent retrieval via QgsDataProvider::extent3D() is always guaranteed to be trivial/fas...
Definition qgis.h:2446
@ FastExtent2D
Provider's 2D extent retrieval via QgsDataProvider::extent() is always guaranteed to be trivial/fast ...
Definition qgis.h:2445
@ BufferedGroups
Buffered transactional editing means that all editable layers in the buffered transaction group are t...
Definition qgis.h:4156
@ Mac
MacOS specific.
Definition qgis.h:5081
@ OpenUrl
Open URL action.
Definition qgis.h:5084
@ Unix
Unix specific.
Definition qgis.h:5083
@ SubmitUrlMultipart
POST data to an URL using "multipart/form-data".
Definition qgis.h:5086
@ Windows
Windows specific.
Definition qgis.h:5082
@ SubmitUrlEncoded
POST data to an URL, using "application/x-www-form-urlencoded" or "application/json" if the body is v...
Definition qgis.h:5085
FieldDomainMergePolicy
Merge policy for field domains.
Definition qgis.h:4107
@ UnsetField
Clears the field value so that the data provider backend will populate using any backend triggers or ...
Definition qgis.h:4111
FieldDomainSplitPolicy
Split policy for field domains.
Definition qgis.h:4090
@ Duplicate
Duplicate original value.
Definition qgis.h:4092
BlendMode
Blending modes defining the available composition modes that can be used when painting.
Definition qgis.h:5333
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition qgis.h:379
@ Point
Points.
Definition qgis.h:380
@ Line
Lines.
Definition qgis.h:381
@ Polygon
Polygons.
Definition qgis.h:382
@ Unknown
Unknown types.
Definition qgis.h:383
@ Null
No geometry.
Definition qgis.h:384
@ Generated
A generated relation is a child of a polymorphic relation.
Definition qgis.h:4770
@ Normal
A normal relation.
Definition qgis.h:4769
FieldDuplicatePolicy
Duplicate policy for fields.
Definition qgis.h:4127
@ Duplicate
Duplicate original value.
Definition qgis.h:4129
static const float DEFAULT_MAPTOPIXEL_THRESHOLD
Default threshold between map coordinates and device coordinates for map2pixel simplification.
Definition qgis.h:6823
QFlags< DataProviderReadFlag > DataProviderReadFlags
Flags which control data provider construction.
Definition qgis.h:512
FeatureAvailability
Possible return value for QgsFeatureSource::hasFeatures() to determine if a source is empty.
Definition qgis.h:604
@ FeaturesMaybeAvailable
There may be features available in this source.
Definition qgis.h:607
@ FeaturesAvailable
There is at least one feature available in this source.
Definition qgis.h:606
@ NoFeaturesAvailable
There are certainly no features available in this source.
Definition qgis.h:605
@ Vector
Vector layer.
Definition qgis.h:207
FieldOrigin
Field origin.
Definition qgis.h:1824
@ Provider
Field originates from the underlying data provider of the vector layer.
Definition qgis.h:1826
@ Edit
Field has been temporarily added in editing mode.
Definition qgis.h:1828
@ Unknown
The field origin has not been specified.
Definition qgis.h:1825
@ Expression
Field is calculated from an expression.
Definition qgis.h:1829
@ Join
Field originates from a joined layer.
Definition qgis.h:1827
RenderUnit
Rendering size units.
Definition qgis.h:5586
@ Points
Points (e.g., for font sizes).
Definition qgis.h:5591
@ Pixels
Pixels.
Definition qgis.h:5589
@ LoadDefaultStyle
Reset the layer's style to the default for the datasource.
Definition qgis.h:495
@ ForceReadOnly
Open layer in a read-only mode.
Definition qgis.h:498
Aggregate
Available aggregates to calculate.
Definition qgis.h:6420
VertexMarkerType
Editing vertex markers, used for showing vertices during a edit operation.
Definition qgis.h:1953
@ NoMarker
No marker.
Definition qgis.h:1956
@ SemiTransparentCircle
Semi-transparent circle marker.
Definition qgis.h:1954
@ Cross
Cross marker.
Definition qgis.h:1955
VectorEditResult
Specifies the result of a vector layer edit operation.
Definition qgis.h:1938
@ EmptyGeometry
Edit operation resulted in an empty geometry.
Definition qgis.h:1940
@ Success
Edit operation was successful.
Definition qgis.h:1939
@ InvalidLayer
Edit failed due to invalid layer.
Definition qgis.h:1943
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:294
@ Unknown
Unknown.
Definition qgis.h:295
FieldConfigurationFlag
Configuration flags for fields These flags are meant to be user-configurable and are not describing a...
Definition qgis.h:1841
@ HideFromWfs
Field is not available if layer is served as WFS from QGIS server.
Definition qgis.h:1845
@ NoFlag
No flag is defined.
Definition qgis.h:1842
@ HideFromWms
Field is not available if layer is served as WMS from QGIS server.
Definition qgis.h:1844
@ AllowOverlapIfRequired
Avoids overlapping labels when possible, but permit overlaps if labels for features cannot otherwise ...
Definition qgis.h:1236
QFlags< FieldConfigurationFlag > FieldConfigurationFlags
Configuration flags for fields These flags are meant to be user-configurable and are not describing a...
Definition qgis.h:1856
@ AlwaysAllowUpsideDown
Show upside down for all labels, including dynamic ones.
Definition qgis.h:1432
SelectBehavior
Specifies how a selection should be applied.
Definition qgis.h:1891
@ SetSelection
Set selection, removing any existing selection.
Definition qgis.h:1892
@ AddToSelection
Add selection to current selection.
Definition qgis.h:1893
@ IntersectSelection
Modify current selection to include only select features which match.
Definition qgis.h:1894
@ RemoveFromSelection
Remove from current selection.
Definition qgis.h:1895
Abstract base class for objects which generate elevation profiles.
virtual bool writeXml(QDomElement &collectionElem, const QgsPropertiesDefinition &definitions) const
Writes the current state of the property collection into an XML element.
Abstract base class - its implementations define different approaches to the labeling of a vector lay...
static QgsAbstractVectorLayerLabeling * create(const QDomElement &element, const QgsReadWriteContext &context)
Try to create instance of an implementation based on the XML data.
Storage and management of actions associated with a layer.
QList< QgsAction > actions(const QString &actionScope=QString()) const
Returns a list of actions that are available in the given action scope.
QUuid addAction(Qgis::AttributeActionType type, const QString &name, const QString &command, bool capture=false)
Add an action with the given name and action details.
Utility class that encapsulates an action based on vector attributes.
Definition qgsaction.h:38
Utility class for calculating aggregates for a field (or expression) over the features from a vector ...
static QgsNetworkContentFetcherRegistry * networkContentFetcherRegistry()
Returns the application's network content registry used for fetching temporary files during QGIS sess...
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling.
A container for configuration of the attribute table.
void update(const QgsFields &fields)
Update the configuration with the given fields.
A vector of attributes.
Allows managing the auxiliary storage for a vector layer.
QgsVectorLayerJoinInfo joinInfo() const
Returns information to use for joining with primary key and so on.
Providing some utility methods to manage auxiliary storage.
QgsAuxiliaryLayer * createAuxiliaryLayer(const QgsField &field, QgsVectorLayer *layer) const
Creates an auxiliary layer for a vector layer.
bool isValid() const
Returns the status of the auxiliary storage currently defined.
A 3-dimensional box composed of x, y, z coordinates.
Definition qgsbox3d.h:45
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin,zmin : xmax,ymax,zmax Coordinates will be truncated...
Definition qgsbox3d.cpp:326
bool isEmpty() const
Returns true if the box is empty.
Definition qgsbox3d.cpp:321
Holds conditional style information for a layer.
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Contains information about the context in which a coordinate transform is executed.
Abstract base class for curved geometry type.
Definition qgscurve.h:36
virtual bool isClosed() const
Returns true if the curve is closed.
Definition qgscurve.cpp:53
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
void dataChanged()
Emitted whenever a change is made to the data provider which may have caused changes in the provider'...
void fullExtentCalculated()
Emitted whenever a deferred extent calculation is completed by the provider.
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
Stores the component parts of a data source URI (e.g.
bool useEstimatedMetadata() const
Returns true if estimated metadata should be used for the connection.
Provides a container for managing client side default values for fields.
bool isValid() const
Returns if this default value should be applied.
Stores the settings for rendering of all diagrams for a layer.
@ PositionX
X-coordinate data defined diagram position.
@ PositionY
Y-coordinate data defined diagram position.
@ Show
Whether to show the diagram.
Evaluates and returns the diagram settings relating to a diagram for a specific feature.
Contains configuration settings for an editor form.
Holder for the widget type and its configuration for a field.
QVariantMap config() const
Returns the widget configuration.
bool isNull() const
Returns true if there is no widget configured.
A embedded script entity for QgsObjectEntityVisitorInterface.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the scope.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the scope.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsExpressionContextScope * popScope()
Removes the last scope from the expression context and return it.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Buffers information about expression fields for a vector layer.
void writeXml(QDomNode &layer_node, QDomDocument &document) const
Saves expressions to xml under the layer node.
An expression node which takes its value from a feature's field.
QString name() const
The name of the column.
Handles parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
QString expression() const
Returns the original, unmodified expression string.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QString evalErrorString() const
Returns evaluation error.
QString parserErrorString() const
Returns parser error.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes).
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
static int expressionToLayerFieldIndex(const QString &expression, const QgsVectorLayer *layer)
Attempts to resolve an expression to a field index from the given layer.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
QVariant evaluate()
Evaluate the feature and return the result.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
bool close()
Call to end the iteration.
An interface for objects which generate feature renderers for vector layers.
Abstract base class for all 2D vector feature renderers.
static QgsFeatureRenderer * defaultRenderer(Qgis::GeometryType geomType)
Returns a new renderer - used by default in vector layers.
static QgsFeatureRenderer * load(QDomElement &symbologyElem, const QgsReadWriteContext &context)
create a renderer from XML element
static QgsFeatureRenderer * loadSld(const QDomNode &node, Qgis::GeometryType geomType, QString &errorMessage)
Create a new renderer according to the information contained in the UserStyle element of a SLD style ...
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets the feature ID that should be fetched.
QFlags< Flag > Flags
virtual QgsFeatureIds allFeatureIds() const
Returns a list of all feature IDs for features present in the source.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:60
Q_INVOKABLE bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
QgsAttributes attributes
Definition qgsfeature.h:64
QgsFields fields
Definition qgsfeature.h:65
QgsFeatureId id
Definition qgsfeature.h:63
QgsGeometry geometry
Definition qgsfeature.h:66
bool hasGeometry() const
Returns true if the feature has an associated geometry.
bool isValid() const
Returns the validity of this feature.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:56
Stores information about constraints which may be present on a field.
ConstraintStrength
Strength of constraints.
void setConstraintStrength(Constraint constraint, ConstraintStrength strength)
Sets the strength of a constraint.
void setConstraintExpression(const QString &expression, const QString &description=QString())
Set the constraint expression for the field.
@ ConstraintOriginProvider
Constraint was set at data provider.
@ ConstraintOriginLayer
Constraint was set by layer.
ConstraintOrigin constraintOrigin(Constraint constraint) const
Returns the origin of a field constraint, or ConstraintOriginNotSet if the constraint is not present ...
Constraint
Constraints which may be present on a field.
@ ConstraintNotNull
Field may not be null.
@ ConstraintUnique
Field must have a unique value.
@ ConstraintExpression
Field has an expression constraint set. See constraintExpression().
void setConstraint(Constraint constraint, ConstraintOrigin origin=ConstraintOriginLayer)
Sets a constraint on the field.
QFlags< Constraint > Constraints
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:56
QString typeName() const
Gets the field type.
Definition qgsfield.cpp:158
QString name
Definition qgsfield.h:65
int precision
Definition qgsfield.h:62
int length
Definition qgsfield.h:61
QString displayNameWithAlias() const
Returns the name to use when displaying this field and adds the alias in parenthesis if it is defined...
Definition qgsfield.cpp:104
QString alias
Definition qgsfield.h:66
QString customComment
Definition qgsfield.h:71
QString comment
Definition qgsfield.h:64
Container of fields for a vector layer.
Definition qgsfields.h:46
int count
Definition qgsfields.h:50
int size() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
const_iterator constBegin() const noexcept
Returns a const STL-style iterator pointing to the first item in the list.
Contains options to automatically adjust geometries to constraints on a layer.
A geometry is the spatial representation of a feature.
bool isExactlyEqual(const QgsGeometry &geometry, Qgis::GeometryBackend backend=Qgis::GeometryBackend::QGIS) const
Compares the geometry with another geometry using the specified backend.
QgsBox3D boundingBox3D() const
Returns the 3D bounding box of the geometry.
Qgis::GeometryType type
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
void setMergeLines(bool merge)
Sets whether connected line features with identical label text should be merged prior to generating l...
void setOverlapHandling(Qgis::LabelOverlapHandling handling)
Sets the technique used to handle overlapping labels.
Formats layer metadata into HTML.
void combine(const QgsAbstractMetadataBase *other) override
Combines the metadata from this object with the metadata from an other object.
Line string geometry type, with support for z-dimension and m-values.
Alters the size of rendered diagrams using linear scaling.
static void warning(const QString &msg)
Goes to qWarning.
Models dependencies with or between map layers.
Base class for storage of map layer elevation properties.
static QString typeToString(Qgis::LayerType type)
Converts a map layer type to a string value.
virtual QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Writes configuration to a DOM element, to be used later with readXml().
static QgsMapLayerLegend * defaultVectorLegend(QgsVectorLayer *vl)
Create new legend implementation for vector layer.
Base class for utility classes that encapsulate information necessary for rendering of map layers.
Base class for storage of map layer selection properties.
Stores style information (renderer, opacity, labeling, diagrams etc.) applicable to a map layer.
Base class for storage of map layer temporal properties.
QString name
Definition qgsmaplayer.h:87
void readStyleManager(const QDomNode &layerNode)
Read style manager's configuration (if any). To be called by subclasses.
void dependenciesChanged()
Emitted when dependencies are changed.
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager's configuration (if exists). To be called by subclasses.
QgsMapLayerLegend * legend() const
Can be nullptr.
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
void recalculateExtents() const
This is used to send a request that any mapcanvas using this layer update its extents.
virtual Q_INVOKABLE QgsRectangle extent() const
Returns the extent of the layer.
QString source() const
Returns the source for the layer.
Q_INVOKABLE QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
int mBlockStyleChangedSignal
If non-zero, the styleChanged signal should not be emitted.
QString providerType() const
Returns the provider type (provider key) for this layer.
virtual void setExtent3D(const QgsBox3D &box)
Sets the extent.
void removeCustomProperty(const QString &key)
Remove a custom property from layer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
void configChanged()
Emitted whenever the configuration is changed.
void setMinimumScale(double scale)
Sets the minimum map scale (i.e.
static Qgis::DataProviderReadFlags providerReadFlags(const QDomNode &layerNode, QgsMapLayer::ReadFlags layerReadFlags)
Returns provider read flag deduced from layer read flags layerReadFlags and a dom node layerNode that...
void editingStarted()
Emitted when editing on this layer has started.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:90
friend class QgsVectorLayer
void writeCustomProperties(QDomNode &layerNode, QDomDocument &doc) const
Write custom properties to project file.
virtual int listStylesInDatabase(QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError)
Lists all the style in db split into related to the layer and not related to.
virtual QString loadDefaultStyle(bool &resultFlag)
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
void setDataSource(const QString &dataSource, const QString &baseName=QString(), const QString &provider=QString(), bool loadDefaultStyleFlag=false)
Updates the data source of the layer.
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
QString crsHtmlMetadata() const
Returns a HTML fragment containing the layer's CRS metadata, for use in the htmlMetadata() method.
void setMaximumScale(double scale)
Sets the maximum map scale (i.e.
QgsLayerMetadata metadata
Definition qgsmaplayer.h:89
QgsMapLayer(Qgis::LayerType type=Qgis::LayerType::Vector, const QString &name=QString(), const QString &source=QString())
Constructor for QgsMapLayer.
Qgis::LayerType type
Definition qgsmaplayer.h:93
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
virtual void setOpacity(double opacity)
Sets the opacity for the layer, where opacity is a value between 0 (totally transparent) and 1....
void setFlags(QgsMapLayer::LayerFlags flags)
Returns the flags for this layer.
QString publicSource(bool hidePassword=false) const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
QSet< QgsMapLayerDependency > mDependencies
List of layers that may modify this layer on modification.
void readCustomProperties(const QDomNode &layerNode, const QString &keyStartsWith=QString())
Read custom properties from project file.
virtual void setMetadata(const QgsLayerMetadata &metadata)
Sets the layer's metadata store.
QFlags< StyleCategory > StyleCategories
Q_INVOKABLE void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
QString mProviderKey
Data provider key (name of the data provider).
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
void styleChanged()
Signal emitted whenever a change affects the layer's style.
QUndoStack * undoStack()
Returns pointer to layer's undo stack.
std::unique_ptr< QgsDataProvider > mPreloadedProvider
Optionally used when loading a project, it is released when the layer is effectively created.
void rendererChanged()
Signal emitted when renderer is changed.
virtual QgsError error() const
Gets current status error.
void setScaleBasedVisibility(bool enabled)
Sets whether scale based visibility is enabled for the layer.
void dataSourceChanged()
Emitted whenever the layer's data source has been changed.
QgsMapLayer::LayerFlags flags
Definition qgsmaplayer.h:99
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
virtual QString getStyleFromDatabase(const QString &styleId, QString &msgError)
Returns the named style corresponding to style id provided.
void emitStyleChanged()
Triggers an emission of the styleChanged() signal.
void dataChanged()
Data of layer changed.
void willBeDeleted()
Emitted in the destructor when the layer is about to be deleted, but it is still in a perfectly valid...
virtual QgsBox3D extent3D() const
Returns the 3D extent of the layer.
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
void setName(const QString &name)
Set the display name of the layer.
virtual void setExtent(const QgsRectangle &rect)
Sets the extent.
virtual void resolveReferences(QgsProject *project)
Resolve references to other layers (kept as layer IDs after reading XML) into layer objects.
QString mDataSource
Data source description string, varies by layer type.
void setMapTipsEnabled(bool enabled)
Enable or disable map tips for this layer.
@ FlagReadExtentFromXml
Read extent from xml and skip get extent from provider.
@ FlagForceReadOnly
Force open as read only.
@ FlagDontResolveLayers
Don't resolve layer paths or create data providers for layers.
void setValid(bool valid)
Sets whether layer is valid or not.
void readCommonStyle(const QDomElement &layerElement, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)
Read style data common to all layer types.
QgsMapLayer::ReadFlags mReadFlags
Read flags. It's up to the subclass to respect these when restoring state from XML.
double minimumScale() const
Returns the minimum map scale (i.e.
void repaintRequested(bool deferredUpdate=false)
By emitting this signal the layer tells that either appearance or content have been changed and any v...
void setMapTipTemplate(const QString &mapTipTemplate)
The mapTip is a pretty, html representation for feature information.
Q_INVOKABLE QStringList customPropertyKeys() const
Returns list of all keys within custom properties.
QgsProject * project() const
Returns the parent project if this map layer is added to a project.
bool mapTipsEnabled
Definition qgsmaplayer.h:97
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
double opacity
Definition qgsmaplayer.h:95
bool mValid
Indicates if the layer is valid and can be drawn.
@ GeometryOptions
Geometry validation configuration.
@ AttributeTable
Attribute table settings: choice and order of columns, conditional styling.
@ LayerConfiguration
General configuration: identifiable, removable, searchable, display expression, read-only.
@ Symbology
Symbology.
@ MapTips
Map tips.
@ Rendering
Rendering: scale visibility, simplify method, opacity.
@ Relations
Relations.
@ CustomProperties
Custom properties (by plugins for instance).
@ Actions
Actions.
@ Forms
Feature form.
@ Fields
Aliases, widgets, WMS/WFS, expressions, constraints, virtual fields.
@ Legend
Legend settings.
@ Diagrams
Diagrams.
@ Labeling
Labeling.
void layerModified()
Emitted when modifications has been done on layer.
void setProviderType(const QString &providerType)
Sets the providerType (provider key).
QString customPropertyHtmlMetadata() const
Returns an HTML fragment containing custom property information, for use in the htmlMetadata() method...
QString generalHtmlMetadata() const
Returns an HTML fragment containing general metadata information, for use in the htmlMetadata() metho...
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
double maximumScale() const
Returns the maximum map scale (i.e.
QString mapTipTemplate
Definition qgsmaplayer.h:96
bool mShouldValidateCrs
true if the layer's CRS should be validated and invalid CRSes are not permitted.
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
QFile * localFile(const QString &filePathOrUrl)
Returns a QFile from a local file or to a temporary file previously fetched by the registry.
An interface for classes which can visit various object entity (e.g.
virtual bool visitEmbeddedScript(const QgsEmbeddedScriptEntity &entity, const QgsObjectVisitorContext &context)
Called when the visitor will visit an embedded script entity.
A QgsObjectEntityVisitorInterface context object.
static QgsExpression * expressionFromOgcFilter(const QDomElement &element, QgsVectorLayer *layer=nullptr)
Parse XML with OGC filter into QGIS expression.
static Qgis::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a Qgis::BlendMode corresponding to a QPainter::CompositionMode.
static QPainter::CompositionMode getCompositionMode(Qgis::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a Qgis::BlendMode.
Contains settings for how a map layer will be labeled.
double yOffset
Vertical offset of label.
const QgsLabelPlacementSettings & placementSettings() const
Returns the label placement settings.
double maxCurvedCharAngleIn
Maximum angle between inside curved label characters (valid range 20.0 to 60.0).
void setFormat(const QgsTextFormat &format)
Sets the label text formatting settings, e.g., font settings, buffer settings, etc.
double xOffset
Horizontal offset of label.
Qgis::LabelPlacement placement
Label placement mode.
double angleOffset
Label rotation, in degrees clockwise.
double maxCurvedCharAngleOut
Maximum angle between outside curved label characters (valid range -20.0 to -95.0).
Qgis::RenderUnit offsetUnits
Units for offsets of label.
bool isExpression
true if this label is made from a expression string, e.g., FieldName || 'mm'
const QgsLabelLineSettings & lineSettings() const
Returns the label line settings, which contain settings related to how the label engine places and fo...
Qgis::UpsideDownLabelHandling upsidedownLabels
Controls whether upside down labels are displayed and how they are handled.
QString fieldName
Name of field (or an expression) to use for label text.
Represents a 2D point.
Definition qgspointxy.h:62
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
Encapsulates properties and constraints relating to fetching elevation profiles from different source...
virtual QString translate(const QString &context, const QString &sourceText, const char *disambiguation=nullptr, int n=-1) const =0
Translates a string using the Qt QTranslator mechanism.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:114
QgsRelationManager * relationManager
Definition qgsproject.h:125
bool commitChanges(QStringList &commitErrors, bool stopEditing=true, QgsVectorLayer *vectorLayer=nullptr)
Attempts to commit to the underlying data provider any buffered changes made since the last to call t...
static QgsProject * instance()
Returns the QgsProject singleton instance.
bool rollBack(QStringList &rollbackErrors, bool stopEditing=true, QgsVectorLayer *vectorLayer=nullptr)
Stops a current editing operation on vectorLayer and discards any uncommitted edits.
bool startEditing(QgsVectorLayer *vectorLayer=nullptr)
Makes the layer editable.
QMap< QString, QgsMapLayer * > mapLayers(const bool validOnly=false) const
Returns a map of all registered layers by layer ID.
A grouped map of multiple QgsProperty objects, each referenced by an integer key value.
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
Definition for a property.
Definition qgsproperty.h:47
@ Double
Double value (including negative values).
Definition qgsproperty.h:56
@ Boolean
Boolean value.
Definition qgsproperty.h:52
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
QString absoluteToRelativeUri(const QString &providerKey, const QString &uri, const QgsReadWriteContext &context) const
Converts absolute path(s) to relative path(s) in the given provider-specific URI.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QString relativeToAbsoluteUri(const QString &providerKey, const QString &uri, const QgsReadWriteContext &context) const
Converts relative path(s) to absolute path(s) in the given provider-specific URI.
Allows entering a context category and takes care of leaving this category on deletion of the class.
A container for the context for various read/write operations on objects.
QgsReadWriteContextCategoryPopper enterCategory(const QString &category, const QString &details=QString()) const
Push a category to the stack.
const QgsProjectTranslator * projectTranslator() const
Returns the project translator.
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
A rectangle specified with double values.
Q_INVOKABLE QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be rounded to the spec...
double xMinimum
double yMinimum
double xMaximum
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
double yMaximum
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
void normalize()
Normalize the rectangle so it has non-negative width/height.
void setNull()
Mark a rectangle as being null (holding no spatial information).
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
void relationsLoaded()
Emitted when the relations were loaded after reading a project.
Represents a relationship between two vector layers.
Definition qgsrelation.h:42
Contains information about the context of a rendering operation.
double rendererScale() const
Returns the renderer map scale.
bool useRenderingOptimization() const
Returns true if the rendering optimization (geometry simplification) can be executed.
void appendChild(QgsRuleBasedLabeling::Rule *rule)
add child rule, take ownership, sets this as parent
A boolean settings entry.
A double settings entry.
A template class for enum and flag settings entry.
static QgsSettingsTreeNode * sTreeQgis
Renders the diagrams for all features with the same settings.
Holds SLD export options and other information related to SLD export of a QGIS layer style.
void setExtraProperties(const QVariantMap &properties)
Sets the open ended set of properties that can drive/inform the SLD encoding.
QVariantMap extraProperties() const
Returns the open ended set of properties that can drive/inform the SLD encoding.
Renders diagrams using mixed diagram render types.
Manages stored expressions regarding creation, modification and storing in the project.
An interface for classes which can visit style entity (e.g.
static double rendererFrameRate(const QgsFeatureRenderer *renderer)
Calculates the frame rate (in frames per second) at which the given renderer must be redrawn.
static QgsStringMap getSvgParameterList(QDomElement &element)
static void mergeScaleDependencies(double mScaleMinDenom, double mScaleMaxDenom, QVariantMap &props)
Merges the local scale limits, if any, with the ones already in the map, if any.
static bool fillFromSld(QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color)
static Qgis::RenderUnit decodeSldUom(const QString &str, double *scaleFactor=nullptr)
Decodes a SLD unit of measure string to a render unit.
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
void taskCompleted()
Will be emitted by task to indicate its successful completion.
void taskTerminated()
Will be emitted by task if it has terminated for any reason other then completion (e....
void setColor(const QColor &color)
Sets the color for the buffer.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units used for the buffer size.
void setEnabled(bool enabled)
Sets whether the text buffer will be drawn.
void setSize(double size)
Sets the size of the buffer.
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setSize(double size)
Sets the size for rendered text.
void setFont(const QFont &font)
Sets the font used for rendering text.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the size of rendered text.
void setBuffer(const QgsTextBufferSettings &bufferSettings)
Sets the text's buffer settings.
static QString threadDescription(QThread *thread)
Returns a descriptive identifier for a thread.
Allows creation of a multi-layer database-side transaction.
void dirtied(const QString &sql, const QString &name)
Emitted if a sql query is executed and the underlying data is modified.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Base class for vector data providers.
static const int EditingCapabilities
Bitmask of all provider's editing capabilities.
virtual QString geometryColumnName() const
Returns the name of the column storing geometry, if applicable.
void raiseError(const QString &msg) const
Signals an error in this provider.
virtual void handlePostCloneOperations(QgsVectorDataProvider *source)
Handles any post-clone operations required after this vector data provider was cloned from the source...
virtual QgsTransaction * transaction() const
Returns the transaction this data provider is included in, if any.
void committedAttributesDeleted(const QString &layerId, const QgsAttributeList &deletedAttributes)
Emitted after attribute deletion has been committed to the layer.
void committedAttributeValuesChanges(const QString &layerId, const QgsChangedAttributesMap &changedAttributesValues)
Emitted after feature attribute value changes have been committed to the layer.
void geometryChanged(QgsFeatureId fid, const QgsGeometry &geom)
Emitted when a feature's geometry is changed.
void committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)
Emitted after attribute addition has been committed to the layer.
void committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)
Emitted after feature addition has been committed to the layer.
void featureDeleted(QgsFeatureId fid)
Emitted when a feature was deleted from the buffer.
void attributeAdded(int idx)
Emitted when an attribute was added to the buffer.
void committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)
Emitted after feature geometry changes have been committed to the layer.
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &value)
Emitted when a feature's attribute value has been changed.
void attributeDeleted(int idx)
Emitted when an attribute was deleted from the buffer.
void featureAdded(QgsFeatureId fid)
Emitted when a feature has been added to the buffer.
void layerModified()
Emitted when modifications has been done on layer.
void committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)
Emitted after feature removal has been committed to the layer.
Contains utility functions for editing vector layers.
int translateFeature(QgsFeatureId featureId, double dx, double dy)
Translates feature by dx, dy.
Qgis::VectorEditResult deleteVertices(QgsFeatureId featureId, const QSet< int > &vertices)
Deletes a set of vertices from a feature.
bool insertVertex(double x, double y, QgsFeatureId atFeatureId, int beforeVertex)
Insert a new vertex before the given vertex number, in the given ring, item (first number is index 0)...
Q_DECL_DEPRECATED Qgis::GeometryOperationResult addPart(const QVector< QgsPointXY > &ring, QgsFeatureId featureId)
Adds a new part polygon to a multipart feature.
Qgis::VectorEditResult deleteVertex(QgsFeatureId featureId, int vertex)
Deletes a vertex from a feature.
int addTopologicalPoints(const QgsGeometry &geom)
Adds topological points for every vertex of the geometry.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult splitParts(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits parts cut by the given line.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult splitFeatures(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits features cut by the given line.
bool moveVertex(double x, double y, QgsFeatureId atFeatureId, int atVertex)
Moves the vertex at the given position number, ring and item (first number is index 0),...
Q_DECL_DEPRECATED Qgis::GeometryOperationResult addRing(const QVector< QgsPointXY > &ring, const QgsFeatureIds &targetFeatureIds=QgsFeatureIds(), QgsFeatureId *modifiedFeatureId=nullptr)
Adds a ring to polygon/multipolygon features.
Vector layer specific subclass of QgsMapLayerElevationProperties.
QgsVectorLayerElevationProperties * clone() const override
Creates a clone of the properties.
Counts the features in a QgsVectorLayer in task.
A feature iterator which iterates over features from a QgsVectorLayer.
Manages joined fields for a vector layer.
bool containsJoins() const
Quick way to test if there is any join at all.
void joinedFieldsChanged()
Emitted whenever the list of joined fields changes (e.g.
Defines left outer join from our vector layer to some other vector layer.
QString targetFieldName() const
Returns name of the field of our layer that will be used for join.
QString joinLayerId() const
ID of the joined layer - may be used to resolve reference to the joined layer.
Implementation of QgsAbstractProfileGenerator for vector layers.
Implementation of threaded rendering for vector layers.
Implementation of layer selection properties for vector layers.
QgsVectorLayerSelectionProperties * clone() const override
Creates a clone of the properties.
Basic implementation of the labeling interface.
Implementation of map layer temporal properties for vector layers.
Contains settings which reflect the context in which vector layer tool operations should be considere...
QgsExpressionContext * expressionContext() const
Returns the optional expression context used by the vector layer tools.
static QString guessFriendlyIdentifierField(const QgsFields &fields, bool *foundFriendly=nullptr)
Given a set of fields, attempts to pick the "most useful" field for user-friendly identification of f...
static QgsFeatureIds filterValidFeatureIds(const QgsVectorLayer *layer, const QgsFeatureIds &featureIds)
Filters a set of feature IDs to only include those that exist in the layer.
Represents a vector layer which manages a vector based dataset.
void setLabeling(QgsAbstractVectorLayerLabeling *labeling)
Sets labeling configuration.
Q_INVOKABLE QString attributeDisplayName(int index) const
Convenience function that returns the attribute alias if defined or the field name else.
bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const final
Write the style for the layer into the document provided.
QSet< QgsMapLayerDependency > dependencies() const final
Gets the list of dependencies.
int addExpressionField(const QString &exp, const QgsField &fld)
Add a new field which is calculated by the expression specified.
Q_INVOKABLE void selectByRect(const QgsRectangle &rect, Qgis::SelectBehavior behavior=Qgis::SelectBehavior::SetSelection)
Selects features found within the search rectangle (in layer's coordinates).
void committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)
Emitted when features are added to the provider if not in transaction mode.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult addPart(const QList< QgsPointXY > &ring)
Adds a new part polygon to a multipart feature.
static const QgsSettingsEntryEnumFlag< Qgis::VectorRenderingSimplificationFlags > * settingsSimplifyDrawingHints
void featureBlendModeChanged(QPainter::CompositionMode blendMode)
Signal emitted when setFeatureBlendMode() is called.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
bool isModified() const override
Returns true if the provider has been modified since the last commit.
bool isEditable() const final
Returns true if the provider is in editing mode.
void addFeatureRendererGenerator(QgsFeatureRendererGenerator *generator)
Adds a new feature renderer generator to the layer.
Q_DECL_DEPRECATED void setExcludeAttributesWfs(const QSet< QString > &att)
A set of attributes that are not advertised in WFS requests with QGIS server.
Q_INVOKABLE bool deleteSelectedFeatures(int *deletedCount=nullptr, QgsVectorLayer::DeleteContext *context=nullptr)
Deletes the selected features.
Q_INVOKABLE void removeFieldAlias(int index)
Removes an alias (a display name) for attributes to display in dialogs.
void setAuxiliaryLayer(QgsAuxiliaryLayer *layer=nullptr)
Sets the current auxiliary layer.
Q_INVOKABLE QVariant minimumValue(int index) const final
Returns the minimum value for an attribute column or an invalid variant in case of error.
void beforeRemovingExpressionField(int idx)
Will be emitted, when an expression field is going to be deleted from this vector layer.
Q_INVOKABLE bool deleteFeatures(const QgsFeatureIds &fids, QgsVectorLayer::DeleteContext *context=nullptr)
Deletes a set of features from the layer (but does not commit it).
void committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)
Emitted when geometry changes are saved to the provider if not in transaction mode.
void beforeCommitChanges(bool stopEditing)
Emitted before changes are committed to the data provider.
Q_INVOKABLE bool startEditing()
Makes the layer editable.
void setFieldConfigurationFlags(int index, Qgis::FieldConfigurationFlags flags)
Sets the configuration flags of the field at given index.
Q_INVOKABLE QVariant maximumValue(int index) const final
Returns the maximum value for an attribute column or an invalid variant in case of error.
QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength > fieldConstraintsAndStrength(int fieldIndex) const
Returns a map of constraint with their strength for a specific field of the layer.
bool addJoin(const QgsVectorLayerJoinInfo &joinInfo)
Joins another vector layer to this layer.
QgsVectorLayer(const QString &path=QString(), const QString &baseName=QString(), const QString &providerLib="ogr", const QgsVectorLayer::LayerOptions &options=QgsVectorLayer::LayerOptions())
Constructor - creates a vector layer.
QgsMapLayerTemporalProperties * temporalProperties() override
Returns the layer's temporal properties.
QgsExpressionContext createExpressionContext() const final
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Q_INVOKABLE bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false, QgsVectorLayerToolsContext *context=nullptr)
Changes an attribute value for a feature (but does not immediately commit the changes).
Q_DECL_DEPRECATED Qgis::GeometryOperationResult splitFeatures(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits features cut by the given line.
QgsDefaultValue defaultValueDefinition(int index) const
Returns the definition of the expression used when calculating the default value for a field.
QgsVectorLayerFeatureCounter * countSymbolFeatures(bool storeSymbolFids=false)
Count features for symbols.
Q_INVOKABLE QString attributeCustomComment(int index) const
Returns the custom comment for the field.
QPainter::CompositionMode featureBlendMode() const
Returns the current blending mode for features.
QString constraintExpression(int index) const
Returns the constraint expression for for a specified field index, if set.
Q_INVOKABLE bool addAttribute(const QgsField &field)
Add an attribute field (but does not commit it) returns true if the field was added.
void attributeAdded(int idx)
Will be emitted, when a new attribute has been added to this vector layer.
QString capabilitiesString() const
Capabilities for this layer, comma separated and translated.
void deselect(QgsFeatureId featureId)
Deselects feature by its ID.
void allowCommitChanged()
Emitted whenever the allowCommit() property of this layer changes.
friend class QgsVectorLayerEditBuffer
void editCommandStarted(const QString &text)
Signal emitted when a new edit command has been started.
void updateFields()
Will regenerate the fields property of this layer by obtaining all fields from the dataProvider,...
QgsBox3D extent3D() const final
Returns the 3D extent of the layer.
const QgsDiagramLayerSettings * diagramLayerSettings() const
void setFieldConstraint(int index, QgsFieldConstraints::Constraint constraint, QgsFieldConstraints::ConstraintStrength strength=QgsFieldConstraints::ConstraintStrengthHard)
Sets a constraint for a specified field index.
Q_INVOKABLE void invertSelectionInRectangle(const QgsRectangle &rect)
Inverts selection of features found within the search rectangle (in layer's coordinates).
bool loadAuxiliaryLayer(const QgsAuxiliaryStorage &storage, const QString &key=QString())
Loads the auxiliary layer for this vector layer.
bool insertVertex(double x, double y, QgsFeatureId atFeatureId, int beforeVertex)
Inserts a new vertex before the given vertex number, in the given ring, item (first number is index 0...
QgsAbstractProfileGenerator * createProfileGenerator(const QgsProfileRequest &request) override
Given a profile request, returns a new profile generator ready for generating elevation profiles.
bool readSymbology(const QDomNode &layerNode, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) final
Read the symbology for the current layer from the DOM node supplied.
Q_INVOKABLE QgsRectangle boundingBoxOfSelected() const
Returns the bounding box of the selected features. If there is no selection, QgsRectangle(0,...
bool isSpatial() const final
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
Q_INVOKABLE QgsFeatureList selectedFeatures() const
Returns a copy of the user-selected features.
QString expressionField(int index) const
Returns the expression used for a given expression field.
void removeFeatureRendererGenerator(const QString &id)
Removes the feature renderer with matching id from the layer.
Q_INVOKABLE bool deleteFeature(QgsFeatureId fid, QgsVectorLayer::DeleteContext *context=nullptr)
Deletes a feature from the layer (but does not commit it).
friend class QgsVectorLayerEditPassthrough
void setSimplifyMethod(const QgsVectorSimplifyMethod &simplifyMethod)
Sets the simplification settings for fast rendering of features.
void editCommandDestroyed()
Signal emitted, when an edit command is destroyed.
QVariant aggregate(Qgis::Aggregate aggregate, const QString &fieldOrExpression, const QgsAggregateCalculator::AggregateParameters &parameters=QgsAggregateCalculator::AggregateParameters(), QgsExpressionContext *context=nullptr, bool *ok=nullptr, QgsFeatureIds *fids=nullptr, QgsFeedback *feedback=nullptr, QString *error=nullptr) const
Calculates an aggregated value from the layer's features.
QgsRectangle sourceExtent() const final
Returns the extent of all geometries from the source.
QgsFieldConstraints::Constraints fieldConstraints(int fieldIndex) const
Returns any constraints which are present for a specified field index.
static const QgsSettingsEntryEnumFlag< Qgis::VectorSimplificationAlgorithm > * settingsSimplifyAlgorithm
Q_DECL_DEPRECATED QSet< QString > excludeAttributesWms() const
A set of attributes that are not advertised in WMS requests with QGIS server.
QgsFeatureIds symbolFeatureIds(const QString &legendKey) const
Ids of features rendered with specified legend key.
void removeFieldConstraint(int index, QgsFieldConstraints::Constraint constraint)
Removes a constraint for a specified field index.
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
void featuresDeleted(const QgsFeatureIds &fids)
Emitted when features have been deleted.
Qgis::VectorLayerTypeFlags vectorLayerTypeFlags() const
Returns the vector layer type flags.
void setLabelsEnabled(bool enabled)
Sets whether labels should be enabled for the layer.
void subsetStringChanged()
Emitted when the layer's subset string has changed.
bool setDependencies(const QSet< QgsMapLayerDependency > &layers) final
Sets the list of dependencies.
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer.
void setCoordinateSystem()
Setup the coordinate system transformation for the layer.
void committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)
Emitted when features are deleted from the provider if not in transaction mode.
void setFieldMergePolicy(int index, Qgis::FieldDomainMergePolicy policy)
Sets a merge policy for the field with the specified index.
void updateExpressionField(int index, const QString &exp)
Changes the expression used to define an expression based (virtual) field.
Q_INVOKABLE void selectByExpression(const QString &expression, Qgis::SelectBehavior behavior=Qgis::SelectBehavior::SetSelection, QgsExpressionContext *context=nullptr)
Selects matching features using an expression.
static const QgsSettingsEntryDouble * settingsSimplifyMaxScale
void reload() final
Synchronises with changes in the datasource.
long long featureCount() const final
Returns feature count including changes which have not yet been committed If you need only the count ...
~QgsVectorLayer() override
QgsRectangle extent() const final
Returns the extent of the layer.
void endEditCommand()
Finish edit command and add it to undo/redo stack.
void destroyEditCommand()
Destroy active command and reverts all changes in it.
bool isAuxiliaryField(int index, int &srcIndex) const
Returns true if the field comes from the auxiliary layer, false otherwise.
bool hasMapTips() const final
Returns true if the layer contains map tips.
Q_INVOKABLE Qgis::WkbType wkbType() const final
Returns the WKBType or WKBUnknown in case of error.
void setExtent(const QgsRectangle &rect) final
Sets the extent.
QList< QgsRelation > referencingRelations(int idx) const
Returns the layer's relations, where the foreign key is on this layer.
Q_DECL_DEPRECATED QSet< QString > excludeAttributesWfs() const
A set of attributes that are not advertised in WFS requests with QGIS server.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult splitParts(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits parts cut by the given line.
void setDefaultValueDefinition(int index, const QgsDefaultValue &definition)
Sets the definition of the expression to use when calculating the default value for a field.
bool diagramsEnabled() const
Returns whether the layer contains diagrams which are enabled and should be drawn.
void setAllowCommit(bool allowCommit)
Controls, if the layer is allowed to commit changes.
QgsBox3D sourceExtent3D() const final
Returns the 3D extent of all geometries from the source.
void symbolFeatureCountMapChanged()
Emitted when the feature count for symbols on this layer has been recalculated.
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
Qgis::VectorEditResult deleteVertex(QgsFeatureId featureId, int vertex)
Deletes a vertex from a feature.
Qgis::FeatureAvailability hasFeatures() const final
Determines if this vector layer has features.
void setFeatureBlendMode(QPainter::CompositionMode blendMode)
Sets the blending mode used for rendering each feature.
QString constraintDescription(int index) const
Returns the descriptive name for the constraint expression for a specified field index.
void writeCustomSymbology(QDomElement &element, QDomDocument &doc, QString &errorMessage) const
Signal emitted whenever the symbology (QML-file) for this layer is being written.
const QgsAbstractVectorLayerLabeling * labeling() const
Access to const labeling configuration.
bool writeStyle(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const final
Write just the symbology information for the layer into the document.
void setProviderEncoding(const QString &encoding)
Sets the text encoding of the data provider.
Q_DECL_DEPRECATED bool writeSld(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QVariantMap &props=QVariantMap()) const
Writes the symbology of the layer into the document provided in SLD 1.1 format.
void setDisplayExpression(const QString &displayExpression)
Set the preview expression, used to create a human readable preview string.
virtual Q_INVOKABLE bool deleteAttribute(int attr)
Deletes an attribute field (but does not commit it).
static const QgsSettingsEntryBool * settingsSimplifyLocal
QString loadDefaultStyle(bool &resultFlag) final
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
bool simplifyDrawingCanbeApplied(const QgsRenderContext &renderContext, Qgis::VectorRenderingSimplificationFlag simplifyHint) const
Returns whether the VectorLayer can apply the specified simplification hint.
QString htmlMetadata() const final
Obtain a formatted HTML string containing assorted metadata for this layer.
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
bool removeJoin(const QString &joinLayerId)
Removes a vector layer join.
void setRenderer(QgsFeatureRenderer *r)
Sets the feature renderer which will be invoked to represent this layer in 2D map views.
Q_INVOKABLE void selectAll()
Select all the features.
QStringList commitErrors() const
Returns a list containing any error messages generated when attempting to commit changes to the layer...
QString decodedSource(const QString &source, const QString &provider, const QgsReadWriteContext &context) const final
Called by readLayerXML(), used by derived classes to decode provider's specific data source from proj...
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
QString encodedSource(const QString &source, const QgsReadWriteContext &context) const final
Called by writeLayerXML(), used by derived classes to encode provider's specific data source to proje...
bool readExtentFromXml() const
Returns true if the extent is read from the XML document when data source has no metadata,...
QString dataComment() const
Returns a description for this layer as defined in the data provider.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
QgsExpressionContextScope * createExpressionContextScope() const final
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QgsGeometryOptions * geometryOptions() const
Configuration and logic to apply automatically on any edit happening on this layer.
QgsStringMap attributeAliases() const
Returns a map of field name to attribute alias.
Q_INVOKABLE int translateFeature(QgsFeatureId featureId, double dx, double dy)
Translates feature by dx, dy.
virtual void updateExtents(bool force=false)
Update the extents for the layer.
void attributeDeleted(int idx)
Will be emitted, when an attribute has been deleted from this vector layer.
QgsFeatureRenderer * renderer()
Returns the feature renderer used for rendering the features in the layer in 2D map views.
void beforeEditingStarted()
Emitted before editing on this layer is started.
void committedAttributeValuesChanges(const QString &layerId, const QgsChangedAttributesMap &changedAttributesValues)
Emitted when attribute value changes are saved to the provider if not in transaction mode.
QgsStringMap attributeCustomComments() const
Returns a map of all the custom comments.
void committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)
Emitted when attributes are added to the provider if not in transaction mode.
void setEditFormConfig(const QgsEditFormConfig &editFormConfig)
Sets the editFormConfig (configuration) of the form used to represent this vector layer.
Qgis::FieldConfigurationFlags fieldConfigurationFlags(int index) const
Returns the configuration flags of the field at given index.
void committedAttributesDeleted(const QString &layerId, const QgsAttributeList &deletedAttributes)
Emitted when attributes are deleted from the provider if not in transaction mode.
QString displayExpression
void displayExpressionChanged()
Emitted when the display expression changes.
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
void setEditorWidgetSetup(int index, const QgsEditorWidgetSetup &setup)
Sets the editor widget setup for the field at the specified index.
void setConstraintExpression(int index, const QString &expression, const QString &description=QString())
Sets the constraint expression for the specified field index.
Q_INVOKABLE bool rollBack(bool deleteBuffer=true)
Stops a current editing operation and discards any uncommitted edits.
QString sourceName() const final
Returns a friendly display name for the source.
Qgis::VectorEditResult deleteVertices(QgsFeatureId featureId, const QSet< int > &vertices)
Deletes a set of vertices from a feature.
bool readStyle(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) final
Read the style for the current layer from the DOM node supplied.
bool updateFeature(QgsFeature &feature, bool skipDefaultValues=false)
Updates an existing feature in the layer, replacing the attributes and geometry for the feature with ...
Q_INVOKABLE bool commitChanges(bool stopEditing=true)
Attempts to commit to the underlying data provider any buffered changes made since the last to call t...
void setFieldConfigurationFlag(int index, Qgis::FieldConfigurationFlag flag, bool active)
Sets the given configuration flag for the field at given index to be active or not.
void setFieldDuplicatePolicy(int index, Qgis::FieldDuplicatePolicy policy)
Sets a duplicate policy for the field with the specified index.
bool setReadOnly(bool readonly=true)
Makes layer read-only (editing disabled) or not.
void editFormConfigChanged()
Will be emitted whenever the edit form configuration of this layer changes.
Q_INVOKABLE void modifySelection(const QgsFeatureIds &selectIds, const QgsFeatureIds &deselectIds)
Modifies the current selection on this layer.
void setWeakRelations(const QList< QgsWeakRelation > &relations)
Sets the layer's weak relations.
void resolveReferences(QgsProject *project) final
Resolves references to other layers (kept as layer IDs after reading XML) into layer objects.
void reselect()
Reselects the previous set of selected features.
void select(QgsFeatureId featureId)
Selects feature by its ID.
QgsEditorWidgetSetup editorWidgetSetup(int index) const
Returns the editor widget setup for the field at the specified index.
bool readSld(const QDomNode &node, QString &errorMessage) final
QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext) final
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context.
Q_INVOKABLE void setFieldCustomComment(int index, const QString &customCommentString)
Sets the custom comment for the field.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
void setReadExtentFromXml(bool readExtentFromXml)
Flag allowing to indicate if the extent has to be read from the XML document when data source has no ...
void afterCommitChanges()
Emitted after changes are committed to the data provider.
QgsVectorLayer * clone() const override
Returns a new instance equivalent to this one.
QgsAttributeTableConfig attributeTableConfig() const
Returns the attribute table configuration object.
QgsActionManager * actions()
Returns all layer actions defined on this layer.
QStringList uniqueStringsMatching(int index, const QString &substring, int limit=-1, QgsFeedback *feedback=nullptr) const
Returns unique string values of an attribute which contain a specified subset string.
void raiseError(const QString &msg)
Signals an error related to this vector layer.
void editCommandEnded()
Signal emitted, when an edit command successfully ended.
void supportsEditingChanged()
Emitted when the read only state or the data provider of this layer is changed.
QgsCoordinateReferenceSystem sourceCrs() const final
Returns the coordinate reference system for features in the source.
void readOnlyChanged()
Emitted when the read only state of this layer is changed.
void removeExpressionField(int index)
Removes an expression field.
void setTransformContext(const QgsCoordinateTransformContext &transformContext) override
Sets the coordinate transform context to transformContext.
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &value)
Emitted whenever an attribute value change is done in the edit buffer.
static Q_DECL_DEPRECATED void drawVertexMarker(double x, double y, QPainter &p, Qgis::VertexMarkerType type, int vertexSize)
Draws a vertex symbol at (screen) coordinates x, y.
Q_INVOKABLE void selectByIds(const QgsFeatureIds &ids, Qgis::SelectBehavior behavior=Qgis::SelectBehavior::SetSelection, bool validateIds=false)
Selects matching features using a list of feature IDs.
Q_INVOKABLE void setFieldAlias(int index, const QString &aliasString)
Sets an alias (a display name) for attributes to display in dialogs.
friend class QgsVectorLayerFeatureSource
void minimumAndMaximumValue(int index, QVariant &minimum, QVariant &maximum) const
Calculates both the minimum and maximum value for an attribute column.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
Q_DECL_DEPRECATED void setExcludeAttributesWms(const QSet< QString > &att)
A set of attributes that are not advertised in WMS requests with QGIS server.
void setAttributeTableConfig(const QgsAttributeTableConfig &attributeTableConfig)
Sets the attribute table configuration object.
virtual bool setSubsetString(const QString &subset)
Sets the string (typically sql) used to define a subset of the layer.
void afterRollBack()
Emitted after changes are rolled back.
bool writeXml(QDomNode &layer_node, QDomDocument &doc, const QgsReadWriteContext &context) const final
Writes vector layer specific state to project file Dom node.
void setDiagramLayerSettings(const QgsDiagramLayerSettings &s)
bool readXml(const QDomNode &layer_node, QgsReadWriteContext &context) final
Reads vector layer specific state from project file Dom node.
QList< QgsWeakRelation > weakRelations() const
Returns the layer's weak relations as specified in the layer's style.
const QgsVectorSimplifyMethod & simplifyMethod() const
Returns the simplification settings for fast rendering of features.
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
void beforeAddingExpressionField(const QString &fieldName)
Will be emitted, when an expression field is going to be added to this vector layer.
Q_INVOKABLE bool deleteAttributes(const QList< int > &attrs)
Deletes a list of attribute fields (but does not commit it).
void updatedFields()
Emitted whenever the fields available from this layer have been changed.
QVariant defaultValue(int index, const QgsFeature &feature=QgsFeature(), QgsExpressionContext *context=nullptr) const
Returns the calculated default value for the specified field index.
void featureAdded(QgsFeatureId fid)
Emitted when a new feature has been added to the layer.
Q_INVOKABLE QString attributeAlias(int index) const
Returns the alias of an attribute name or a null string if there is no alias.
void featureDeleted(QgsFeatureId fid)
Emitted when a feature has been deleted.
Q_INVOKABLE void removeSelection()
Clear selection.
bool allowCommit() const
Controls, if the layer is allowed to commit changes.
QgsConditionalLayerStyles * conditionalStyles() const
Returns the conditional styles that are set for this layer.
void readCustomSymbology(const QDomElement &element, QString &errorMessage)
Signal emitted whenever the symbology (QML-file) for this layer is being read.
void setExtent3D(const QgsBox3D &rect) final
Sets the extent.
const QList< QgsVectorLayerJoinInfo > vectorJoins() const
Q_INVOKABLE bool renameAttribute(int index, const QString &newName)
Renames an attribute field (but does not commit it).
bool isSqlQuery() const
Returns true if the layer is a query (SQL) layer.
void beforeRollBack()
Emitted before changes are rolled back.
QgsAttributeList primaryKeyAttributes() const
Returns the list of attributes which make up the layer's primary keys.
void beginEditCommand(const QString &text)
Create edit command for undo/redo operations.
QString displayField() const
This is a shorthand for accessing the displayExpression if it is a simple field.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult addRing(const QVector< QgsPointXY > &ring, QgsFeatureId *featureId=nullptr)
Adds a ring to polygon/multipolygon features.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) final
Adds a list of features to the sink.
void setDiagramRenderer(QgsDiagramRenderer *r)
Sets diagram rendering object (takes ownership).
void geometryChanged(QgsFeatureId fid, const QgsGeometry &geometry)
Emitted whenever a geometry change is done in the edit buffer.
QgsEditFormConfig editFormConfig
QList< const QgsFeatureRendererGenerator * > featureRendererGenerators() const
Returns a list of the feature renderer generators owned by the layer.
Q_INVOKABLE QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const final
Calculates a list of unique values contained within an attribute in the layer.
Q_INVOKABLE void removeFieldCustomComment(int index)
Removes the custom comment for the field.
bool moveVertex(double x, double y, QgsFeatureId atFeatureId, int atVertex)
Moves the vertex at the given position number, ring and item (first number is index 0),...
QgsGeometry getGeometry(QgsFeatureId fid) const
Queries the layer for the geometry at the given id.
int addTopologicalPoints(const QgsGeometry &geom)
Adds topological points for every vertex of the geometry.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) final
Adds a single feature to the sink.
void beforeModifiedCheck() const
Emitted when the layer is checked for modifications. Use for last-minute additions.
Q_INVOKABLE QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
Q_INVOKABLE void invertSelection()
Selects not selected features and deselects selected ones.
const QgsDiagramRenderer * diagramRenderer() const
Q_INVOKABLE bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues=QgsAttributeMap(), bool skipDefaultValues=false, QgsVectorLayerToolsContext *context=nullptr)
Changes attributes' values for a feature (but does not immediately commit the changes).
QgsMapLayerSelectionProperties * selectionProperties() override
Returns the layer's selection properties.
QgsVectorDataProvider * dataProvider() final
Returns the layer's data provider, it may be nullptr.
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...
static const QgsSettingsEntryDouble * settingsSimplifyDrawingTol
Qgis::SpatialIndexPresence hasSpatialIndex() const override
void setFieldSplitPolicy(int index, Qgis::FieldDomainSplitPolicy policy)
Sets a split policy for the field with the specified index.
@ Referencing
The layer is referencing (or the "child" / "right" layer in the relationship).
@ Referenced
The layer is referenced (or the "parent" / "left" left in the relationship).
static void writeXml(const QgsVectorLayer *layer, WeakRelationType type, const QgsRelation &relation, QDomNode &node, QDomDocument &doc)
Writes a weak relation infoto an XML structure.
static QgsWeakRelation readXml(const QgsVectorLayer *layer, WeakRelationType type, const QDomNode &node, const QgsPathResolver resolver)
Returns a weak relation for the given layer.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static Q_INVOKABLE QString displayString(Qgis::WkbType type)
Returns a non-translated display string type for a WKB type, e.g., the geometry name used in WKT geom...
static Q_INVOKABLE QString geometryDisplayString(Qgis::GeometryType type)
Returns a display string for a geometry type.
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
static QgsBox3D readBox3D(const QDomElement &element)
Decodes a DOM element to a 3D box.
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
static QgsRectangle readRectangle(const QDomElement &element)
@ UnknownCount
Provider returned an unknown feature count.
Definition qgis.h:574
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored).
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsVariantEqual(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether they are equal, two NULL values are always treated a...
Definition qgis.cpp:657
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is less than the second.
Definition qgis.cpp:596
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is greater than the second.
Definition qgis.cpp:601
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
Definition qgis.h:7458
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:7439
QString qgsFlagValueToKeys(const T &value, bool *returnOk=nullptr)
Returns the value for the given keys of a flag.
Definition qgis.h:7497
T qgsFlagKeysToValue(const QString &keys, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given keys of a flag.
Definition qgis.h:7526
QMap< QString, QString > QgsStringMap
Definition qgis.h:7772
QVector< QgsPoint > QgsPointSequence
QMap< int, QVariant > QgsAttributeMap
QList< QgsFeature > QgsFeatureList
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
#define QgsDebugError(str)
Definition qgslogger.h:59
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
#define RENDERER_TAG_NAME
Definition qgsrenderer.h:57
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS_NON_FATAL
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS
bool saveStyle_t(const QString &uri, const QString &qmlStyle, const QString &sldStyle, const QString &styleName, const QString &styleDescription, const QString &uiFileContent, bool useAsDefault, QString &errCause)
int listStyles_t(const QString &uri, QStringList &ids, QStringList &names, QStringList &descriptions, QString &errCause)
QString getStyleById_t(const QString &uri, QString styleID, QString &errCause)
bool deleteStyleById_t(const QString &uri, QString styleID, QString &errCause)
QString loadStyle_t(const QString &uri, QString &errCause)
QList< int > QgsAttributeList
QMap< QgsFeatureId, QgsFeature > QgsFeatureMap
A bundle of parameters controlling aggregate calculation.
Setting options for creating vector data providers.
Context for cascade delete features.
QList< QgsVectorLayer * > handledLayers(bool includeAuxiliaryLayers=true) const
Returns a list of all layers affected by the delete operation.
QMap< QgsVectorLayer *, QgsFeatureIds > mHandledFeatures
QgsFeatureIds handledFeatures(QgsVectorLayer *layer) const
Returns a list of feature IDs from the specified layer affected by the delete operation.
Setting options for loading vector layers.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
bool forceReadOnly
Controls whether the layer is forced to be load as Read Only.
bool loadDefaultStyle
Set to true if the default layer style should be loaded.
QgsCoordinateTransformContext transformContext
Coordinate transform context.
QgsCoordinateReferenceSystem fallbackCrs
Fallback layer coordinate reference system.
Qgis::WkbType fallbackWkbType
Fallback geometry type.
bool loadAllStoredStyles
Controls whether the stored styles will be all loaded.