QGIS API Documentation 3.34.0-Prizren (ffbdd678812)
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 "qgis.h" //for globals
25#include "qgssettings.h"
26#include "qgsvectorlayer.h"
27#include "qgsactionmanager.h"
28#include "qgsapplication.h"
29#include "qgsconditionalstyle.h"
31#include "qgscurve.h"
32#include "qgsdatasourceuri.h"
35#include "qgsfeature.h"
36#include "qgsfeaturerequest.h"
37#include "qgsfields.h"
38#include "qgsmaplayerfactory.h"
40#include "qgsgeometry.h"
42#include "qgslogger.h"
43#include "qgsmaplayerlegend.h"
44#include "qgsmessagelog.h"
45#include "qgsogcutils.h"
46#include "qgspainting.h"
47#include "qgspointxy.h"
48#include "qgsproject.h"
49#include "qgsproviderregistry.h"
50#include "qgsrectangle.h"
51#include "qgsrelationmanager.h"
52#include "qgsweakrelation.h"
53#include "qgsrendercontext.h"
66#include "qgspoint.h"
67#include "qgsrenderer.h"
68#include "qgssymbollayer.h"
69#include "qgsdiagramrenderer.h"
70#include "qgspallabeling.h"
74#include "qgsfeedback.h"
75#include "qgsxmlutils.h"
76#include "qgstaskmanager.h"
77#include "qgstransaction.h"
78#include "qgsauxiliarystorage.h"
79#include "qgsgeometryoptions.h"
81#include "qgsruntimeprofiler.h"
83#include "qgsvectorlayerutils.h"
85#include "qgsprofilerequest.h"
86#include "qgssymbollayerutils.h"
87#include "qgsthreadingutils.h"
88
89#include <QDir>
90#include <QFile>
91#include <QImage>
92#include <QPainter>
93#include <QPainterPath>
94#include <QPolygonF>
95#include <QProgressDialog>
96#include <QString>
97#include <QDomNode>
98#include <QVector>
99#include <QStringBuilder>
100#include <QUrl>
101#include <QUndoCommand>
102#include <QUrlQuery>
103#include <QUuid>
104#include <QRegularExpression>
105#include <QTimer>
106
107#include <limits>
108#include <optional>
109
111#include "qgssettingsentryimpl.h"
112#include "qgssettingstree.h"
113
119
120
121#ifdef TESTPROVIDERLIB
122#include <dlfcn.h>
123#endif
124
125typedef bool saveStyle_t(
126 const QString &uri,
127 const QString &qmlStyle,
128 const QString &sldStyle,
129 const QString &styleName,
130 const QString &styleDescription,
131 const QString &uiFileContent,
132 bool useAsDefault,
133 QString &errCause
134);
135
136typedef QString loadStyle_t(
137 const QString &uri,
138 QString &errCause
139);
140
141typedef int listStyles_t(
142 const QString &uri,
143 QStringList &ids,
144 QStringList &names,
145 QStringList &descriptions,
146 QString &errCause
147);
148
149typedef QString getStyleById_t(
150 const QString &uri,
151 QString styleID,
152 QString &errCause
153);
154
155typedef bool deleteStyleById_t(
156 const QString &uri,
157 QString styleID,
158 QString &errCause
159);
160
161
162QgsVectorLayer::QgsVectorLayer( const QString &vectorLayerPath,
163 const QString &baseName,
164 const QString &providerKey,
165 const QgsVectorLayer::LayerOptions &options )
166 : QgsMapLayer( Qgis::LayerType::Vector, baseName, vectorLayerPath )
167 , mSelectionProperties( new QgsVectorLayerSelectionProperties( this ) )
168 , mTemporalProperties( new QgsVectorLayerTemporalProperties( this ) )
169 , mElevationProperties( new QgsVectorLayerElevationProperties( this ) )
170 , mAuxiliaryLayer( nullptr )
171 , mAuxiliaryLayerKey( QString() )
172 , mReadExtentFromXml( options.readExtentFromXml )
173 , mRefreshRendererTimer( new QTimer( this ) )
174{
176 mLoadAllStoredStyle = options.loadAllStoredStyles;
177
178 if ( options.fallbackCrs.isValid() )
179 setCrs( options.fallbackCrs, false );
180 mWkbType = options.fallbackWkbType;
181
182 setProviderType( providerKey );
183
184 mGeometryOptions = std::make_unique<QgsGeometryOptions>();
185 mActions = new QgsActionManager( this );
186 mConditionalStyles = new QgsConditionalLayerStyles( this );
187 mStoredExpressionManager = new QgsStoredExpressionManager();
188 mStoredExpressionManager->setParent( this );
189
190 mJoinBuffer = new QgsVectorLayerJoinBuffer( this );
191 mJoinBuffer->setParent( this );
192 connect( mJoinBuffer, &QgsVectorLayerJoinBuffer::joinedFieldsChanged, this, &QgsVectorLayer::onJoinedFieldsChanged );
193
194 mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
195 // if we're given a provider type, try to create and bind one to this layer
196 if ( !vectorLayerPath.isEmpty() && !mProviderKey.isEmpty() )
197 {
198 QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
199 QgsDataProvider::ReadFlags providerFlags = QgsDataProvider::ReadFlags();
200 if ( options.loadDefaultStyle )
201 {
203 }
204 if ( options.forceReadOnly )
205 {
206 providerFlags |= QgsDataProvider::ForceReadOnly;
207 mDataSourceReadOnly = true;
208 }
209 setDataSource( vectorLayerPath, baseName, providerKey, providerOptions, providerFlags );
210 }
211
212 for ( const QgsField &field : std::as_const( mFields ) )
213 {
214 if ( !mAttributeAliasMap.contains( field.name() ) )
215 mAttributeAliasMap.insert( field.name(), QString() );
216 }
217
218 if ( isValid() )
219 {
220 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
221 if ( !mTemporalProperties->isActive() )
222 {
223 // didn't populate temporal properties from provider metadata, so at least try to setup some initially nice
224 // selections
225 mTemporalProperties->guessDefaultsFromFields( mFields );
226 }
227
228 mElevationProperties->setDefaultsFromLayer( this );
229 }
230
231 connect( this, &QgsVectorLayer::selectionChanged, this, [ = ] { triggerRepaint(); } );
232 connect( QgsProject::instance()->relationManager(), &QgsRelationManager::relationsLoaded, this, &QgsVectorLayer::onRelationsLoaded );
233
237
238 // Default simplify drawing settings
239 QgsSettings settings;
240 mSimplifyMethod.setSimplifyHints( QgsVectorLayer::settingsSimplifyDrawingHints->valueWithDefaultOverride( mSimplifyMethod.simplifyHints() ) );
241 mSimplifyMethod.setSimplifyAlgorithm( QgsVectorLayer::settingsSimplifyAlgorithm->valueWithDefaultOverride( mSimplifyMethod.simplifyAlgorithm() ) );
242 mSimplifyMethod.setThreshold( QgsVectorLayer::settingsSimplifyDrawingTol->valueWithDefaultOverride( mSimplifyMethod.threshold() ) );
243 mSimplifyMethod.setForceLocalOptimization( QgsVectorLayer::settingsSimplifyLocal->valueWithDefaultOverride( mSimplifyMethod.forceLocalOptimization() ) );
244 mSimplifyMethod.setMaximumScale( QgsVectorLayer::settingsSimplifyMaxScale->valueWithDefaultOverride( mSimplifyMethod.maximumScale() ) );
245
246 connect( mRefreshRendererTimer, &QTimer::timeout, this, [ = ] { triggerRepaint( true ); } );
247}
248
250{
251 emit willBeDeleted();
252
253 setValid( false );
254
255 delete mDataProvider;
256 delete mEditBuffer;
257 delete mJoinBuffer;
258 delete mExpressionFieldBuffer;
259 delete mLabeling;
260 delete mDiagramLayerSettings;
261 delete mDiagramRenderer;
262
263 delete mActions;
264
265 delete mRenderer;
266 delete mConditionalStyles;
267 delete mStoredExpressionManager;
268
269 if ( mFeatureCounter )
270 mFeatureCounter->cancel();
271
272 qDeleteAll( mRendererGenerators );
273}
274
276{
278
280 // We get the data source string from the provider when
281 // possible because some providers may have changed it
282 // directly (memory provider does that).
283 QString dataSource;
284 if ( mDataProvider )
285 {
286 dataSource = mDataProvider->dataSourceUri();
287 options.transformContext = mDataProvider->transformContext();
288 }
289 else
290 {
291 dataSource = source();
292 }
293 options.forceReadOnly = mDataSourceReadOnly;
294 QgsVectorLayer *layer = new QgsVectorLayer( dataSource, name(), mProviderKey, options );
295 if ( mDataProvider && layer->dataProvider() )
296 {
297 layer->dataProvider()->handlePostCloneOperations( mDataProvider );
298 }
299 QgsMapLayer::clone( layer );
300
301 QList<QgsVectorLayerJoinInfo> joins = vectorJoins();
302 const auto constJoins = joins;
303 for ( const QgsVectorLayerJoinInfo &join : constJoins )
304 {
305 // do not copy join information for auxiliary layer
306 if ( !auxiliaryLayer()
307 || ( auxiliaryLayer() && auxiliaryLayer()->id() != join.joinLayerId() ) )
308 layer->addJoin( join );
309 }
310
311 if ( mDataProvider )
312 layer->setProviderEncoding( mDataProvider->encoding() );
313 layer->setSubsetString( subsetString() );
317 layer->setReadOnly( isReadOnly() );
322
323 const auto constActions = actions()->actions();
324 for ( const QgsAction &action : constActions )
325 {
326 layer->actions()->addAction( action );
327 }
328
329 if ( auto *lRenderer = renderer() )
330 {
331 layer->setRenderer( lRenderer->clone() );
332 }
333
334 if ( auto *lLabeling = labeling() )
335 {
336 layer->setLabeling( lLabeling->clone() );
337 }
339
341
342 if ( auto *lDiagramRenderer = diagramRenderer() )
343 {
344 layer->setDiagramRenderer( lDiagramRenderer->clone() );
345 }
346
347 if ( auto *lDiagramLayerSettings = diagramLayerSettings() )
348 {
349 layer->setDiagramLayerSettings( *lDiagramLayerSettings );
350 }
351
352 for ( int i = 0; i < fields().count(); i++ )
353 {
354 layer->setFieldAlias( i, attributeAlias( i ) );
356 layer->setEditorWidgetSetup( i, editorWidgetSetup( i ) );
359
360 QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength> constraints = fieldConstraintsAndStrength( i );
361 auto constraintIt = constraints.constBegin();
362 for ( ; constraintIt != constraints.constEnd(); ++ constraintIt )
363 {
364 layer->setFieldConstraint( i, constraintIt.key(), constraintIt.value() );
365 }
366
367 if ( fields().fieldOrigin( i ) == QgsFields::OriginExpression )
368 {
369 layer->addExpressionField( expressionField( i ), fields().at( i ) );
370 }
371 }
372
374
375 if ( auto *lAuxiliaryLayer = auxiliaryLayer() )
376 layer->setAuxiliaryLayer( lAuxiliaryLayer->clone( layer ) );
377
378 layer->mElevationProperties = mElevationProperties->clone();
379 layer->mElevationProperties->setParent( layer );
380
381 layer->mSelectionProperties = mSelectionProperties->clone();
382 layer->mSelectionProperties->setParent( layer );
383
384 return layer;
385}
386
388{
390
391 if ( mDataProvider )
392 {
393 return mDataProvider->storageType();
394 }
395 return QString();
396}
397
398
400{
402
403 if ( mDataProvider )
404 {
405 return mDataProvider->capabilitiesString();
406 }
407 return QString();
408}
409
411{
413
414 return mDataProvider && mDataProvider->isSqlQuery();
415}
416
417Qgis::VectorLayerTypeFlags QgsVectorLayer::vectorLayerTypeFlags() const
418{
420
421 return mDataProvider ? mDataProvider->vectorLayerTypeFlags() : Qgis::VectorLayerTypeFlags();
422}
423
425{
427
428 if ( mDataProvider )
429 {
430 return mDataProvider->dataComment();
431 }
432 return QString();
433}
434
441
443{
445
446 return name();
447}
448
450{
451 // non fatal for now -- the QgsVirtualLayerTask class is not thread safe and calls this
453
454 if ( mDataProvider )
455 {
456 mDataProvider->reloadData();
457 updateFields();
458 }
459}
460
462{
463 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
465
466 return new QgsVectorLayerRenderer( this, rendererContext );
467}
468
469
470void QgsVectorLayer::drawVertexMarker( double x, double y, QPainter &p, Qgis::VertexMarkerType type, int m )
471{
472 switch ( type )
473 {
475 p.setPen( QColor( 50, 100, 120, 200 ) );
476 p.setBrush( QColor( 200, 200, 210, 120 ) );
477 p.drawEllipse( x - m, y - m, m * 2 + 1, m * 2 + 1 );
478 break;
479
481 p.setPen( QColor( 255, 0, 0 ) );
482 p.drawLine( x - m, y + m, x + m, y - m );
483 p.drawLine( x - m, y - m, x + m, y + m );
484 break;
485
487 break;
488 }
489}
490
492{
494
495 mSelectedFeatureIds.insert( fid );
496 mPreviousSelectedFeatureIds.clear();
497
498 emit selectionChanged( QgsFeatureIds() << fid, QgsFeatureIds(), false );
499}
500
501void QgsVectorLayer::select( const QgsFeatureIds &featureIds )
502{
504
505 mSelectedFeatureIds.unite( featureIds );
506 mPreviousSelectedFeatureIds.clear();
507
508 emit selectionChanged( featureIds, QgsFeatureIds(), false );
509}
510
512{
514
515 mSelectedFeatureIds.remove( fid );
516 mPreviousSelectedFeatureIds.clear();
517
518 emit selectionChanged( QgsFeatureIds(), QgsFeatureIds() << fid, false );
519}
520
522{
524
525 mSelectedFeatureIds.subtract( featureIds );
526 mPreviousSelectedFeatureIds.clear();
527
528 emit selectionChanged( QgsFeatureIds(), featureIds, false );
529}
530
532{
534
535 // normalize the rectangle
536 rect.normalize();
537
538 QgsFeatureIds newSelection;
539
541 .setFilterRect( rect )
543 .setNoAttributes() );
544
545 QgsFeature feat;
546 while ( features.nextFeature( feat ) )
547 {
548 newSelection << feat.id();
549 }
550 features.close();
551
552 selectByIds( newSelection, behavior );
553}
554
555void QgsVectorLayer::selectByExpression( const QString &expression, Qgis::SelectBehavior behavior, QgsExpressionContext *context )
556{
558
559 QgsFeatureIds newSelection;
560
561 std::optional< QgsExpressionContext > defaultContext;
562 if ( !context )
563 {
564 defaultContext.emplace( QgsExpressionContextUtils::globalProjectLayerScopes( this ) );
565 context = &defaultContext.value();
566 }
567
569 {
571 .setExpressionContext( *context )
574
575 QgsFeatureIterator features = getFeatures( request );
576
577 if ( behavior == Qgis::SelectBehavior::AddToSelection )
578 {
579 newSelection = selectedFeatureIds();
580 }
581 QgsFeature feat;
582 while ( features.nextFeature( feat ) )
583 {
584 newSelection << feat.id();
585 }
586 features.close();
587 }
589 {
590 QgsExpression exp( expression );
591 exp.prepare( context );
592
593 QgsFeatureIds oldSelection = selectedFeatureIds();
594 QgsFeatureRequest request = QgsFeatureRequest().setFilterFids( oldSelection );
595
596 //refine request
597 if ( !exp.needsGeometry() )
601 QgsFeatureIterator features = getFeatures( request );
602 QgsFeature feat;
603 while ( features.nextFeature( feat ) )
604 {
605 context->setFeature( feat );
606 bool matches = exp.evaluate( context ).toBool();
607
608 if ( matches && behavior == Qgis::SelectBehavior::IntersectSelection )
609 {
610 newSelection << feat.id();
611 }
612 else if ( !matches && behavior == Qgis::SelectBehavior::RemoveFromSelection )
613 {
614 newSelection << feat.id();
615 }
616 }
617 }
618
619 selectByIds( newSelection );
620}
621
623{
625
626 QgsFeatureIds newSelection;
627
628 switch ( behavior )
629 {
631 newSelection = ids;
632 break;
633
635 newSelection = mSelectedFeatureIds + ids;
636 break;
637
639 newSelection = mSelectedFeatureIds - ids;
640 break;
641
643 newSelection = mSelectedFeatureIds.intersect( ids );
644 break;
645 }
646
647 QgsFeatureIds deselectedFeatures = mSelectedFeatureIds - newSelection;
648 mSelectedFeatureIds = newSelection;
649 mPreviousSelectedFeatureIds.clear();
650
651 emit selectionChanged( newSelection, deselectedFeatures, true );
652}
653
654void QgsVectorLayer::modifySelection( const QgsFeatureIds &selectIds, const QgsFeatureIds &deselectIds )
655{
657
658 QgsFeatureIds intersectingIds = selectIds & deselectIds;
659 if ( !intersectingIds.isEmpty() )
660 {
661 QgsDebugMsgLevel( QStringLiteral( "Trying to select and deselect the same item at the same time. Unsure what to do. Selecting dubious items." ), 3 );
662 }
663
664 mSelectedFeatureIds -= deselectIds;
665 mSelectedFeatureIds += selectIds;
666 mPreviousSelectedFeatureIds.clear();
667
668 emit selectionChanged( selectIds, deselectIds - intersectingIds, false );
669}
670
672{
674
676 ids.subtract( mSelectedFeatureIds );
677 selectByIds( ids );
678}
679
686
688{
690
691 // normalize the rectangle
692 rect.normalize();
693
695 .setFilterRect( rect )
697 .setNoAttributes() );
698
699 QgsFeatureIds selectIds;
700 QgsFeatureIds deselectIds;
701
702 QgsFeature fet;
703 while ( fit.nextFeature( fet ) )
704 {
705 if ( mSelectedFeatureIds.contains( fet.id() ) )
706 {
707 deselectIds << fet.id();
708 }
709 else
710 {
711 selectIds << fet.id();
712 }
713 }
714
715 modifySelection( selectIds, deselectIds );
716}
717
719{
721
722 if ( mSelectedFeatureIds.isEmpty() )
723 return;
724
725 const QgsFeatureIds previous = mSelectedFeatureIds;
727 mPreviousSelectedFeatureIds = previous;
728}
729
731{
733
734 if ( mPreviousSelectedFeatureIds.isEmpty() || !mSelectedFeatureIds.empty() )
735 return;
736
737 selectByIds( mPreviousSelectedFeatureIds );
738}
739
741{
742 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
744
745 return mDataProvider;
746}
747
749{
750 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
752
753 return mDataProvider;
754}
755
757{
758 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
760
761 return mSelectionProperties;
762}
763
770
777
779{
781
782 QgsProfileRequest modifiedRequest( request );
783 modifiedRequest.expressionContext().appendScope( createExpressionContextScope() );
784 return new QgsVectorLayerProfileGenerator( this, modifiedRequest );
785}
786
787void QgsVectorLayer::setProviderEncoding( const QString &encoding )
788{
790
791 if ( isValid() && mDataProvider && mDataProvider->encoding() != encoding )
792 {
793 mDataProvider->setEncoding( encoding );
794 updateFields();
795 }
796}
797
799{
801
802 delete mDiagramRenderer;
803 mDiagramRenderer = r;
804 emit rendererChanged();
805 emit styleChanged();
806}
807
809{
810 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
812
813 return QgsWkbTypes::geometryType( mWkbType );
814}
815
817{
819
820 return mWkbType;
821}
822
824{
826
827 if ( !isValid() || !isSpatial() || mSelectedFeatureIds.isEmpty() || !mDataProvider ) //no selected features
828 {
829 return QgsRectangle( 0, 0, 0, 0 );
830 }
831
832 QgsRectangle r, retval;
833 retval.setNull();
834
835 QgsFeature fet;
836 if ( mDataProvider->capabilities() & QgsVectorDataProvider::SelectAtId )
837 {
839 .setFilterFids( mSelectedFeatureIds )
840 .setNoAttributes() );
841
842 while ( fit.nextFeature( fet ) )
843 {
844 if ( !fet.hasGeometry() )
845 continue;
846 r = fet.geometry().boundingBox();
847 retval.combineExtentWith( r );
848 }
849 }
850 else
851 {
853 .setNoAttributes() );
854
855 while ( fit.nextFeature( fet ) )
856 {
857 if ( mSelectedFeatureIds.contains( fet.id() ) )
858 {
859 if ( fet.hasGeometry() )
860 {
861 r = fet.geometry().boundingBox();
862 retval.combineExtentWith( r );
863 }
864 }
865 }
866 }
867
868 if ( retval.width() == 0.0 || retval.height() == 0.0 )
869 {
870 // If all of the features are at the one point, buffer the
871 // rectangle a bit. If they are all at zero, do something a bit
872 // more crude.
873
874 if ( retval.xMinimum() == 0.0 && retval.xMaximum() == 0.0 &&
875 retval.yMinimum() == 0.0 && retval.yMaximum() == 0.0 )
876 {
877 retval.set( -1.0, -1.0, 1.0, 1.0 );
878 }
879 }
880
881 return retval;
882}
883
885{
886 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
888
889 return mLabelsEnabled && static_cast< bool >( mLabeling );
890}
891
893{
895
896 mLabelsEnabled = enabled;
897}
898
900{
901 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
903
904 if ( !mDiagramRenderer || !mDiagramLayerSettings )
905 return false;
906
907 QList<QgsDiagramSettings> settingList = mDiagramRenderer->diagramSettings();
908 if ( !settingList.isEmpty() )
909 {
910 return settingList.at( 0 ).enabled;
911 }
912 return false;
913}
914
915long long QgsVectorLayer::featureCount( const QString &legendKey ) const
916{
918
919 if ( !mSymbolFeatureCounted )
920 return -1;
921
922 return mSymbolFeatureCountMap.value( legendKey, -1 );
923}
924
925QgsFeatureIds QgsVectorLayer::symbolFeatureIds( const QString &legendKey ) const
926{
928
929 if ( !mSymbolFeatureCounted )
930 return QgsFeatureIds();
931
932 return mSymbolFeatureIdMap.value( legendKey, QgsFeatureIds() );
933}
935{
937
938 if ( ( mSymbolFeatureCounted || mFeatureCounter ) && !( storeSymbolFids && mSymbolFeatureIdMap.isEmpty() ) )
939 return mFeatureCounter;
940
941 mSymbolFeatureCountMap.clear();
942 mSymbolFeatureIdMap.clear();
943
944 if ( !isValid() )
945 {
946 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer" ), 3 );
947 return mFeatureCounter;
948 }
949 if ( !mDataProvider )
950 {
951 QgsDebugMsgLevel( QStringLiteral( "invoked with null mDataProvider" ), 3 );
952 return mFeatureCounter;
953 }
954 if ( !mRenderer )
955 {
956 QgsDebugMsgLevel( QStringLiteral( "invoked with null mRenderer" ), 3 );
957 return mFeatureCounter;
958 }
959
960 if ( !mFeatureCounter || ( storeSymbolFids && mSymbolFeatureIdMap.isEmpty() ) )
961 {
962 mFeatureCounter = new QgsVectorLayerFeatureCounter( this, QgsExpressionContext(), storeSymbolFids );
963 connect( mFeatureCounter, &QgsTask::taskCompleted, this, &QgsVectorLayer::onFeatureCounterCompleted, Qt::UniqueConnection );
964 connect( mFeatureCounter, &QgsTask::taskTerminated, this, &QgsVectorLayer::onFeatureCounterTerminated, Qt::UniqueConnection );
965 QgsApplication::taskManager()->addTask( mFeatureCounter );
966 }
967
968 return mFeatureCounter;
969}
970
972{
974
975 // do not update extent by default when trust project option is activated
976 if ( force || !mReadExtentFromXml || ( mReadExtentFromXml && mXmlExtent.isNull() ) )
977 mValidExtent = false;
978}
979
981{
983
985 mValidExtent = true;
986}
987
988void QgsVectorLayer::updateDefaultValues( QgsFeatureId fid, QgsFeature feature )
989{
991
992 if ( !mDefaultValueOnUpdateFields.isEmpty() )
993 {
994 if ( !feature.isValid() )
995 feature = getFeature( fid );
996
997 int size = mFields.size();
998 for ( int idx : std::as_const( mDefaultValueOnUpdateFields ) )
999 {
1000 if ( idx < 0 || idx >= size )
1001 continue;
1002
1003 feature.setAttribute( idx, defaultValue( idx, feature ) );
1004 updateFeature( feature, true );
1005 }
1006 }
1007}
1008
1010{
1012
1013 QgsRectangle rect;
1014 rect.setNull();
1015
1016 if ( !isSpatial() )
1017 return rect;
1018
1019 if ( !mValidExtent && mLazyExtent && mReadExtentFromXml && !mXmlExtent.isNull() )
1020 {
1021 updateExtent( mXmlExtent );
1022 mValidExtent = true;
1023 mLazyExtent = false;
1024 }
1025
1026 if ( !mValidExtent && mLazyExtent && mDataProvider && mDataProvider->isValid() )
1027 {
1028 // store the extent
1029 updateExtent( mDataProvider->extent() );
1030 mValidExtent = true;
1031 mLazyExtent = false;
1032
1033 // show the extent
1034 QgsDebugMsgLevel( QStringLiteral( "Extent of layer: %1" ).arg( mExtent.toString() ), 3 );
1035 }
1036
1037 if ( mValidExtent )
1038 return QgsMapLayer::extent();
1039
1040 if ( !isValid() || !mDataProvider )
1041 {
1042 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
1043 return rect;
1044 }
1045
1046 if ( !mEditBuffer ||
1047 ( !mDataProvider->transaction() && ( mEditBuffer->deletedFeatureIds().isEmpty() && mEditBuffer->changedGeometries().isEmpty() ) ) ||
1049 {
1050 mDataProvider->updateExtents();
1051
1052 // get the extent of the layer from the provider
1053 // but only when there are some features already
1054 if ( mDataProvider->featureCount() != 0 )
1055 {
1056 const QgsRectangle r = mDataProvider->extent();
1057 rect.combineExtentWith( r );
1058 }
1059
1060 if ( mEditBuffer && !mDataProvider->transaction() )
1061 {
1062 const auto addedFeatures = mEditBuffer->addedFeatures();
1063 for ( QgsFeatureMap::const_iterator it = addedFeatures.constBegin(); it != addedFeatures.constEnd(); ++it )
1064 {
1065 if ( it->hasGeometry() )
1066 {
1067 const QgsRectangle r = it->geometry().boundingBox();
1068 rect.combineExtentWith( r );
1069 }
1070 }
1071 }
1072 }
1073 else
1074 {
1076 .setNoAttributes() );
1077
1078 QgsFeature fet;
1079 while ( fit.nextFeature( fet ) )
1080 {
1081 if ( fet.hasGeometry() && fet.geometry().type() != Qgis::GeometryType::Unknown )
1082 {
1083 const QgsRectangle bb = fet.geometry().boundingBox();
1084 rect.combineExtentWith( bb );
1085 }
1086 }
1087 }
1088
1089 if ( rect.xMinimum() > rect.xMaximum() && rect.yMinimum() > rect.yMaximum() )
1090 {
1091 // special case when there are no features in provider nor any added
1092 rect = QgsRectangle(); // use rectangle with zero coordinates
1093 }
1094
1095 updateExtent( rect );
1096 mValidExtent = true;
1097
1098 // Send this (hopefully) up the chain to the map canvas
1099 emit recalculateExtents();
1100
1101 return rect;
1102}
1103
1110
1112{
1114
1115 if ( !isValid() || !mDataProvider )
1116 {
1117 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
1118 return customProperty( QStringLiteral( "storedSubsetString" ) ).toString();
1119 }
1120 return mDataProvider->subsetString();
1121}
1122
1123bool QgsVectorLayer::setSubsetString( const QString &subset )
1124{
1126
1127 if ( !isValid() || !mDataProvider )
1128 {
1129 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider or while editing" ), 3 );
1130 setCustomProperty( QStringLiteral( "storedSubsetString" ), subset );
1131 return false;
1132 }
1133 else if ( mEditBuffer )
1134 {
1135 QgsDebugMsgLevel( QStringLiteral( "invoked while editing" ), 3 );
1136 return false;
1137 }
1138
1139 if ( subset == mDataProvider->subsetString() )
1140 return true;
1141
1142 bool res = mDataProvider->setSubsetString( subset );
1143
1144 // get the updated data source string from the provider
1145 mDataSource = mDataProvider->dataSourceUri();
1146 updateExtents();
1147 updateFields();
1148
1149 if ( res )
1150 {
1151 emit subsetStringChanged();
1153 }
1154
1155 return res;
1156}
1157
1159{
1160 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
1162
1163 if ( isValid() && mDataProvider && !mEditBuffer && ( isSpatial() && geometryType() != Qgis::GeometryType::Point ) && ( mSimplifyMethod.simplifyHints() & simplifyHint ) && renderContext.useRenderingOptimization() )
1164 {
1165 double maximumSimplificationScale = mSimplifyMethod.maximumScale();
1166
1167 // check maximum scale at which generalisation should be carried out
1168 return !( maximumSimplificationScale > 1 && renderContext.rendererScale() <= maximumSimplificationScale );
1169 }
1170 return false;
1171}
1172
1174{
1176
1177 return mConditionalStyles;
1178}
1179
1181{
1182 // non fatal for now -- the aggregate expression functions are not thread safe and call this
1184
1185 if ( !isValid() || !mDataProvider )
1186 return QgsFeatureIterator();
1187
1188 return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( new QgsVectorLayerFeatureSource( this ), true, request ) );
1189}
1190
1192{
1194
1195 QgsFeature feature;
1197 if ( feature.isValid() )
1198 return feature.geometry();
1199 else
1200 return QgsGeometry();
1201}
1202
1204{
1206
1207 if ( !isValid() || !mEditBuffer || !mDataProvider )
1208 return false;
1209
1210
1211 if ( mGeometryOptions->isActive() )
1212 {
1213 QgsGeometry geom = feature.geometry();
1214 mGeometryOptions->apply( geom );
1215 feature.setGeometry( geom );
1216 }
1217
1218 bool success = mEditBuffer->addFeature( feature );
1219
1220 if ( success )
1221 {
1222 updateExtents();
1223
1224 if ( mJoinBuffer->containsJoins() )
1225 success = mJoinBuffer->addFeature( feature );
1226 }
1227
1228 return success;
1229}
1230
1231bool QgsVectorLayer::updateFeature( QgsFeature &updatedFeature, bool skipDefaultValues )
1232{
1234
1235 if ( !mEditBuffer || !mDataProvider )
1236 {
1237 return false;
1238 }
1239
1240 QgsFeature currentFeature = getFeature( updatedFeature.id() );
1241 if ( currentFeature.isValid() )
1242 {
1243 bool hasChanged = false;
1244 bool hasError = false;
1245
1246 if ( ( updatedFeature.hasGeometry() || currentFeature.hasGeometry() ) && !updatedFeature.geometry().equals( currentFeature.geometry() ) )
1247 {
1248 QgsGeometry geometry = updatedFeature.geometry();
1249 if ( changeGeometry( updatedFeature.id(), geometry, true ) )
1250 {
1251 hasChanged = true;
1252 updatedFeature.setGeometry( geometry );
1253 }
1254 else
1255 {
1256 QgsDebugMsgLevel( QStringLiteral( "geometry of feature %1 could not be changed." ).arg( updatedFeature.id() ), 3 );
1257 }
1258 }
1259
1260 QgsAttributes fa = updatedFeature.attributes();
1261 QgsAttributes ca = currentFeature.attributes();
1262
1263 for ( int attr = 0; attr < fa.count(); ++attr )
1264 {
1265 if ( !qgsVariantEqual( fa.at( attr ), ca.at( attr ) ) )
1266 {
1267 if ( changeAttributeValue( updatedFeature.id(), attr, fa.at( attr ), ca.at( attr ), true ) )
1268 {
1269 hasChanged = true;
1270 }
1271 else
1272 {
1273 QgsDebugMsgLevel( QStringLiteral( "attribute %1 of feature %2 could not be changed." ).arg( attr ).arg( updatedFeature.id() ), 3 );
1274 hasError = true;
1275 }
1276 }
1277 }
1278 if ( hasChanged && !mDefaultValueOnUpdateFields.isEmpty() && !skipDefaultValues )
1279 updateDefaultValues( updatedFeature.id(), updatedFeature );
1280
1281 return !hasError;
1282 }
1283 else
1284 {
1285 QgsDebugMsgLevel( QStringLiteral( "feature %1 could not be retrieved" ).arg( updatedFeature.id() ), 3 );
1286 return false;
1287 }
1288}
1289
1290
1291bool QgsVectorLayer::insertVertex( double x, double y, QgsFeatureId atFeatureId, int beforeVertex )
1292{
1294
1295 if ( !isValid() || !mEditBuffer || !mDataProvider )
1296 return false;
1297
1298 QgsVectorLayerEditUtils utils( this );
1299 bool result = utils.insertVertex( x, y, atFeatureId, beforeVertex );
1300 if ( result )
1301 updateExtents();
1302 return result;
1303}
1304
1305
1306bool QgsVectorLayer::insertVertex( const QgsPoint &point, QgsFeatureId atFeatureId, int beforeVertex )
1307{
1309
1310 if ( !isValid() || !mEditBuffer || !mDataProvider )
1311 return false;
1312
1313 QgsVectorLayerEditUtils utils( this );
1314 bool result = utils.insertVertex( point, atFeatureId, beforeVertex );
1315 if ( result )
1316 updateExtents();
1317 return result;
1318}
1319
1320
1321bool QgsVectorLayer::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
1322{
1324
1325 if ( !isValid() || !mEditBuffer || !mDataProvider )
1326 return false;
1327
1328 QgsVectorLayerEditUtils utils( this );
1329 bool result = utils.moveVertex( x, y, atFeatureId, atVertex );
1330
1331 if ( result )
1332 updateExtents();
1333 return result;
1334}
1335
1336bool QgsVectorLayer::moveVertex( const QgsPoint &p, QgsFeatureId atFeatureId, int atVertex )
1337{
1339
1340 if ( !isValid() || !mEditBuffer || !mDataProvider )
1341 return false;
1342
1343 QgsVectorLayerEditUtils utils( this );
1344 bool result = utils.moveVertex( p, atFeatureId, atVertex );
1345
1346 if ( result )
1347 updateExtents();
1348 return result;
1349}
1350
1352{
1354
1355 if ( !isValid() || !mEditBuffer || !mDataProvider )
1357
1358 QgsVectorLayerEditUtils utils( this );
1359 Qgis::VectorEditResult result = utils.deleteVertex( featureId, vertex );
1360
1361 if ( result == Qgis::VectorEditResult::Success )
1362 updateExtents();
1363 return result;
1364}
1365
1366
1368{
1370
1371 if ( !isValid() || !mDataProvider || !( mDataProvider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) )
1372 {
1373 return false;
1374 }
1375
1376 if ( !isEditable() )
1377 {
1378 return false;
1379 }
1380
1381 int deleted = 0;
1382 int count = mSelectedFeatureIds.size();
1383 // Make a copy since deleteFeature modifies mSelectedFeatureIds
1384 QgsFeatureIds selectedFeatures( mSelectedFeatureIds );
1385 for ( QgsFeatureId fid : std::as_const( selectedFeatures ) )
1386 {
1387 deleted += deleteFeature( fid, context ); // removes from selection
1388 }
1389
1391 updateExtents();
1392
1393 if ( deletedCount )
1394 {
1395 *deletedCount = deleted;
1396 }
1397
1398 return deleted == count;
1399}
1400
1401static const QgsPointSequence vectorPointXY2pointSequence( const QVector<QgsPointXY> &points )
1402{
1403 QgsPointSequence pts;
1404 pts.reserve( points.size() );
1405 QVector<QgsPointXY>::const_iterator it = points.constBegin();
1406 while ( it != points.constEnd() )
1407 {
1408 pts.append( QgsPoint( *it ) );
1409 ++it;
1410 }
1411 return pts;
1412}
1413Qgis::GeometryOperationResult QgsVectorLayer::addRing( const QVector<QgsPointXY> &ring, QgsFeatureId *featureId )
1414{
1416
1417 return addRing( vectorPointXY2pointSequence( ring ), featureId );
1418}
1419
1421{
1423
1424 if ( !isValid() || !mEditBuffer || !mDataProvider )
1426
1427 QgsVectorLayerEditUtils utils( this );
1429
1430 //first try with selected features
1431 if ( !mSelectedFeatureIds.isEmpty() )
1432 {
1433 result = utils.addRing( ring, mSelectedFeatureIds, featureId );
1434 }
1435
1437 {
1438 //try with all intersecting features
1439 result = utils.addRing( ring, QgsFeatureIds(), featureId );
1440 }
1441
1442 return result;
1443}
1444
1446{
1448
1449 if ( !isValid() || !mEditBuffer || !mDataProvider )
1450 {
1451 delete ring;
1453 }
1454
1455 if ( !ring )
1456 {
1458 }
1459
1460 if ( !ring->isClosed() )
1461 {
1462 delete ring;
1464 }
1465
1466 QgsVectorLayerEditUtils utils( this );
1468
1469 //first try with selected features
1470 if ( !mSelectedFeatureIds.isEmpty() )
1471 {
1472 result = utils.addRing( static_cast< QgsCurve * >( ring->clone() ), mSelectedFeatureIds, featureId );
1473 }
1474
1476 {
1477 //try with all intersecting features
1478 result = utils.addRing( static_cast< QgsCurve * >( ring->clone() ), QgsFeatureIds(), featureId );
1479 }
1480
1481 delete ring;
1482 return result;
1483}
1484
1486{
1488
1489 QgsPointSequence pts;
1490 pts.reserve( points.size() );
1491 for ( QList<QgsPointXY>::const_iterator it = points.constBegin(); it != points.constEnd() ; ++it )
1492 {
1493 pts.append( QgsPoint( *it ) );
1494 }
1495 return addPart( pts );
1496}
1497
1498#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1499Qgis::GeometryOperationResult QgsVectorLayer::addPart( const QVector<QgsPointXY> &points )
1500{
1502
1503 return addPart( vectorPointXY2pointSequence( points ) );
1504}
1505#endif
1506
1508{
1510
1511 if ( !isValid() || !mEditBuffer || !mDataProvider )
1513
1514 //number of selected features must be 1
1515
1516 if ( mSelectedFeatureIds.empty() )
1517 {
1518 QgsDebugMsgLevel( QStringLiteral( "Number of selected features <1" ), 3 );
1520 }
1521 else if ( mSelectedFeatureIds.size() > 1 )
1522 {
1523 QgsDebugMsgLevel( QStringLiteral( "Number of selected features >1" ), 3 );
1525 }
1526
1527 QgsVectorLayerEditUtils utils( this );
1528 Qgis::GeometryOperationResult result = utils.addPart( points, *mSelectedFeatureIds.constBegin() );
1529
1531 updateExtents();
1532 return result;
1533}
1534
1536{
1538
1539 if ( !isValid() || !mEditBuffer || !mDataProvider )
1541
1542 //number of selected features must be 1
1543
1544 if ( mSelectedFeatureIds.empty() )
1545 {
1546 QgsDebugMsgLevel( QStringLiteral( "Number of selected features <1" ), 3 );
1548 }
1549 else if ( mSelectedFeatureIds.size() > 1 )
1550 {
1551 QgsDebugMsgLevel( QStringLiteral( "Number of selected features >1" ), 3 );
1553 }
1554
1555 QgsVectorLayerEditUtils utils( this );
1556 Qgis::GeometryOperationResult result = utils.addPart( ring, *mSelectedFeatureIds.constBegin() );
1557
1559 updateExtents();
1560 return result;
1561}
1562
1563// TODO QGIS 4.0 -- this should return Qgis::GeometryOperationResult, not int
1564int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double dy )
1565{
1567
1568 if ( !isValid() || !mEditBuffer || !mDataProvider )
1569 return static_cast< int >( Qgis::GeometryOperationResult::LayerNotEditable );
1570
1571 QgsVectorLayerEditUtils utils( this );
1572 int result = utils.translateFeature( featureId, dx, dy );
1573
1574 if ( result == static_cast< int >( Qgis::GeometryOperationResult::Success ) )
1575 updateExtents();
1576 return result;
1577}
1578
1579Qgis::GeometryOperationResult QgsVectorLayer::splitParts( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
1580{
1582
1583 return splitParts( vectorPointXY2pointSequence( splitLine ), topologicalEditing );
1584}
1585
1587{
1589
1590 if ( !isValid() || !mEditBuffer || !mDataProvider )
1592
1593 QgsVectorLayerEditUtils utils( this );
1594 return utils.splitParts( splitLine, topologicalEditing );
1595}
1596
1597Qgis::GeometryOperationResult QgsVectorLayer::splitFeatures( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
1598{
1600
1601 return splitFeatures( vectorPointXY2pointSequence( splitLine ), topologicalEditing );
1602}
1603
1605{
1607
1608 QgsLineString splitLineString( splitLine );
1609 QgsPointSequence topologyTestPoints;
1610 bool preserveCircular = false;
1611 return splitFeatures( &splitLineString, topologyTestPoints, preserveCircular, topologicalEditing );
1612}
1613
1614Qgis::GeometryOperationResult QgsVectorLayer::splitFeatures( const QgsCurve *curve, QgsPointSequence &topologyTestPoints, bool preserveCircular, bool topologicalEditing )
1615{
1617
1618 if ( !isValid() || !mEditBuffer || !mDataProvider )
1620
1621 QgsVectorLayerEditUtils utils( this );
1622 return utils.splitFeatures( curve, topologyTestPoints, preserveCircular, topologicalEditing );
1623}
1624
1626{
1628
1629 if ( !isValid() || !mEditBuffer || !mDataProvider )
1630 return -1;
1631
1632 QgsVectorLayerEditUtils utils( this );
1633 return utils.addTopologicalPoints( geom );
1634}
1635
1642
1644{
1646
1647 if ( !isValid() || !mEditBuffer || !mDataProvider )
1648 return -1;
1649
1650 QgsVectorLayerEditUtils utils( this );
1651 return utils.addTopologicalPoints( p );
1652}
1653
1655{
1657
1658 if ( !mValid || !mEditBuffer || !mDataProvider )
1659 return -1;
1660
1661 QgsVectorLayerEditUtils utils( this );
1662 return utils.addTopologicalPoints( ps );
1663}
1664
1666{
1668
1669 if ( mLabeling == labeling )
1670 return;
1671
1672 delete mLabeling;
1673 mLabeling = labeling;
1674}
1675
1677{
1679
1680 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
1681 return project()->startEditing( this );
1682
1683 if ( !isValid() || !mDataProvider )
1684 {
1685 return false;
1686 }
1687
1688 // allow editing if provider supports any of the capabilities
1689 if ( !supportsEditing() )
1690 {
1691 return false;
1692 }
1693
1694 if ( mEditBuffer )
1695 {
1696 // editing already underway
1697 return false;
1698 }
1699
1700 mDataProvider->enterUpdateMode();
1701
1702 emit beforeEditingStarted();
1703
1704 createEditBuffer();
1705
1706 updateFields();
1707
1708 emit editingStarted();
1709
1710 return true;
1711}
1712
1714{
1716
1717 if ( mDataProvider )
1718 mDataProvider->setTransformContext( transformContext );
1719}
1720
1727
1729{
1731
1732 if ( mRenderer )
1733 if ( !mRenderer->accept( visitor ) )
1734 return false;
1735
1736 if ( mLabeling )
1737 if ( !mLabeling->accept( visitor ) )
1738 return false;
1739
1740 return true;
1741}
1742
1743bool QgsVectorLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1744{
1746
1747 QgsDebugMsgLevel( QStringLiteral( "Datasource in QgsVectorLayer::readXml: %1" ).arg( mDataSource.toLocal8Bit().data() ), 3 );
1748
1749 //process provider key
1750 QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
1751
1752 if ( pkeyNode.isNull() )
1753 {
1754 mProviderKey.clear();
1755 }
1756 else
1757 {
1758 QDomElement pkeyElt = pkeyNode.toElement();
1759 mProviderKey = pkeyElt.text();
1760 }
1761
1762 // determine type of vector layer
1763 if ( !mProviderKey.isNull() )
1764 {
1765 // if the provider string isn't empty, then we successfully
1766 // got the stored provider
1767 }
1768 else if ( mDataSource.contains( QLatin1String( "dbname=" ) ) )
1769 {
1770 mProviderKey = QStringLiteral( "postgres" );
1771 }
1772 else
1773 {
1774 mProviderKey = QStringLiteral( "ogr" );
1775 }
1776
1777 const QDomElement elem = layer_node.toElement();
1779
1780 mDataSourceReadOnly = mReadFlags & QgsMapLayer::FlagForceReadOnly;
1781 QgsDataProvider::ReadFlags flags = providerReadFlags( layer_node, mReadFlags );
1782
1783 if ( ( mReadFlags & QgsMapLayer::FlagDontResolveLayers ) || !setDataProvider( mProviderKey, options, flags ) )
1784 {
1786 {
1787 QgsDebugError( QStringLiteral( "Could not set data provider for layer %1" ).arg( publicSource() ) );
1788 }
1789
1790 // for invalid layer sources, we fallback to stored wkbType if available
1791 if ( elem.hasAttribute( QStringLiteral( "wkbType" ) ) )
1792 mWkbType = qgsEnumKeyToValue( elem.attribute( QStringLiteral( "wkbType" ) ), mWkbType );
1793 }
1794
1795 QDomElement pkeyElem = pkeyNode.toElement();
1796 if ( !pkeyElem.isNull() )
1797 {
1798 QString encodingString = pkeyElem.attribute( QStringLiteral( "encoding" ) );
1799 if ( mDataProvider && !encodingString.isEmpty() )
1800 {
1801 mDataProvider->setEncoding( encodingString );
1802 }
1803 }
1804
1805 // load vector joins - does not resolve references to layers yet
1806 mJoinBuffer->readXml( layer_node );
1807
1808 updateFields();
1809
1810 // If style doesn't include a legend, we'll need to make a default one later...
1811 mSetLegendFromStyle = false;
1812
1813 QString errorMsg;
1814 if ( !readSymbology( layer_node, errorMsg, context ) )
1815 {
1816 return false;
1817 }
1818
1819 readStyleManager( layer_node );
1820
1821 QDomNode depsNode = layer_node.namedItem( QStringLiteral( "dataDependencies" ) );
1822 QDomNodeList depsNodes = depsNode.childNodes();
1823 QSet<QgsMapLayerDependency> sources;
1824 for ( int i = 0; i < depsNodes.count(); i++ )
1825 {
1826 QString source = depsNodes.at( i ).toElement().attribute( QStringLiteral( "id" ) );
1827 sources << QgsMapLayerDependency( source );
1828 }
1829 setDependencies( sources );
1830
1831 if ( !mSetLegendFromStyle )
1833
1834 // read extent
1836 {
1837 mReadExtentFromXml = true;
1838 }
1839 if ( mReadExtentFromXml )
1840 {
1841 const QDomNode extentNode = layer_node.namedItem( QStringLiteral( "extent" ) );
1842 if ( !extentNode.isNull() )
1843 {
1844 mXmlExtent = QgsXmlUtils::readRectangle( extentNode.toElement() );
1845 }
1846 }
1847
1848 // auxiliary layer
1849 const QDomNode asNode = layer_node.namedItem( QStringLiteral( "auxiliaryLayer" ) );
1850 const QDomElement asElem = asNode.toElement();
1851 if ( !asElem.isNull() )
1852 {
1853 mAuxiliaryLayerKey = asElem.attribute( QStringLiteral( "key" ) );
1854 }
1855
1856 // QGIS Server WMS Dimensions
1857 mServerProperties->readXml( layer_node );
1858
1859 return isValid(); // should be true if read successfully
1860
1861} // void QgsVectorLayer::readXml
1862
1863
1864void QgsVectorLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider,
1865 const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1866{
1868
1869 Qgis::GeometryType geomType = geometryType();
1870
1871 mDataSource = dataSource;
1872 setName( baseName );
1873 setDataProvider( provider, options, flags );
1874
1875 if ( !isValid() )
1876 {
1877 return;
1878 }
1879
1880 // Always set crs
1882
1883 bool loadDefaultStyleFlag = false;
1885 {
1886 loadDefaultStyleFlag = true;
1887 }
1888
1889 // reset style if loading default style, style is missing, or geometry type is has changed (and layer is valid)
1890 if ( !renderer() || !legend() || ( isValid() && geomType != geometryType() ) || loadDefaultStyleFlag )
1891 {
1892 std::unique_ptr< QgsScopedRuntimeProfile > profile;
1893 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
1894 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Load layer style" ), QStringLiteral( "projectload" ) );
1895
1896 bool defaultLoadedFlag = false;
1897
1898 // defer style changed signal until we've set the renderer, labeling, everything.
1899 // we don't want multiple signals!
1900 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
1901
1902 // need to check whether the default style included a legend, and if not, we need to make a default legend
1903 // later...
1904 mSetLegendFromStyle = false;
1905
1906 // first check if there is a default style / propertysheet defined
1907 // for this layer and if so apply it
1908 // this should take precedence over all
1909 if ( !defaultLoadedFlag && loadDefaultStyleFlag )
1910 {
1911 loadDefaultStyle( defaultLoadedFlag );
1912 }
1913
1914 if ( loadDefaultStyleFlag && !defaultLoadedFlag && isSpatial() && mDataProvider->capabilities() & QgsVectorDataProvider::CreateRenderer )
1915 {
1916 // if we didn't load a default style for this layer, try to create a renderer directly from the data provider
1917 std::unique_ptr< QgsFeatureRenderer > defaultRenderer( mDataProvider->createRenderer() );
1918 if ( defaultRenderer )
1919 {
1920 defaultLoadedFlag = true;
1921 setRenderer( defaultRenderer.release() );
1922 }
1923 }
1924
1925 // if the default style failed to load or was disabled use some very basic defaults
1926 if ( !defaultLoadedFlag && isSpatial() )
1927 {
1928 // add single symbol renderer
1930 }
1931
1932 if ( !mSetLegendFromStyle )
1934
1935 if ( mDataProvider->capabilities() & QgsVectorDataProvider::CreateLabeling )
1936 {
1937 std::unique_ptr< QgsAbstractVectorLayerLabeling > defaultLabeling( mDataProvider->createLabeling() );
1938 if ( defaultLabeling )
1939 {
1940 setLabeling( defaultLabeling.release() );
1941 setLabelsEnabled( true );
1942 }
1943 }
1944
1945 styleChangedSignalBlocker.release();
1947 }
1948}
1949
1950QString QgsVectorLayer::loadDefaultStyle( bool &resultFlag )
1951{
1953
1954 // first try to load a user-defined default style - this should always take precedence
1955 QString styleXml = QgsMapLayer::loadDefaultStyle( resultFlag );
1956
1957 if ( resultFlag )
1958 {
1959 // Try to load all stored styles from DB
1960 if ( mLoadAllStoredStyle && mDataProvider && mDataProvider->styleStorageCapabilities().testFlag( Qgis::ProviderStyleStorageCapability::LoadFromDatabase ) )
1961 {
1962 QStringList ids, names, descriptions;
1963 QString errorMessage;
1964 // Get the number of styles related to current layer.
1965 const int relatedStylesCount { listStylesInDatabase( ids, names, descriptions, errorMessage ) };
1966 Q_ASSERT( ids.count() == names.count() );
1967 const QString currentStyleName { mStyleManager->currentStyle() };
1968 for ( int i = 0; i < relatedStylesCount; ++i )
1969 {
1970 if ( names.at( i ) == currentStyleName )
1971 {
1972 continue;
1973 }
1974 errorMessage.clear();
1975 const QString styleXml { getStyleFromDatabase( ids.at( i ), errorMessage ) };
1976 if ( ! styleXml.isEmpty() && errorMessage.isEmpty() )
1977 {
1978 mStyleManager->addStyle( names.at( i ), QgsMapLayerStyle( styleXml ) );
1979 }
1980 else
1981 {
1982 QgsDebugMsgLevel( QStringLiteral( "Error retrieving style %1 from DB: %2" ).arg( ids.at( i ), errorMessage ), 2 );
1983 }
1984 }
1985 }
1986 return styleXml ;
1987 }
1988
1989 if ( isSpatial() && mDataProvider->capabilities() & QgsVectorDataProvider::CreateRenderer )
1990 {
1991 // otherwise try to create a renderer directly from the data provider
1992 std::unique_ptr< QgsFeatureRenderer > defaultRenderer( mDataProvider->createRenderer() );
1993 if ( defaultRenderer )
1994 {
1995 resultFlag = true;
1996 setRenderer( defaultRenderer.release() );
1997 return QString();
1998 }
1999 }
2000
2001 return QString();
2002}
2003
2004bool QgsVectorLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
2005{
2007
2008 mProviderKey = provider;
2009 delete mDataProvider;
2010
2011 // For Postgres provider primary key unicity is tested at construction time,
2012 // so it has to be set before initializing the provider,
2013 // this manipulation is necessary to preserve default behavior when
2014 // "trust layer metadata" project level option is set and checkPrimaryKeyUnicity
2015 // was not explicitly passed in the uri
2016 if ( provider.compare( QLatin1String( "postgres" ) ) == 0 )
2017 {
2018 const QString checkUnicityKey { QStringLiteral( "checkPrimaryKeyUnicity" ) };
2020 if ( ! uri.hasParam( checkUnicityKey ) )
2021 {
2022 uri.setParam( checkUnicityKey, mReadExtentFromXml ? "0" : "1" );
2023 mDataSource = uri.uri( false );
2024 }
2025 }
2026
2027 std::unique_ptr< QgsScopedRuntimeProfile > profile;
2028 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
2029 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), QStringLiteral( "projectload" ) );
2030
2031 if ( mPreloadedProvider )
2032 mDataProvider = qobject_cast< QgsVectorDataProvider * >( mPreloadedProvider.release() );
2033 else
2034 mDataProvider = qobject_cast<QgsVectorDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, mDataSource, options, flags ) );
2035
2036 if ( !mDataProvider )
2037 {
2038 setValid( false );
2039 QgsDebugMsgLevel( QStringLiteral( "Unable to get data provider" ), 2 );
2040 return false;
2041 }
2042
2043 mDataProvider->setParent( this );
2044 connect( mDataProvider, &QgsVectorDataProvider::raiseError, this, &QgsVectorLayer::raiseError );
2045
2046 QgsDebugMsgLevel( QStringLiteral( "Instantiated the data provider plugin" ), 2 );
2047
2048 setValid( mDataProvider->isValid() );
2049 if ( !isValid() )
2050 {
2051 QgsDebugMsgLevel( QStringLiteral( "Invalid provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
2052 return false;
2053 }
2054
2055 if ( profile )
2056 profile->switchTask( tr( "Read layer metadata" ) );
2058 {
2059 // we combine the provider metadata with the layer's existing metadata, so as not to reset any user customizations to the metadata
2060 // back to the default if a layer's data source is changed
2061 QgsLayerMetadata newMetadata = mDataProvider->layerMetadata();
2062 // this overwrites the provider metadata with any properties which are non-empty from the existing layer metadata
2063 newMetadata.combine( &mMetadata );
2064
2065 setMetadata( newMetadata );
2066 QgsDebugMsgLevel( QStringLiteral( "Set Data provider QgsLayerMetadata identifier[%1]" ).arg( metadata().identifier() ), 4 );
2067 }
2068
2069 // TODO: Check if the provider has the capability to send fullExtentCalculated
2070 connect( mDataProvider, &QgsVectorDataProvider::fullExtentCalculated, this, [ = ] { updateExtents(); } );
2071
2072 // get and store the feature type
2073 mWkbType = mDataProvider->wkbType();
2074
2075 // before we update the layer fields from the provider, we first copy any default set alias and
2076 // editor widget config from the data provider fields, if present
2077 const QgsFields providerFields = mDataProvider->fields();
2078 for ( const QgsField &field : providerFields )
2079 {
2080 // we only copy defaults from the provider if we aren't overriding any configuration made in the layer
2081 if ( !field.editorWidgetSetup().isNull() && mFieldWidgetSetups.value( field.name() ).isNull() )
2082 {
2083 mFieldWidgetSetups[ field.name() ] = field.editorWidgetSetup();
2084 }
2085 if ( !field.alias().isEmpty() && mAttributeAliasMap.value( field.name() ).isEmpty() )
2086 {
2087 mAttributeAliasMap[ field.name() ] = field.alias();
2088 }
2089 if ( !mAttributeSplitPolicy.contains( field.name() ) )
2090 {
2091 mAttributeSplitPolicy[ field.name() ] = field.splitPolicy();
2092 }
2093 }
2094
2095 if ( profile )
2096 profile->switchTask( tr( "Read layer fields" ) );
2097 updateFields();
2098
2099 if ( mProviderKey == QLatin1String( "postgres" ) )
2100 {
2101 // update datasource from data provider computed one
2102 mDataSource = mDataProvider->dataSourceUri( false );
2103
2104 QgsDebugMsgLevel( QStringLiteral( "Beautifying layer name %1" ).arg( name() ), 3 );
2105
2106 // adjust the display name for postgres layers
2107 const thread_local QRegularExpression reg( R"lit("[^"]+"\."([^"] + )"( \‍([^)]+\))?)lit" );
2108 const QRegularExpressionMatch match = reg.match( name() );
2109 if ( match.hasMatch() )
2110 {
2111 QStringList stuff = match.capturedTexts();
2112 QString lName = stuff[1];
2113
2114 const QMap<QString, QgsMapLayer *> &layers = QgsProject::instance()->mapLayers();
2115
2116 QMap<QString, QgsMapLayer *>::const_iterator it;
2117 for ( it = layers.constBegin(); it != layers.constEnd() && ( *it )->name() != lName; ++it )
2118 ;
2119
2120 if ( it != layers.constEnd() && stuff.size() > 2 )
2121 {
2122 lName += '.' + stuff[2].mid( 2, stuff[2].length() - 3 );
2123 }
2124
2125 if ( !lName.isEmpty() )
2126 setName( lName );
2127 }
2128 QgsDebugMsgLevel( QStringLiteral( "Beautified layer name %1" ).arg( name() ), 3 );
2129 }
2130 else if ( mProviderKey == QLatin1String( "osm" ) )
2131 {
2132 // make sure that the "observer" has been removed from URI to avoid crashes
2133 mDataSource = mDataProvider->dataSourceUri();
2134 }
2135 else if ( provider == QLatin1String( "ogr" ) )
2136 {
2137 // make sure that the /vsigzip or /vsizip is added to uri, if applicable
2138 mDataSource = mDataProvider->dataSourceUri();
2139 if ( mDataSource.right( 10 ) == QLatin1String( "|layerid=0" ) )
2140 mDataSource.chop( 10 );
2141 }
2142 else if ( provider == QLatin1String( "memory" ) )
2143 {
2144 // required so that source differs between memory layers
2145 mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
2146 }
2147 else if ( provider == QLatin1String( "hana" ) )
2148 {
2149 // update datasource from data provider computed one
2150 mDataSource = mDataProvider->dataSourceUri( false );
2151 }
2152
2153 connect( mDataProvider, &QgsVectorDataProvider::dataChanged, this, &QgsVectorLayer::emitDataChanged );
2155
2156 return true;
2157} // QgsVectorLayer:: setDataProvider
2158
2159
2160
2161
2162/* virtual */
2163bool QgsVectorLayer::writeXml( QDomNode &layer_node,
2164 QDomDocument &document,
2165 const QgsReadWriteContext &context ) const
2166{
2168
2169 // first get the layer element so that we can append the type attribute
2170
2171 QDomElement mapLayerNode = layer_node.toElement();
2172
2173 if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) )
2174 {
2175 QgsDebugMsgLevel( QStringLiteral( "can't find <maplayer>" ), 2 );
2176 return false;
2177 }
2178
2179 mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( Qgis::LayerType::Vector ) );
2180
2181 // set the geometry type
2182 mapLayerNode.setAttribute( QStringLiteral( "geometry" ), QgsWkbTypes::geometryDisplayString( geometryType() ) );
2183 mapLayerNode.setAttribute( QStringLiteral( "wkbType" ), qgsEnumValueToKey( wkbType() ) );
2184
2185 // add provider node
2186 if ( mDataProvider )
2187 {
2188 QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
2189 provider.setAttribute( QStringLiteral( "encoding" ), mDataProvider->encoding() );
2190 QDomText providerText = document.createTextNode( providerType() );
2191 provider.appendChild( providerText );
2192 layer_node.appendChild( provider );
2193 }
2194
2195 //save joins
2196 mJoinBuffer->writeXml( layer_node, document );
2197
2198 // dependencies
2199 QDomElement dependenciesElement = document.createElement( QStringLiteral( "layerDependencies" ) );
2200 const auto constDependencies = dependencies();
2201 for ( const QgsMapLayerDependency &dep : constDependencies )
2202 {
2204 continue;
2205 QDomElement depElem = document.createElement( QStringLiteral( "layer" ) );
2206 depElem.setAttribute( QStringLiteral( "id" ), dep.layerId() );
2207 dependenciesElement.appendChild( depElem );
2208 }
2209 layer_node.appendChild( dependenciesElement );
2210
2211 // change dependencies
2212 QDomElement dataDependenciesElement = document.createElement( QStringLiteral( "dataDependencies" ) );
2213 for ( const QgsMapLayerDependency &dep : constDependencies )
2214 {
2215 if ( dep.type() != QgsMapLayerDependency::DataDependency )
2216 continue;
2217 QDomElement depElem = document.createElement( QStringLiteral( "layer" ) );
2218 depElem.setAttribute( QStringLiteral( "id" ), dep.layerId() );
2219 dataDependenciesElement.appendChild( depElem );
2220 }
2221 layer_node.appendChild( dataDependenciesElement );
2222
2223 // save expression fields
2224 mExpressionFieldBuffer->writeXml( layer_node, document );
2225
2226 writeStyleManager( layer_node, document );
2227
2228 // auxiliary layer
2229 QDomElement asElem = document.createElement( QStringLiteral( "auxiliaryLayer" ) );
2230 if ( mAuxiliaryLayer )
2231 {
2232 const QString pkField = mAuxiliaryLayer->joinInfo().targetFieldName();
2233 asElem.setAttribute( QStringLiteral( "key" ), pkField );
2234 }
2235 layer_node.appendChild( asElem );
2236
2237 // save QGIS Server properties (WMS Dimension, metadata URLS...)
2238 mServerProperties->writeXml( layer_node, document );
2239
2240 // renderer specific settings
2241 QString errorMsg;
2242 return writeSymbology( layer_node, document, errorMsg, context );
2243}
2244
2245QString QgsVectorLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
2246{
2248
2249 if ( providerType() == QLatin1String( "memory" ) )
2250 {
2251 // Refetch the source from the provider, because adding fields actually changes the source for this provider.
2252 return dataProvider()->dataSourceUri();
2253 }
2254
2256}
2257
2258QString QgsVectorLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
2259{
2261
2262 return QgsProviderRegistry::instance()->relativeToAbsoluteUri( provider, source, context );
2263}
2264
2265
2266
2274
2275
2276bool QgsVectorLayer::readSymbology( const QDomNode &layerNode, QString &errorMessage,
2277 QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
2278{
2280
2281 if ( categories.testFlag( Fields ) )
2282 {
2283 if ( !mExpressionFieldBuffer )
2284 mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
2285 mExpressionFieldBuffer->readXml( layerNode );
2286
2287 updateFields();
2288 }
2289
2290 if ( categories.testFlag( Relations ) )
2291 {
2292 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Relations" ) );
2293
2294 const QgsPathResolver resolver { QgsProject::instance()->pathResolver() };
2295
2296 // Restore referenced layers: relations where "this" is the child layer (the referencing part, that holds the FK)
2297 QDomNodeList referencedLayersNodeList = layerNode.toElement().elementsByTagName( QStringLiteral( "referencedLayers" ) );
2298 if ( referencedLayersNodeList.size() > 0 )
2299 {
2300 const QDomNodeList relationNodes { referencedLayersNodeList.at( 0 ).childNodes() };
2301 for ( int i = 0; i < relationNodes.length(); ++i )
2302 {
2303 const QDomElement relationElement = relationNodes.at( i ).toElement();
2304
2305 mWeakRelations.push_back( QgsWeakRelation::readXml( this, QgsWeakRelation::Referencing, relationElement, resolver ) );
2306 }
2307 }
2308
2309 // Restore referencing layers: relations where "this" is the parent layer (the referenced part where the FK points to)
2310 QDomNodeList referencingLayersNodeList = layerNode.toElement().elementsByTagName( QStringLiteral( "referencingLayers" ) );
2311 if ( referencingLayersNodeList.size() > 0 )
2312 {
2313 const QDomNodeList relationNodes { referencingLayersNodeList.at( 0 ).childNodes() };
2314 for ( int i = 0; i < relationNodes.length(); ++i )
2315 {
2316 const QDomElement relationElement = relationNodes.at( i ).toElement();
2317 mWeakRelations.push_back( QgsWeakRelation::readXml( this, QgsWeakRelation::Referenced, relationElement, resolver ) );
2318 }
2319 }
2320 }
2321
2322 QDomElement layerElement = layerNode.toElement();
2323
2324 readCommonStyle( layerElement, context, categories );
2325
2326 readStyle( layerNode, errorMessage, context, categories );
2327
2328 if ( categories.testFlag( MapTips ) )
2329 {
2330 QDomElement mapTipElem = layerNode.namedItem( QStringLiteral( "mapTip" ) ).toElement();
2331 setMapTipTemplate( mapTipElem.text() );
2332 setMapTipsEnabled( mapTipElem.attribute( QStringLiteral( "enabled" ), QStringLiteral( "1" ) ).toInt() == 1 );
2333 }
2334
2335 if ( categories.testFlag( LayerConfiguration ) )
2336 mDisplayExpression = layerNode.namedItem( QStringLiteral( "previewExpression" ) ).toElement().text();
2337
2338 // Try to migrate pre QGIS 3.0 display field property
2339 QString displayField = layerNode.namedItem( QStringLiteral( "displayfield" ) ).toElement().text();
2340 if ( mFields.lookupField( displayField ) < 0 )
2341 {
2342 // if it's not a field, it's a maptip
2343 if ( mMapTipTemplate.isEmpty() && categories.testFlag( MapTips ) )
2344 mMapTipTemplate = displayField;
2345 }
2346 else
2347 {
2348 if ( mDisplayExpression.isEmpty() && categories.testFlag( LayerConfiguration ) )
2349 mDisplayExpression = QgsExpression::quotedColumnRef( displayField );
2350 }
2351
2352 // process the attribute actions
2353 if ( categories.testFlag( Actions ) )
2354 mActions->readXml( layerNode );
2355
2356 if ( categories.testFlag( Fields ) )
2357 {
2358 // IMPORTANT - we don't clear mAttributeAliasMap here, as it may contain aliases which are coming direct
2359 // from the data provider. Instead we leave any existing aliases and only overwrite them if the style
2360 // has a specific value for that field's alias
2361 QDomNode aliasesNode = layerNode.namedItem( QStringLiteral( "aliases" ) );
2362 if ( !aliasesNode.isNull() )
2363 {
2364 QDomElement aliasElem;
2365
2366 QDomNodeList aliasNodeList = aliasesNode.toElement().elementsByTagName( QStringLiteral( "alias" ) );
2367 for ( int i = 0; i < aliasNodeList.size(); ++i )
2368 {
2369 aliasElem = aliasNodeList.at( i ).toElement();
2370
2371 QString field;
2372 if ( aliasElem.hasAttribute( QStringLiteral( "field" ) ) )
2373 {
2374 field = aliasElem.attribute( QStringLiteral( "field" ) );
2375 }
2376 else
2377 {
2378 int index = aliasElem.attribute( QStringLiteral( "index" ) ).toInt();
2379
2380 if ( index >= 0 && index < fields().count() )
2381 field = fields().at( index ).name();
2382 }
2383
2384 QString alias;
2385
2386 if ( !aliasElem.attribute( QStringLiteral( "name" ) ).isEmpty() )
2387 {
2388 //if it has alias
2389 alias = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ), aliasElem.attribute( QStringLiteral( "name" ) ) );
2390 QgsDebugMsgLevel( "context" + QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ) + " source " + aliasElem.attribute( QStringLiteral( "name" ) ), 3 );
2391 }
2392 else
2393 {
2394 //if it has no alias, it should be the fields translation
2395 alias = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ), field );
2396 QgsDebugMsgLevel( "context" + QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ) + " source " + field, 3 );
2397 //if it gets the exact field value, there has been no translation (or not even translation loaded) - so no alias should be generated;
2398 if ( alias == aliasElem.attribute( QStringLiteral( "field" ) ) )
2399 alias.clear();
2400 }
2401
2402 QgsDebugMsgLevel( "field " + field + " origalias " + aliasElem.attribute( QStringLiteral( "name" ) ) + " trans " + alias, 3 );
2403 mAttributeAliasMap.insert( field, alias );
2404 }
2405 }
2406
2407 // IMPORTANT - we don't clear mAttributeSplitPolicy here, as it may contain policies which are coming direct
2408 // from the data provider. Instead we leave any existing policies and only overwrite them if the style
2409 // has a specific value for that field's policy
2410 const QDomNode splitPoliciesNode = layerNode.namedItem( QStringLiteral( "splitPolicies" ) );
2411 if ( !splitPoliciesNode.isNull() )
2412 {
2413 const QDomNodeList splitPolicyNodeList = splitPoliciesNode.toElement().elementsByTagName( QStringLiteral( "policy" ) );
2414 for ( int i = 0; i < splitPolicyNodeList.size(); ++i )
2415 {
2416 const QDomElement splitPolicyElem = splitPolicyNodeList.at( i ).toElement();
2417 const QString field = splitPolicyElem.attribute( QStringLiteral( "field" ) );
2418 const Qgis::FieldDomainSplitPolicy policy = qgsEnumKeyToValue( splitPolicyElem.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDomainSplitPolicy::Duplicate );
2419 mAttributeSplitPolicy.insert( field, policy );
2420 }
2421 }
2422
2423 // default expressions
2424 mDefaultExpressionMap.clear();
2425 QDomNode defaultsNode = layerNode.namedItem( QStringLiteral( "defaults" ) );
2426 if ( !defaultsNode.isNull() )
2427 {
2428 QDomNodeList defaultNodeList = defaultsNode.toElement().elementsByTagName( QStringLiteral( "default" ) );
2429 for ( int i = 0; i < defaultNodeList.size(); ++i )
2430 {
2431 QDomElement defaultElem = defaultNodeList.at( i ).toElement();
2432
2433 QString field = defaultElem.attribute( QStringLiteral( "field" ), QString() );
2434 QString expression = defaultElem.attribute( QStringLiteral( "expression" ), QString() );
2435 bool applyOnUpdate = defaultElem.attribute( QStringLiteral( "applyOnUpdate" ), QStringLiteral( "0" ) ) == QLatin1String( "1" );
2436 if ( field.isEmpty() || expression.isEmpty() )
2437 continue;
2438
2439 mDefaultExpressionMap.insert( field, QgsDefaultValue( expression, applyOnUpdate ) );
2440 }
2441 }
2442
2443 // constraints
2444 mFieldConstraints.clear();
2445 mFieldConstraintStrength.clear();
2446 QDomNode constraintsNode = layerNode.namedItem( QStringLiteral( "constraints" ) );
2447 if ( !constraintsNode.isNull() )
2448 {
2449 QDomNodeList constraintNodeList = constraintsNode.toElement().elementsByTagName( QStringLiteral( "constraint" ) );
2450 for ( int i = 0; i < constraintNodeList.size(); ++i )
2451 {
2452 QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2453
2454 QString field = constraintElem.attribute( QStringLiteral( "field" ), QString() );
2455 int constraints = constraintElem.attribute( QStringLiteral( "constraints" ), QStringLiteral( "0" ) ).toInt();
2456 if ( field.isEmpty() || constraints == 0 )
2457 continue;
2458
2459 mFieldConstraints.insert( field, static_cast< QgsFieldConstraints::Constraints >( constraints ) );
2460
2461 int uniqueStrength = constraintElem.attribute( QStringLiteral( "unique_strength" ), QStringLiteral( "1" ) ).toInt();
2462 int notNullStrength = constraintElem.attribute( QStringLiteral( "notnull_strength" ), QStringLiteral( "1" ) ).toInt();
2463 int expStrength = constraintElem.attribute( QStringLiteral( "exp_strength" ), QStringLiteral( "1" ) ).toInt();
2464
2465 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintUnique ), static_cast< QgsFieldConstraints::ConstraintStrength >( uniqueStrength ) );
2466 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintNotNull ), static_cast< QgsFieldConstraints::ConstraintStrength >( notNullStrength ) );
2467 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintExpression ), static_cast< QgsFieldConstraints::ConstraintStrength >( expStrength ) );
2468 }
2469 }
2470 mFieldConstraintExpressions.clear();
2471 QDomNode constraintExpressionsNode = layerNode.namedItem( QStringLiteral( "constraintExpressions" ) );
2472 if ( !constraintExpressionsNode.isNull() )
2473 {
2474 QDomNodeList constraintNodeList = constraintExpressionsNode.toElement().elementsByTagName( QStringLiteral( "constraint" ) );
2475 for ( int i = 0; i < constraintNodeList.size(); ++i )
2476 {
2477 QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2478
2479 QString field = constraintElem.attribute( QStringLiteral( "field" ), QString() );
2480 QString exp = constraintElem.attribute( QStringLiteral( "exp" ), QString() );
2481 QString desc = constraintElem.attribute( QStringLiteral( "desc" ), QString() );
2482 if ( field.isEmpty() || exp.isEmpty() )
2483 continue;
2484
2485 mFieldConstraintExpressions.insert( field, qMakePair( exp, desc ) );
2486 }
2487 }
2488
2489 updateFields();
2490 }
2491
2492 // load field configuration
2493 if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
2494 {
2495 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Forms" ) );
2496
2497 QDomElement widgetsElem = layerNode.namedItem( QStringLiteral( "fieldConfiguration" ) ).toElement();
2498 QDomNodeList fieldConfigurationElementList = widgetsElem.elementsByTagName( QStringLiteral( "field" ) );
2499 for ( int i = 0; i < fieldConfigurationElementList.size(); ++i )
2500 {
2501 const QDomElement fieldConfigElement = fieldConfigurationElementList.at( i ).toElement();
2502 const QDomElement fieldWidgetElement = fieldConfigElement.elementsByTagName( QStringLiteral( "editWidget" ) ).at( 0 ).toElement();
2503
2504 QString fieldName = fieldConfigElement.attribute( QStringLiteral( "name" ) );
2505
2506 if ( categories.testFlag( Fields ) )
2507 mFieldConfigurationFlags[fieldName] = qgsFlagKeysToValue( fieldConfigElement.attribute( QStringLiteral( "configurationFlags" ) ), Qgis::FieldConfigurationFlag::NoFlag );
2508
2509 // Load editor widget configuration
2510 if ( categories.testFlag( Forms ) )
2511 {
2512 const QString widgetType = fieldWidgetElement.attribute( QStringLiteral( "type" ) );
2513 const QDomElement cfgElem = fieldConfigElement.elementsByTagName( QStringLiteral( "config" ) ).at( 0 ).toElement();
2514 const QDomElement optionsElem = cfgElem.childNodes().at( 0 ).toElement();
2515 QVariantMap optionsMap = QgsXmlUtils::readVariant( optionsElem ).toMap();
2516 if ( widgetType == QLatin1String( "ValueRelation" ) )
2517 {
2518 optionsMap[ QStringLiteral( "Value" ) ] = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fields:%2:valuerelationvalue" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text(), fieldName ), optionsMap[ QStringLiteral( "Value" ) ].toString() );
2519 }
2520 QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( widgetType, optionsMap );
2521 mFieldWidgetSetups[fieldName] = setup;
2522 }
2523 }
2524 }
2525
2526 // Legacy reading for QGIS 3.14 and older projects
2527 // Attributes excluded from WMS and WFS
2528 if ( categories.testFlag( Fields ) )
2529 {
2530 const QList<QPair<QString, Qgis::FieldConfigurationFlag>> legacyConfig
2531 {
2532 qMakePair( QStringLiteral( "excludeAttributesWMS" ), Qgis::FieldConfigurationFlag::HideFromWms ),
2533 qMakePair( QStringLiteral( "excludeAttributesWFS" ), Qgis::FieldConfigurationFlag::HideFromWfs )
2534 };
2535 for ( const auto &config : legacyConfig )
2536 {
2537 QDomNode excludeNode = layerNode.namedItem( config.first );
2538 if ( !excludeNode.isNull() )
2539 {
2540 QDomNodeList attributeNodeList = excludeNode.toElement().elementsByTagName( QStringLiteral( "attribute" ) );
2541 for ( int i = 0; i < attributeNodeList.size(); ++i )
2542 {
2543 QString fieldName = attributeNodeList.at( i ).toElement().text();
2544 if ( !mFieldConfigurationFlags.contains( fieldName ) )
2545 mFieldConfigurationFlags[fieldName] = config.second;
2546 else
2547 mFieldConfigurationFlags[fieldName].setFlag( config.second, true );
2548 }
2549 }
2550 }
2551 }
2552
2553 if ( categories.testFlag( GeometryOptions ) )
2554 mGeometryOptions->readXml( layerNode.namedItem( QStringLiteral( "geometryOptions" ) ) );
2555
2556 if ( categories.testFlag( Forms ) )
2557 mEditFormConfig.readXml( layerNode, context );
2558
2559 if ( categories.testFlag( AttributeTable ) )
2560 {
2561 mAttributeTableConfig.readXml( layerNode );
2562 mConditionalStyles->readXml( layerNode, context );
2563 mStoredExpressionManager->readXml( layerNode );
2564 }
2565
2566 if ( categories.testFlag( CustomProperties ) )
2567 readCustomProperties( layerNode, QStringLiteral( "variable" ) );
2568
2569 QDomElement mapLayerNode = layerNode.toElement();
2570 if ( categories.testFlag( LayerConfiguration )
2571 && mapLayerNode.attribute( QStringLiteral( "readOnly" ), QStringLiteral( "0" ) ).toInt() == 1 )
2572 mReadOnly = true;
2573
2574 updateFields();
2575
2576 if ( categories.testFlag( Legend ) )
2577 {
2578 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Legend" ) );
2579
2580 const QDomElement legendElem = layerNode.firstChildElement( QStringLiteral( "legend" ) );
2581 if ( !legendElem.isNull() )
2582 {
2583 std::unique_ptr< QgsMapLayerLegend > legend( QgsMapLayerLegend::defaultVectorLegend( this ) );
2584 legend->readXml( legendElem, context );
2585 setLegend( legend.release() );
2586 mSetLegendFromStyle = true;
2587 }
2588 }
2589
2590 return true;
2591}
2592
2593bool QgsVectorLayer::readStyle( const QDomNode &node, QString &errorMessage,
2594 QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
2595{
2597
2598 bool result = true;
2599 emit readCustomSymbology( node.toElement(), errorMessage );
2600
2601 // we must try to restore a renderer if our geometry type is unknown
2602 // as this allows the renderer to be correctly restored even for layers
2603 // with broken sources
2604 if ( isSpatial() || mWkbType == Qgis::WkbType::Unknown )
2605 {
2606 // defer style changed signal until we've set the renderer, labeling, everything.
2607 // we don't want multiple signals!
2608 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
2609
2610 // try renderer v2 first
2611 if ( categories.testFlag( Symbology ) )
2612 {
2613 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Symbology" ) );
2614
2615 QDomElement rendererElement = node.firstChildElement( RENDERER_TAG_NAME );
2616 if ( !rendererElement.isNull() )
2617 {
2618 QgsFeatureRenderer *r = QgsFeatureRenderer::load( rendererElement, context );
2619 if ( r )
2620 {
2621 setRenderer( r );
2622 }
2623 else
2624 {
2625 result = false;
2626 }
2627 }
2628 // make sure layer has a renderer - if none exists, fallback to a default renderer
2629 if ( isSpatial() && !renderer() )
2630 {
2632 }
2633
2634 if ( mSelectionProperties )
2635 mSelectionProperties->readXml( node.toElement(), context );
2636 }
2637
2638 // read labeling definition
2639 if ( categories.testFlag( Labeling ) )
2640 {
2641 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Labeling" ) );
2642
2643 QDomElement labelingElement = node.firstChildElement( QStringLiteral( "labeling" ) );
2645 if ( labelingElement.isNull() ||
2646 ( labelingElement.attribute( QStringLiteral( "type" ) ) == QLatin1String( "simple" ) && labelingElement.firstChildElement( QStringLiteral( "settings" ) ).isNull() ) )
2647 {
2648 // make sure we have custom properties for labeling for 2.x projects
2649 // (custom properties should be already loaded when reading the whole layer from XML,
2650 // but when reading style, custom properties are not read)
2651 readCustomProperties( node, QStringLiteral( "labeling" ) );
2652
2653 // support for pre-QGIS 3 labeling configurations written in custom properties
2654 labeling = readLabelingFromCustomProperties();
2655 }
2656 else
2657 {
2658 labeling = QgsAbstractVectorLayerLabeling::create( labelingElement, context );
2659 }
2661
2662 if ( node.toElement().hasAttribute( QStringLiteral( "labelsEnabled" ) ) )
2663 mLabelsEnabled = node.toElement().attribute( QStringLiteral( "labelsEnabled" ) ).toInt();
2664 else
2665 mLabelsEnabled = true;
2666 }
2667
2668 if ( categories.testFlag( Symbology ) )
2669 {
2670 // get and set the blend mode if it exists
2671 QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
2672 if ( !blendModeNode.isNull() )
2673 {
2674 QDomElement e = blendModeNode.toElement();
2675 setBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
2676 }
2677
2678 // get and set the feature blend mode if it exists
2679 QDomNode featureBlendModeNode = node.namedItem( QStringLiteral( "featureBlendMode" ) );
2680 if ( !featureBlendModeNode.isNull() )
2681 {
2682 QDomElement e = featureBlendModeNode.toElement();
2683 setFeatureBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
2684 }
2685 }
2686
2687 // get and set the layer transparency and scale visibility if they exists
2688 if ( categories.testFlag( Rendering ) )
2689 {
2690 QDomNode layerTransparencyNode = node.namedItem( QStringLiteral( "layerTransparency" ) );
2691 if ( !layerTransparencyNode.isNull() )
2692 {
2693 QDomElement e = layerTransparencyNode.toElement();
2694 setOpacity( 1.0 - e.text().toInt() / 100.0 );
2695 }
2696 QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
2697 if ( !layerOpacityNode.isNull() )
2698 {
2699 QDomElement e = layerOpacityNode.toElement();
2700 setOpacity( e.text().toDouble() );
2701 }
2702
2703 const bool hasScaleBasedVisibiliy { node.attributes().namedItem( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).nodeValue() == '1' };
2704 setScaleBasedVisibility( hasScaleBasedVisibiliy );
2705 bool ok;
2706 const double maxScale { node.attributes().namedItem( QStringLiteral( "maxScale" ) ).nodeValue().toDouble( &ok ) };
2707 if ( ok )
2708 {
2709 setMaximumScale( maxScale );
2710 }
2711 const double minScale { node.attributes().namedItem( QStringLiteral( "minScale" ) ).nodeValue().toDouble( &ok ) };
2712 if ( ok )
2713 {
2714 setMinimumScale( minScale );
2715 }
2716
2717 QDomElement e = node.toElement();
2718
2719 // get the simplification drawing settings
2720 mSimplifyMethod.setSimplifyHints( static_cast< QgsVectorSimplifyMethod::SimplifyHints >( e.attribute( QStringLiteral( "simplifyDrawingHints" ), QStringLiteral( "1" ) ).toInt() ) );
2721 mSimplifyMethod.setSimplifyAlgorithm( static_cast< QgsVectorSimplifyMethod::SimplifyAlgorithm >( e.attribute( QStringLiteral( "simplifyAlgorithm" ), QStringLiteral( "0" ) ).toInt() ) );
2722 mSimplifyMethod.setThreshold( e.attribute( QStringLiteral( "simplifyDrawingTol" ), QStringLiteral( "1" ) ).toFloat() );
2723 mSimplifyMethod.setForceLocalOptimization( e.attribute( QStringLiteral( "simplifyLocal" ), QStringLiteral( "1" ) ).toInt() );
2724 mSimplifyMethod.setMaximumScale( e.attribute( QStringLiteral( "simplifyMaxScale" ), QStringLiteral( "1" ) ).toFloat() );
2725
2726 if ( mRenderer )
2727 mRenderer->setReferenceScale( e.attribute( QStringLiteral( "symbologyReferenceScale" ), QStringLiteral( "-1" ) ).toDouble() );
2728 }
2729
2730 //diagram renderer and diagram layer settings
2731 if ( categories.testFlag( Diagrams ) )
2732 {
2733 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Diagrams" ) );
2734
2735 delete mDiagramRenderer;
2736 mDiagramRenderer = nullptr;
2737 QDomElement singleCatDiagramElem = node.firstChildElement( QStringLiteral( "SingleCategoryDiagramRenderer" ) );
2738 if ( !singleCatDiagramElem.isNull() )
2739 {
2740 mDiagramRenderer = new QgsSingleCategoryDiagramRenderer();
2741 mDiagramRenderer->readXml( singleCatDiagramElem, context );
2742 }
2743 QDomElement linearDiagramElem = node.firstChildElement( QStringLiteral( "LinearlyInterpolatedDiagramRenderer" ) );
2744 if ( !linearDiagramElem.isNull() )
2745 {
2746 if ( linearDiagramElem.hasAttribute( QStringLiteral( "classificationAttribute" ) ) )
2747 {
2748 // fix project from before QGIS 3.0
2749 int idx = linearDiagramElem.attribute( QStringLiteral( "classificationAttribute" ) ).toInt();
2750 if ( idx >= 0 && idx < mFields.count() )
2751 linearDiagramElem.setAttribute( QStringLiteral( "classificationField" ), mFields.at( idx ).name() );
2752 }
2753
2754 mDiagramRenderer = new QgsLinearlyInterpolatedDiagramRenderer();
2755 mDiagramRenderer->readXml( linearDiagramElem, context );
2756 }
2757
2758 if ( mDiagramRenderer )
2759 {
2760 QDomElement diagramSettingsElem = node.firstChildElement( QStringLiteral( "DiagramLayerSettings" ) );
2761 if ( !diagramSettingsElem.isNull() )
2762 {
2763 bool oldXPos = diagramSettingsElem.hasAttribute( QStringLiteral( "xPosColumn" ) );
2764 bool oldYPos = diagramSettingsElem.hasAttribute( QStringLiteral( "yPosColumn" ) );
2765 bool oldShow = diagramSettingsElem.hasAttribute( QStringLiteral( "showColumn" ) );
2766 if ( oldXPos || oldYPos || oldShow )
2767 {
2768 // fix project from before QGIS 3.0
2770 if ( oldXPos )
2771 {
2772 int xPosColumn = diagramSettingsElem.attribute( QStringLiteral( "xPosColumn" ) ).toInt();
2773 if ( xPosColumn >= 0 && xPosColumn < mFields.count() )
2774 ddp.setProperty( QgsDiagramLayerSettings::PositionX, QgsProperty::fromField( mFields.at( xPosColumn ).name(), true ) );
2775 }
2776 if ( oldYPos )
2777 {
2778 int yPosColumn = diagramSettingsElem.attribute( QStringLiteral( "yPosColumn" ) ).toInt();
2779 if ( yPosColumn >= 0 && yPosColumn < mFields.count() )
2780 ddp.setProperty( QgsDiagramLayerSettings::PositionY, QgsProperty::fromField( mFields.at( yPosColumn ).name(), true ) );
2781 }
2782 if ( oldShow )
2783 {
2784 int showColumn = diagramSettingsElem.attribute( QStringLiteral( "showColumn" ) ).toInt();
2785 if ( showColumn >= 0 && showColumn < mFields.count() )
2786 ddp.setProperty( QgsDiagramLayerSettings::Show, QgsProperty::fromField( mFields.at( showColumn ).name(), true ) );
2787 }
2788 QDomElement propertiesElem = diagramSettingsElem.ownerDocument().createElement( QStringLiteral( "properties" ) );
2790 {
2791 { QgsDiagramLayerSettings::PositionX, QgsPropertyDefinition( "positionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double ) },
2792 { QgsDiagramLayerSettings::PositionY, QgsPropertyDefinition( "positionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double ) },
2793 { QgsDiagramLayerSettings::Show, QgsPropertyDefinition( "show", QObject::tr( "Show diagram" ), QgsPropertyDefinition::Boolean ) },
2794 };
2795 ddp.writeXml( propertiesElem, defs );
2796 diagramSettingsElem.appendChild( propertiesElem );
2797 }
2798
2799 delete mDiagramLayerSettings;
2800 mDiagramLayerSettings = new QgsDiagramLayerSettings();
2801 mDiagramLayerSettings->readXml( diagramSettingsElem );
2802 }
2803 }
2804 }
2805 // end diagram
2806
2807 styleChangedSignalBlocker.release();
2809 }
2810 return result;
2811}
2812
2813
2814bool QgsVectorLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
2815 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
2816{
2818
2819 QDomElement layerElement = node.toElement();
2820 writeCommonStyle( layerElement, doc, context, categories );
2821
2822 ( void )writeStyle( node, doc, errorMessage, context, categories );
2823
2824 if ( categories.testFlag( GeometryOptions ) )
2825 mGeometryOptions->writeXml( node );
2826
2827 if ( categories.testFlag( Legend ) && legend() )
2828 {
2829 QDomElement legendElement = legend()->writeXml( doc, context );
2830 if ( !legendElement.isNull() )
2831 node.appendChild( legendElement );
2832 }
2833
2834 // Relation information for both referenced and referencing sides
2835 if ( categories.testFlag( Relations ) )
2836 {
2837 // Store referenced layers: relations where "this" is the child layer (the referencing part, that holds the FK)
2838 QDomElement referencedLayersElement = doc.createElement( QStringLiteral( "referencedLayers" ) );
2839 node.appendChild( referencedLayersElement );
2840
2841 const QList<QgsRelation> referencingRelations { QgsProject::instance()->relationManager()->referencingRelations( this ) };
2842 for ( const QgsRelation &rel : referencingRelations )
2843 {
2844 switch ( rel.type() )
2845 {
2847 QgsWeakRelation::writeXml( this, QgsWeakRelation::Referencing, rel, referencedLayersElement, doc );
2848 break;
2850 break;
2851 }
2852 }
2853
2854 // Store referencing layers: relations where "this" is the parent layer (the referenced part, that holds the FK)
2855 QDomElement referencingLayersElement = doc.createElement( QStringLiteral( "referencingLayers" ) );
2856 node.appendChild( referencedLayersElement );
2857
2858 const QList<QgsRelation> referencedRelations { QgsProject::instance()->relationManager()->referencedRelations( this ) };
2859 for ( const QgsRelation &rel : referencedRelations )
2860 {
2861 switch ( rel.type() )
2862 {
2864 QgsWeakRelation::writeXml( this, QgsWeakRelation::Referenced, rel, referencingLayersElement, doc );
2865 break;
2867 break;
2868 }
2869 }
2870 }
2871
2872 // write field configurations
2873 if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
2874 {
2875 QDomElement fieldConfigurationElement;
2876 // field configuration flag
2877 fieldConfigurationElement = doc.createElement( QStringLiteral( "fieldConfiguration" ) );
2878 node.appendChild( fieldConfigurationElement );
2879
2880 for ( const QgsField &field : std::as_const( mFields ) )
2881 {
2882 QDomElement fieldElement = doc.createElement( QStringLiteral( "field" ) );
2883 fieldElement.setAttribute( QStringLiteral( "name" ), field.name() );
2884 fieldConfigurationElement.appendChild( fieldElement );
2885
2886 if ( categories.testFlag( Fields ) )
2887 {
2888 fieldElement.setAttribute( QStringLiteral( "configurationFlags" ), qgsFlagValueToKeys( field.configurationFlags() ) );
2889 }
2890
2891 if ( categories.testFlag( Forms ) )
2892 {
2893 QgsEditorWidgetSetup widgetSetup = field.editorWidgetSetup();
2894
2895 // TODO : wrap this part in an if to only save if it was user-modified
2896 QDomElement editWidgetElement = doc.createElement( QStringLiteral( "editWidget" ) );
2897 fieldElement.appendChild( editWidgetElement );
2898 editWidgetElement.setAttribute( QStringLiteral( "type" ), field.editorWidgetSetup().type() );
2899 QDomElement editWidgetConfigElement = doc.createElement( QStringLiteral( "config" ) );
2900
2901 editWidgetConfigElement.appendChild( QgsXmlUtils::writeVariant( widgetSetup.config(), doc ) );
2902 editWidgetElement.appendChild( editWidgetConfigElement );
2903 // END TODO : wrap this part in an if to only save if it was user-modified
2904 }
2905 }
2906 }
2907
2908 if ( categories.testFlag( Fields ) )
2909 {
2910 //attribute aliases
2911 QDomElement aliasElem = doc.createElement( QStringLiteral( "aliases" ) );
2912 for ( const QgsField &field : std::as_const( mFields ) )
2913 {
2914 QDomElement aliasEntryElem = doc.createElement( QStringLiteral( "alias" ) );
2915 aliasEntryElem.setAttribute( QStringLiteral( "field" ), field.name() );
2916 aliasEntryElem.setAttribute( QStringLiteral( "index" ), mFields.indexFromName( field.name() ) );
2917 aliasEntryElem.setAttribute( QStringLiteral( "name" ), field.alias() );
2918 aliasElem.appendChild( aliasEntryElem );
2919 }
2920 node.appendChild( aliasElem );
2921
2922 //split policies
2923 {
2924 QDomElement splitPoliciesElement = doc.createElement( QStringLiteral( "splitPolicies" ) );
2925 for ( const QgsField &field : std::as_const( mFields ) )
2926 {
2927 QDomElement splitPolicyElem = doc.createElement( QStringLiteral( "policy" ) );
2928 splitPolicyElem.setAttribute( QStringLiteral( "field" ), field.name() );
2929 splitPolicyElem.setAttribute( QStringLiteral( "policy" ), qgsEnumValueToKey( field.splitPolicy() ) );
2930 splitPoliciesElement.appendChild( splitPolicyElem );
2931 }
2932 node.appendChild( splitPoliciesElement );
2933 }
2934
2935 //default expressions
2936 QDomElement defaultsElem = doc.createElement( QStringLiteral( "defaults" ) );
2937 for ( const QgsField &field : std::as_const( mFields ) )
2938 {
2939 QDomElement defaultElem = doc.createElement( QStringLiteral( "default" ) );
2940 defaultElem.setAttribute( QStringLiteral( "field" ), field.name() );
2941 defaultElem.setAttribute( QStringLiteral( "expression" ), field.defaultValueDefinition().expression() );
2942 defaultElem.setAttribute( QStringLiteral( "applyOnUpdate" ), field.defaultValueDefinition().applyOnUpdate() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
2943 defaultsElem.appendChild( defaultElem );
2944 }
2945 node.appendChild( defaultsElem );
2946
2947 // constraints
2948 QDomElement constraintsElem = doc.createElement( QStringLiteral( "constraints" ) );
2949 for ( const QgsField &field : std::as_const( mFields ) )
2950 {
2951 QDomElement constraintElem = doc.createElement( QStringLiteral( "constraint" ) );
2952 constraintElem.setAttribute( QStringLiteral( "field" ), field.name() );
2953 constraintElem.setAttribute( QStringLiteral( "constraints" ), field.constraints().constraints() );
2954 constraintElem.setAttribute( QStringLiteral( "unique_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintUnique ) );
2955 constraintElem.setAttribute( QStringLiteral( "notnull_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintNotNull ) );
2956 constraintElem.setAttribute( QStringLiteral( "exp_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintExpression ) );
2957 constraintsElem.appendChild( constraintElem );
2958 }
2959 node.appendChild( constraintsElem );
2960
2961 // constraint expressions
2962 QDomElement constraintExpressionsElem = doc.createElement( QStringLiteral( "constraintExpressions" ) );
2963 for ( const QgsField &field : std::as_const( mFields ) )
2964 {
2965 QDomElement constraintExpressionElem = doc.createElement( QStringLiteral( "constraint" ) );
2966 constraintExpressionElem.setAttribute( QStringLiteral( "field" ), field.name() );
2967 constraintExpressionElem.setAttribute( QStringLiteral( "exp" ), field.constraints().constraintExpression() );
2968 constraintExpressionElem.setAttribute( QStringLiteral( "desc" ), field.constraints().constraintDescription() );
2969 constraintExpressionsElem.appendChild( constraintExpressionElem );
2970 }
2971 node.appendChild( constraintExpressionsElem );
2972
2973 // save expression fields
2974 if ( !mExpressionFieldBuffer )
2975 {
2976 // can happen when saving style on a invalid layer
2978 dummy.writeXml( node, doc );
2979 }
2980 else
2981 {
2982 mExpressionFieldBuffer->writeXml( node, doc );
2983 }
2984 }
2985
2986 // add attribute actions
2987 if ( categories.testFlag( Actions ) )
2988 mActions->writeXml( node );
2989
2990 if ( categories.testFlag( AttributeTable ) )
2991 {
2992 mAttributeTableConfig.writeXml( node );
2993 mConditionalStyles->writeXml( node, doc, context );
2994 mStoredExpressionManager->writeXml( node );
2995 }
2996
2997 if ( categories.testFlag( Forms ) )
2998 mEditFormConfig.writeXml( node, context );
2999
3000 // save readonly state
3001 if ( categories.testFlag( LayerConfiguration ) )
3002 node.toElement().setAttribute( QStringLiteral( "readOnly" ), mReadOnly );
3003
3004 // save preview expression
3005 if ( categories.testFlag( LayerConfiguration ) )
3006 {
3007 QDomElement prevExpElem = doc.createElement( QStringLiteral( "previewExpression" ) );
3008 QDomText prevExpText = doc.createTextNode( mDisplayExpression );
3009 prevExpElem.appendChild( prevExpText );
3010 node.appendChild( prevExpElem );
3011 }
3012
3013 // save map tip
3014 if ( categories.testFlag( MapTips ) )
3015 {
3016 QDomElement mapTipElem = doc.createElement( QStringLiteral( "mapTip" ) );
3017 mapTipElem.setAttribute( QStringLiteral( "enabled" ), mapTipsEnabled() );
3018 QDomText mapTipText = doc.createTextNode( mMapTipTemplate );
3019 mapTipElem.appendChild( mapTipText );
3020 node.toElement().appendChild( mapTipElem );
3021 }
3022
3023 return true;
3024}
3025
3026bool QgsVectorLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
3027 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
3028{
3030
3031 QDomElement mapLayerNode = node.toElement();
3032
3033 emit writeCustomSymbology( mapLayerNode, doc, errorMessage );
3034
3035 // we must try to write the renderer if our geometry type is unknown
3036 // as this allows the renderer to be correctly restored even for layers
3037 // with broken sources
3038 if ( isSpatial() || mWkbType == Qgis::WkbType::Unknown )
3039 {
3040 if ( categories.testFlag( Symbology ) )
3041 {
3042 if ( mRenderer )
3043 {
3044 QDomElement rendererElement = mRenderer->save( doc, context );
3045 node.appendChild( rendererElement );
3046 }
3047 if ( mSelectionProperties )
3048 {
3049 mSelectionProperties->writeXml( mapLayerNode, doc, context );
3050 }
3051 }
3052
3053 if ( categories.testFlag( Labeling ) )
3054 {
3055 if ( mLabeling )
3056 {
3057 QDomElement labelingElement = mLabeling->save( doc, context );
3058 node.appendChild( labelingElement );
3059 }
3060 mapLayerNode.setAttribute( QStringLiteral( "labelsEnabled" ), mLabelsEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
3061 }
3062
3063 // save the simplification drawing settings
3064 if ( categories.testFlag( Rendering ) )
3065 {
3066 mapLayerNode.setAttribute( QStringLiteral( "simplifyDrawingHints" ), QString::number( mSimplifyMethod.simplifyHints() ) );
3067 mapLayerNode.setAttribute( QStringLiteral( "simplifyAlgorithm" ), QString::number( mSimplifyMethod.simplifyAlgorithm() ) );
3068 mapLayerNode.setAttribute( QStringLiteral( "simplifyDrawingTol" ), QString::number( mSimplifyMethod.threshold() ) );
3069 mapLayerNode.setAttribute( QStringLiteral( "simplifyLocal" ), mSimplifyMethod.forceLocalOptimization() ? 1 : 0 );
3070 mapLayerNode.setAttribute( QStringLiteral( "simplifyMaxScale" ), QString::number( mSimplifyMethod.maximumScale() ) );
3071 }
3072
3073 //save customproperties
3074 if ( categories.testFlag( CustomProperties ) )
3075 {
3076 writeCustomProperties( node, doc );
3077 }
3078
3079 if ( categories.testFlag( Symbology ) )
3080 {
3081 // add the blend mode field
3082 QDomElement blendModeElem = doc.createElement( QStringLiteral( "blendMode" ) );
3083 QDomText blendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( blendMode() ) ) ) );
3084 blendModeElem.appendChild( blendModeText );
3085 node.appendChild( blendModeElem );
3086
3087 // add the feature blend mode field
3088 QDomElement featureBlendModeElem = doc.createElement( QStringLiteral( "featureBlendMode" ) );
3089 QDomText featureBlendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( featureBlendMode() ) ) ) );
3090 featureBlendModeElem.appendChild( featureBlendModeText );
3091 node.appendChild( featureBlendModeElem );
3092 }
3093
3094 // add the layer opacity and scale visibility
3095 if ( categories.testFlag( Rendering ) )
3096 {
3097 QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
3098 QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
3099 layerOpacityElem.appendChild( layerOpacityText );
3100 node.appendChild( layerOpacityElem );
3101 mapLayerNode.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
3102 mapLayerNode.setAttribute( QStringLiteral( "maxScale" ), maximumScale() );
3103 mapLayerNode.setAttribute( QStringLiteral( "minScale" ), minimumScale() );
3104
3105 mapLayerNode.setAttribute( QStringLiteral( "symbologyReferenceScale" ), mRenderer ? mRenderer->referenceScale() : -1 );
3106 }
3107
3108 if ( categories.testFlag( Diagrams ) && mDiagramRenderer )
3109 {
3110 mDiagramRenderer->writeXml( mapLayerNode, doc, context );
3111 if ( mDiagramLayerSettings )
3112 mDiagramLayerSettings->writeXml( mapLayerNode, doc );
3113 }
3114 }
3115 return true;
3116}
3117
3118bool QgsVectorLayer::readSld( const QDomNode &node, QString &errorMessage )
3119{
3121
3122 // get the Name element
3123 QDomElement nameElem = node.firstChildElement( QStringLiteral( "Name" ) );
3124 if ( nameElem.isNull() )
3125 {
3126 errorMessage = QStringLiteral( "Warning: Name element not found within NamedLayer while it's required." );
3127 }
3128
3129 if ( isSpatial() )
3130 {
3131 QgsFeatureRenderer *r = QgsFeatureRenderer::loadSld( node, geometryType(), errorMessage );
3132 if ( !r )
3133 return false;
3134
3135 // defer style changed signal until we've set the renderer, labeling, everything.
3136 // we don't want multiple signals!
3137 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
3138
3139 setRenderer( r );
3140
3141 // labeling
3142 readSldLabeling( node );
3143
3144 styleChangedSignalBlocker.release();
3146 }
3147 return true;
3148}
3149
3150bool QgsVectorLayer::writeSld( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QVariantMap &props ) const
3151{
3153
3154 Q_UNUSED( errorMessage )
3155
3156 QVariantMap localProps = QVariantMap( props );
3158 {
3160 }
3161
3162 if ( isSpatial() )
3163 {
3164 // store the Name element
3165 QDomElement nameNode = doc.createElement( QStringLiteral( "se:Name" ) );
3166 nameNode.appendChild( doc.createTextNode( name() ) );
3167 node.appendChild( nameNode );
3168
3169 QDomElement userStyleElem = doc.createElement( QStringLiteral( "UserStyle" ) );
3170 node.appendChild( userStyleElem );
3171
3172 QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
3173 nameElem.appendChild( doc.createTextNode( name() ) );
3174
3175 userStyleElem.appendChild( nameElem );
3176
3177 QDomElement featureTypeStyleElem = doc.createElement( QStringLiteral( "se:FeatureTypeStyle" ) );
3178 userStyleElem.appendChild( featureTypeStyleElem );
3179
3180 mRenderer->toSld( doc, featureTypeStyleElem, localProps );
3181 if ( labelsEnabled() )
3182 {
3183 mLabeling->toSld( featureTypeStyleElem, localProps );
3184 }
3185 }
3186 return true;
3187}
3188
3189
3190bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, QgsGeometry &geom, bool skipDefaultValue )
3191{
3193
3194 if ( !mEditBuffer || !mDataProvider )
3195 {
3196 return false;
3197 }
3198
3199 if ( mGeometryOptions->isActive() )
3200 mGeometryOptions->apply( geom );
3201
3202 updateExtents();
3203
3204 bool result = mEditBuffer->changeGeometry( fid, geom );
3205
3206 if ( result )
3207 {
3208 updateExtents();
3209 if ( !skipDefaultValue && !mDefaultValueOnUpdateFields.isEmpty() )
3210 updateDefaultValues( fid );
3211 }
3212 return result;
3213}
3214
3215
3216bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue, bool skipDefaultValues )
3217{
3219
3220 bool result = false;
3221
3222 switch ( fields().fieldOrigin( field ) )
3223 {
3225 result = mJoinBuffer->changeAttributeValue( fid, field, newValue, oldValue );
3226 if ( result )
3227 emit attributeValueChanged( fid, field, newValue );
3228 break;
3229
3233 {
3234 if ( mEditBuffer && mDataProvider )
3235 result = mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
3236 break;
3237 }
3238
3240 break;
3241 }
3242
3243 if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
3244 updateDefaultValues( fid );
3245
3246 return result;
3247}
3248
3249bool QgsVectorLayer::changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues, bool skipDefaultValues )
3250{
3252
3253 bool result = true;
3254
3255 QgsAttributeMap newValuesJoin;
3256 QgsAttributeMap oldValuesJoin;
3257
3258 QgsAttributeMap newValuesNotJoin;
3259 QgsAttributeMap oldValuesNotJoin;
3260
3261 for ( auto it = newValues.constBegin(); it != newValues.constEnd(); ++it )
3262 {
3263 const int field = it.key();
3264 const QVariant newValue = it.value();
3265 QVariant oldValue;
3266
3267 if ( oldValues.contains( field ) )
3268 oldValue = oldValues[field];
3269
3270 switch ( fields().fieldOrigin( field ) )
3271 {
3273 newValuesJoin[field] = newValue;
3274 oldValuesJoin[field] = oldValue;
3275 break;
3276
3280 {
3281 newValuesNotJoin[field] = newValue;
3282 oldValuesNotJoin[field] = oldValue;
3283 break;
3284 }
3285
3287 break;
3288 }
3289 }
3290
3291 if ( ! newValuesJoin.isEmpty() && mJoinBuffer )
3292 {
3293 result = mJoinBuffer->changeAttributeValues( fid, newValuesJoin, oldValuesJoin );
3294 }
3295
3296 if ( ! newValuesNotJoin.isEmpty() )
3297 {
3298 if ( mEditBuffer && mDataProvider )
3299 result &= mEditBuffer->changeAttributeValues( fid, newValuesNotJoin, oldValues );
3300 else
3301 result = false;
3302 }
3303
3304 if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
3305 {
3306 updateDefaultValues( fid );
3307 }
3308
3309 return result;
3310}
3311
3313{
3315
3316 if ( !mEditBuffer || !mDataProvider )
3317 return false;
3318
3319 return mEditBuffer->addAttribute( field );
3320}
3321
3323{
3325
3326 if ( attIndex < 0 || attIndex >= fields().count() )
3327 return;
3328
3329 QString name = fields().at( attIndex ).name();
3330 mFields[ attIndex ].setAlias( QString() );
3331 if ( mAttributeAliasMap.contains( name ) )
3332 {
3333 mAttributeAliasMap.remove( name );
3334 updateFields();
3335 mEditFormConfig.setFields( mFields );
3336 emit layerModified();
3337 }
3338}
3339
3340bool QgsVectorLayer::renameAttribute( int index, const QString &newName )
3341{
3343
3344 if ( index < 0 || index >= fields().count() )
3345 return false;
3346
3347 switch ( mFields.fieldOrigin( index ) )
3348 {
3350 {
3351 if ( mExpressionFieldBuffer )
3352 {
3353 int oi = mFields.fieldOriginIndex( index );
3354 mExpressionFieldBuffer->renameExpression( oi, newName );
3355 updateFields();
3356 return true;
3357 }
3358 else
3359 {
3360 return false;
3361 }
3362 }
3363
3366
3367 if ( !mEditBuffer || !mDataProvider )
3368 return false;
3369
3370 return mEditBuffer->renameAttribute( index, newName );
3371
3374 return false;
3375
3376 }
3377
3378 return false; // avoid warning
3379}
3380
3381void QgsVectorLayer::setFieldAlias( int attIndex, const QString &aliasString )
3382{
3384
3385 if ( attIndex < 0 || attIndex >= fields().count() )
3386 return;
3387
3388 QString name = fields().at( attIndex ).name();
3389
3390 mAttributeAliasMap.insert( name, aliasString );
3391 mFields[ attIndex ].setAlias( aliasString );
3392 mEditFormConfig.setFields( mFields );
3393 emit layerModified(); // TODO[MD]: should have a different signal?
3394}
3395
3396QString QgsVectorLayer::attributeAlias( int index ) const
3397{
3399
3400 if ( index < 0 || index >= fields().count() )
3401 return QString();
3402
3403 return fields().at( index ).alias();
3404}
3405
3407{
3409
3410 if ( index >= 0 && index < mFields.count() )
3411 return mFields.at( index ).displayName();
3412 else
3413 return QString();
3414}
3415
3417{
3419
3420 return mAttributeAliasMap;
3421}
3422
3424{
3426
3427 if ( index < 0 || index >= fields().count() )
3428 return;
3429
3430 const QString name = fields().at( index ).name();
3431
3432 mAttributeSplitPolicy.insert( name, policy );
3433 mFields[ index ].setSplitPolicy( policy );
3434 mEditFormConfig.setFields( mFields );
3435 emit layerModified(); // TODO[MD]: should have a different signal?
3436}
3437
3439{
3441
3442 QSet<QString> excludeList;
3443 QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
3444 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
3445 {
3446 if ( flagsIt->testFlag( Qgis::FieldConfigurationFlag::HideFromWms ) )
3447 {
3448 excludeList << flagsIt.key();
3449 }
3450 }
3451 return excludeList;
3452}
3453
3454void QgsVectorLayer::setExcludeAttributesWms( const QSet<QString> &att )
3455{
3457
3458 QMap< QString, Qgis::FieldConfigurationFlags >::iterator flagsIt = mFieldConfigurationFlags.begin();
3459 for ( ; flagsIt != mFieldConfigurationFlags.end(); ++flagsIt )
3460 {
3461 flagsIt->setFlag( Qgis::FieldConfigurationFlag::HideFromWms, att.contains( flagsIt.key() ) );
3462 }
3463 updateFields();
3464}
3465
3467{
3469
3470 QSet<QString> excludeList;
3471 QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
3472 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
3473 {
3474 if ( flagsIt->testFlag( Qgis::FieldConfigurationFlag::HideFromWfs ) )
3475 {
3476 excludeList << flagsIt.key();
3477 }
3478 }
3479 return excludeList;
3480}
3481
3482void QgsVectorLayer::setExcludeAttributesWfs( const QSet<QString> &att )
3483{
3485
3486 QMap< QString, Qgis::FieldConfigurationFlags >::iterator flagsIt = mFieldConfigurationFlags.begin();
3487 for ( ; flagsIt != mFieldConfigurationFlags.end(); ++flagsIt )
3488 {
3489 flagsIt->setFlag( Qgis::FieldConfigurationFlag::HideFromWfs, att.contains( flagsIt.key() ) );
3490 }
3491 updateFields();
3492}
3493
3495{
3497
3498 if ( index < 0 || index >= fields().count() )
3499 return false;
3500
3501 if ( mFields.fieldOrigin( index ) == QgsFields::OriginExpression )
3502 {
3503 removeExpressionField( index );
3504 return true;
3505 }
3506
3507 if ( !mEditBuffer || !mDataProvider )
3508 return false;
3509
3510 return mEditBuffer->deleteAttribute( index );
3511}
3512
3513bool QgsVectorLayer::deleteAttributes( const QList<int> &attrs )
3514{
3516
3517 bool deleted = false;
3518
3519 // Remove multiple occurrences of same attribute
3520 QList<int> attrList = qgis::setToList( qgis::listToSet( attrs ) );
3521
3522 std::sort( attrList.begin(), attrList.end(), std::greater<int>() );
3523
3524 for ( int attr : std::as_const( attrList ) )
3525 {
3526 if ( deleteAttribute( attr ) )
3527 {
3528 deleted = true;
3529 }
3530 }
3531
3532 return deleted;
3533}
3534
3535bool QgsVectorLayer::deleteFeatureCascade( QgsFeatureId fid, QgsVectorLayer::DeleteContext *context )
3536{
3538
3539 if ( !mEditBuffer )
3540 return false;
3541
3542 if ( context && context->cascade )
3543 {
3544 const QList<QgsRelation> relations = context->project->relationManager()->referencedRelations( this );
3545 const bool hasRelationsOrJoins = !relations.empty() || mJoinBuffer->containsJoins();
3546 if ( hasRelationsOrJoins )
3547 {
3548 if ( context->mHandledFeatures.contains( this ) )
3549 {
3550 QgsFeatureIds &handledFeatureIds = context->mHandledFeatures[ this ];
3551 if ( handledFeatureIds.contains( fid ) )
3552 {
3553 // avoid endless recursion
3554 return false;
3555 }
3556 else
3557 {
3558 // add feature id
3559 handledFeatureIds << fid;
3560 }
3561 }
3562 else
3563 {
3564 // add layer and feature id
3565 context->mHandledFeatures.insert( this, QgsFeatureIds() << fid );
3566 }
3567
3568 for ( const QgsRelation &relation : relations )
3569 {
3570 //check if composition (and not association)
3571 switch ( relation.strength() )
3572 {
3574 {
3575 //get features connected over this relation
3576 QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( getFeature( fid ) );
3577 QgsFeatureIds childFeatureIds;
3578 QgsFeature childFeature;
3579 while ( relatedFeaturesIt.nextFeature( childFeature ) )
3580 {
3581 childFeatureIds.insert( childFeature.id() );
3582 }
3583 if ( childFeatureIds.count() > 0 )
3584 {
3585 relation.referencingLayer()->startEditing();
3586 relation.referencingLayer()->deleteFeatures( childFeatureIds, context );
3587 }
3588 break;
3589 }
3590
3592 break;
3593 }
3594 }
3595 }
3596 }
3597
3598 if ( mJoinBuffer->containsJoins() )
3599 mJoinBuffer->deleteFeature( fid, context );
3600
3601 bool res = mEditBuffer->deleteFeature( fid );
3602
3603 return res;
3604}
3605
3607{
3609
3610 if ( !mEditBuffer )
3611 return false;
3612
3613 bool res = deleteFeatureCascade( fid, context );
3614
3615 if ( res )
3616 {
3617 updateExtents();
3618 }
3619
3620 return res;
3621}
3622
3624{
3626
3627 bool res = true;
3628
3629 if ( ( context && context->cascade ) || mJoinBuffer->containsJoins() )
3630 {
3631 // should ideally be "deleteFeaturesCascade" for performance!
3632 for ( QgsFeatureId fid : fids )
3633 res = deleteFeatureCascade( fid, context ) && res;
3634 }
3635 else
3636 {
3637 res = mEditBuffer && mEditBuffer->deleteFeatures( fids );
3638 }
3639
3640 if ( res )
3641 {
3642 mSelectedFeatureIds.subtract( fids ); // remove it from selection
3643 updateExtents();
3644 }
3645
3646 return res;
3647}
3648
3650{
3651 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
3653
3654 return mFields;
3655}
3656
3658{
3660
3661 QgsAttributeList pkAttributesList;
3662 if ( !mDataProvider )
3663 return pkAttributesList;
3664
3665 QgsAttributeList providerIndexes = mDataProvider->pkAttributeIndexes();
3666 for ( int i = 0; i < mFields.count(); ++i )
3667 {
3668 if ( mFields.fieldOrigin( i ) == QgsFields::OriginProvider &&
3669 providerIndexes.contains( mFields.fieldOriginIndex( i ) ) )
3670 pkAttributesList << i;
3671 }
3672
3673 return pkAttributesList;
3674}
3675
3677{
3679
3680 if ( !mDataProvider )
3681 return static_cast< long long >( Qgis::FeatureCountState::UnknownCount );
3682 return mDataProvider->featureCount() +
3683 ( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->addedFeatures().size() - mEditBuffer->deletedFeatureIds().size() : 0 );
3684}
3685
3687{
3689
3690 const QgsFeatureIds deletedFeatures( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->deletedFeatureIds() : QgsFeatureIds() );
3691 const QgsFeatureMap addedFeatures( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->addedFeatures() : QgsFeatureMap() );
3692
3693 if ( mEditBuffer && !deletedFeatures.empty() )
3694 {
3695 if ( addedFeatures.size() > deletedFeatures.size() )
3697 else
3699 }
3700
3701 if ( ( !mEditBuffer || addedFeatures.empty() ) && mDataProvider && mDataProvider->empty() )
3703 else
3705}
3706
3707bool QgsVectorLayer::commitChanges( bool stopEditing )
3708{
3710
3711 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
3712 return project()->commitChanges( mCommitErrors, stopEditing, this );
3713
3714 mCommitErrors.clear();
3715
3716 if ( !mDataProvider )
3717 {
3718 mCommitErrors << tr( "ERROR: no provider" );
3719 return false;
3720 }
3721
3722 if ( !mEditBuffer )
3723 {
3724 mCommitErrors << tr( "ERROR: layer not editable" );
3725 return false;
3726 }
3727
3728 emit beforeCommitChanges( stopEditing );
3729
3730 if ( !mAllowCommit )
3731 return false;
3732
3733 mCommitChangesActive = true;
3734
3735 bool success = false;
3736 if ( mEditBuffer->editBufferGroup() )
3737 success = mEditBuffer->editBufferGroup()->commitChanges( mCommitErrors, stopEditing );
3738 else
3739 success = mEditBuffer->commitChanges( mCommitErrors );
3740
3741 mCommitChangesActive = false;
3742
3743 if ( !mDeletedFids.empty() )
3744 {
3745 emit featuresDeleted( mDeletedFids );
3746 mDeletedFids.clear();
3747 }
3748
3749 if ( success )
3750 {
3751 if ( stopEditing )
3752 {
3753 clearEditBuffer();
3754 }
3755 undoStack()->clear();
3756 emit afterCommitChanges();
3757 if ( stopEditing )
3758 emit editingStopped();
3759 }
3760 else
3761 {
3762 QgsMessageLog::logMessage( tr( "Commit errors:\n %1" ).arg( mCommitErrors.join( QLatin1String( "\n " ) ) ) );
3763 }
3764
3765 updateFields();
3766
3767 mDataProvider->updateExtents();
3768 mDataProvider->leaveUpdateMode();
3769
3770 // This second call is required because OGR provider with JSON
3771 // driver might have changed fields order after the call to
3772 // leaveUpdateMode
3773 if ( mFields.names() != mDataProvider->fields().names() )
3774 {
3775 updateFields();
3776 }
3777
3779
3780 return success;
3781}
3782
3784{
3786
3787 return mCommitErrors;
3788}
3789
3790bool QgsVectorLayer::rollBack( bool deleteBuffer )
3791{
3793
3794 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
3795 return project()->rollBack( mCommitErrors, deleteBuffer, this );
3796
3797 if ( !mEditBuffer )
3798 {
3799 return false;
3800 }
3801
3802 if ( !mDataProvider )
3803 {
3804 mCommitErrors << tr( "ERROR: no provider" );
3805 return false;
3806 }
3807
3808 bool rollbackExtent = !mDataProvider->transaction() && ( !mEditBuffer->deletedFeatureIds().isEmpty() ||
3809 !mEditBuffer->addedFeatures().isEmpty() ||
3810 !mEditBuffer->changedGeometries().isEmpty() );
3811
3812 emit beforeRollBack();
3813
3814 mEditBuffer->rollBack();
3815
3816 emit afterRollBack();
3817
3818 if ( isModified() )
3819 {
3820 // new undo stack roll back method
3821 // old method of calling every undo could cause many canvas refreshes
3822 undoStack()->setIndex( 0 );
3823 }
3824
3825 updateFields();
3826
3827 if ( deleteBuffer )
3828 {
3829 delete mEditBuffer;
3830 mEditBuffer = nullptr;
3831 undoStack()->clear();
3832 }
3833 emit editingStopped();
3834
3835 if ( rollbackExtent )
3836 updateExtents();
3837
3838 mDataProvider->leaveUpdateMode();
3839
3841 return true;
3842}
3843
3845{
3847
3848 return mSelectedFeatureIds.size();
3849}
3850
3852{
3853 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
3855
3856 return mSelectedFeatureIds;
3857}
3858
3860{
3862
3863 QgsFeatureList features;
3864 features.reserve( mSelectedFeatureIds.count() );
3865 QgsFeature f;
3866
3868
3869 while ( it.nextFeature( f ) )
3870 {
3871 features.push_back( f );
3872 }
3873
3874 return features;
3875}
3876
3878{
3880
3881 if ( mSelectedFeatureIds.isEmpty() )
3882 return QgsFeatureIterator();
3883
3886
3887 if ( mSelectedFeatureIds.count() == 1 )
3888 request.setFilterFid( *mSelectedFeatureIds.constBegin() );
3889 else
3890 request.setFilterFids( mSelectedFeatureIds );
3891
3892 return getFeatures( request );
3893}
3894
3896{
3898
3899 if ( !mEditBuffer || !mDataProvider )
3900 return false;
3901
3902 if ( mGeometryOptions->isActive() )
3903 {
3904 for ( auto feature = features.begin(); feature != features.end(); ++feature )
3905 {
3906 QgsGeometry geom = feature->geometry();
3907 mGeometryOptions->apply( geom );
3908 feature->setGeometry( geom );
3909 }
3910 }
3911
3912 bool res = mEditBuffer->addFeatures( features );
3913 updateExtents();
3914
3915 if ( res && mJoinBuffer->containsJoins() )
3916 res = mJoinBuffer->addFeatures( features );
3917
3918 return res;
3919}
3920
3922{
3924
3925 // if layer is not spatial, it has not CRS!
3926 setCrs( ( isSpatial() && mDataProvider ) ? mDataProvider->crs() : QgsCoordinateReferenceSystem() );
3927}
3928
3930{
3932
3934 if ( exp.isField() )
3935 {
3936 return static_cast<const QgsExpressionNodeColumnRef *>( exp.rootNode() )->name();
3937 }
3938
3939 return QString();
3940}
3941
3942void QgsVectorLayer::setDisplayExpression( const QString &displayExpression )
3943{
3945
3946 if ( mDisplayExpression == displayExpression )
3947 return;
3948
3949 mDisplayExpression = displayExpression;
3951}
3952
3954{
3956
3957 if ( !mDisplayExpression.isEmpty() || mFields.isEmpty() )
3958 {
3959 return mDisplayExpression;
3960 }
3961 else
3962 {
3963 const QString candidateName = QgsVectorLayerUtils::guessFriendlyIdentifierField( mFields );
3964 if ( !candidateName.isEmpty() )
3965 {
3966 return QgsExpression::quotedColumnRef( candidateName );
3967 }
3968 else
3969 {
3970 return QString();
3971 }
3972 }
3973}
3974
3976{
3978
3979 // display expressions are used as a fallback when no explicit map tip template is set
3980 return mapTipsEnabled() && ( !mapTipTemplate().isEmpty() || !displayExpression().isEmpty() );
3981}
3982
3984{
3986
3987 return ( mEditBuffer && mDataProvider );
3988}
3989
3991{
3992 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
3994
3997}
3998
3999bool QgsVectorLayer::isReadOnly() const
4000{
4002
4003 return mDataSourceReadOnly || mReadOnly;
4004}
4005
4006bool QgsVectorLayer::setReadOnly( bool readonly )
4007{
4009
4010 // exit if the layer is in editing mode
4011 if ( readonly && mEditBuffer )
4012 return false;
4013
4014 // exit if the data source is in read-only mode
4015 if ( !readonly && mDataSourceReadOnly )
4016 return false;
4017
4018 mReadOnly = readonly;
4019 emit readOnlyChanged();
4020 return true;
4021}
4022
4024{
4026
4027 if ( ! mDataProvider )
4028 return false;
4029
4030 if ( mDataSourceReadOnly )
4031 return false;
4032
4033 return mDataProvider->capabilities() & QgsVectorDataProvider::EditingCapabilities && ! mReadOnly;
4034}
4035
4037{
4039
4040 emit beforeModifiedCheck();
4041 return mEditBuffer && mEditBuffer->isModified();
4042}
4043
4044bool QgsVectorLayer::isAuxiliaryField( int index, int &srcIndex ) const
4045{
4047
4048 bool auxiliaryField = false;
4049 srcIndex = -1;
4050
4051 if ( !auxiliaryLayer() )
4052 return auxiliaryField;
4053
4054 if ( index >= 0 && fields().fieldOrigin( index ) == QgsFields::OriginJoin )
4055 {
4056 const QgsVectorLayerJoinInfo *info = mJoinBuffer->joinForFieldIndex( index, fields(), srcIndex );
4057
4058 if ( info && info->joinLayerId() == auxiliaryLayer()->id() )
4059 auxiliaryField = true;
4060 }
4061
4062 return auxiliaryField;
4063}
4064
4066{
4068
4069 // we must allow setting a renderer if our geometry type is unknown
4070 // as this allows the renderer to be correctly set even for layers
4071 // with broken sources
4072 if ( !isSpatial() && mWkbType != Qgis::WkbType::Unknown )
4073 return;
4074
4075 if ( r != mRenderer )
4076 {
4077 delete mRenderer;
4078 mRenderer = r;
4079 mSymbolFeatureCounted = false;
4080 mSymbolFeatureCountMap.clear();
4081 mSymbolFeatureIdMap.clear();
4082
4083 if ( mRenderer )
4084 {
4085 const double refreshRate = QgsSymbolLayerUtils::rendererFrameRate( mRenderer );
4086 if ( refreshRate <= 0 )
4087 {
4088 mRefreshRendererTimer->stop();
4089 mRefreshRendererTimer->setInterval( 0 );
4090 }
4091 else
4092 {
4093 mRefreshRendererTimer->setInterval( 1000 / refreshRate );
4094 mRefreshRendererTimer->start();
4095 }
4096 }
4097
4098 emit rendererChanged();
4100 }
4101}
4102
4104{
4106
4107 if ( generator )
4108 {
4109 mRendererGenerators << generator;
4110 }
4111}
4112
4114{
4116
4117 for ( int i = mRendererGenerators.count() - 1; i >= 0; --i )
4118 {
4119 if ( mRendererGenerators.at( i )->id() == id )
4120 {
4121 delete mRendererGenerators.at( i );
4122 mRendererGenerators.removeAt( i );
4123 }
4124 }
4125}
4126
4127QList<const QgsFeatureRendererGenerator *> QgsVectorLayer::featureRendererGenerators() const
4128{
4129 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
4131
4132 QList< const QgsFeatureRendererGenerator * > res;
4133 for ( const QgsFeatureRendererGenerator *generator : mRendererGenerators )
4134 res << generator;
4135 return res;
4136}
4137
4138void QgsVectorLayer::beginEditCommand( const QString &text )
4139{
4141
4142 if ( !mDataProvider )
4143 {
4144 return;
4145 }
4146 if ( mDataProvider->transaction() )
4147 {
4148 QString ignoredError;
4149 mDataProvider->transaction()->createSavepoint( ignoredError );
4150 }
4151 undoStack()->beginMacro( text );
4152 mEditCommandActive = true;
4153 emit editCommandStarted( text );
4154}
4155
4157{
4159
4160 if ( !mDataProvider )
4161 {
4162 return;
4163 }
4164 undoStack()->endMacro();
4165 mEditCommandActive = false;
4166 if ( !mDeletedFids.isEmpty() )
4167 {
4168 if ( selectedFeatureCount() > 0 )
4169 {
4170 mSelectedFeatureIds.subtract( mDeletedFids );
4171 }
4172 emit featuresDeleted( mDeletedFids );
4173 mDeletedFids.clear();
4174 }
4175 emit editCommandEnded();
4176}
4177
4179{
4181
4182 if ( !mDataProvider )
4183 {
4184 return;
4185 }
4186 undoStack()->endMacro();
4187 undoStack()->undo();
4188
4189 // it's not directly possible to pop the last command off the stack (the destroyed one)
4190 // and delete, so we add a dummy obsolete command to force this to occur.
4191 // Pushing the new command deletes the destroyed one, and since the new
4192 // command is obsolete it's automatically deleted by the undo stack.
4193 std::unique_ptr< QUndoCommand > command = std::make_unique< QUndoCommand >();
4194 command->setObsolete( true );
4195 undoStack()->push( command.release() );
4196
4197 mEditCommandActive = false;
4198 mDeletedFids.clear();
4199 emit editCommandDestroyed();
4200}
4201
4203{
4205
4206 return mJoinBuffer->addJoin( joinInfo );
4207}
4208
4209bool QgsVectorLayer::removeJoin( const QString &joinLayerId )
4210{
4212
4213 return mJoinBuffer->removeJoin( joinLayerId );
4214}
4215
4216const QList< QgsVectorLayerJoinInfo > QgsVectorLayer::vectorJoins() const
4217{
4219
4220 return mJoinBuffer->vectorJoins();
4221}
4222
4223int QgsVectorLayer::addExpressionField( const QString &exp, const QgsField &fld )
4224{
4226
4227 emit beforeAddingExpressionField( fld.name() );
4228 mExpressionFieldBuffer->addExpression( exp, fld );
4229 updateFields();
4230 int idx = mFields.indexFromName( fld.name() );
4231 emit attributeAdded( idx );
4232 return idx;
4233}
4234
4236{
4238
4239 emit beforeRemovingExpressionField( index );
4240 int oi = mFields.fieldOriginIndex( index );
4241 mExpressionFieldBuffer->removeExpression( oi );
4242 updateFields();
4243 emit attributeDeleted( index );
4244}
4245
4246QString QgsVectorLayer::expressionField( int index ) const
4247{
4249
4250 if ( mFields.fieldOrigin( index ) != QgsFields::OriginExpression )
4251 return QString();
4252
4253 int oi = mFields.fieldOriginIndex( index );
4254 if ( oi < 0 || oi >= mExpressionFieldBuffer->expressions().size() )
4255 return QString();
4256
4257 return mExpressionFieldBuffer->expressions().at( oi ).cachedExpression.expression();
4258}
4259
4260void QgsVectorLayer::updateExpressionField( int index, const QString &exp )
4261{
4263
4264 int oi = mFields.fieldOriginIndex( index );
4265 mExpressionFieldBuffer->updateExpression( oi, exp );
4266}
4267
4269{
4270 // non fatal for now -- the QgsVirtualLayerTask class is not thread safe and calls this
4272
4273 if ( !mDataProvider )
4274 return;
4275
4276 QgsFields oldFields = mFields;
4277
4278 mFields = mDataProvider->fields();
4279
4280 // added / removed fields
4281 if ( mEditBuffer )
4282 mEditBuffer->updateFields( mFields );
4283
4284 // joined fields
4285 if ( mJoinBuffer->containsJoins() )
4286 mJoinBuffer->updateFields( mFields );
4287
4288 if ( mExpressionFieldBuffer )
4289 mExpressionFieldBuffer->updateFields( mFields );
4290
4291 // set aliases and default values
4292 for ( auto aliasIt = mAttributeAliasMap.constBegin(); aliasIt != mAttributeAliasMap.constEnd(); ++aliasIt )
4293 {
4294 int index = mFields.lookupField( aliasIt.key() );
4295 if ( index < 0 )
4296 continue;
4297
4298 mFields[ index ].setAlias( aliasIt.value() );
4299 }
4300
4301 for ( auto splitPolicyIt = mAttributeSplitPolicy.constBegin(); splitPolicyIt != mAttributeSplitPolicy.constEnd(); ++splitPolicyIt )
4302 {
4303 int index = mFields.lookupField( splitPolicyIt.key() );
4304 if ( index < 0 )
4305 continue;
4306
4307 mFields[ index ].setSplitPolicy( splitPolicyIt.value() );
4308 }
4309
4310 // Update configuration flags
4311 QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
4312 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
4313 {
4314 int index = mFields.lookupField( flagsIt.key() );
4315 if ( index < 0 )
4316 continue;
4317
4318 mFields[index].setConfigurationFlags( flagsIt.value() );
4319 }
4320
4321 // Update default values
4322 mDefaultValueOnUpdateFields.clear();
4323 QMap< QString, QgsDefaultValue >::const_iterator defaultIt = mDefaultExpressionMap.constBegin();
4324 for ( ; defaultIt != mDefaultExpressionMap.constEnd(); ++defaultIt )
4325 {
4326 int index = mFields.lookupField( defaultIt.key() );
4327 if ( index < 0 )
4328 continue;
4329
4330 mFields[ index ].setDefaultValueDefinition( defaultIt.value() );
4331 if ( defaultIt.value().applyOnUpdate() )
4332 mDefaultValueOnUpdateFields.insert( index );
4333 }
4334
4335 QMap< QString, QgsFieldConstraints::Constraints >::const_iterator constraintIt = mFieldConstraints.constBegin();
4336 for ( ; constraintIt != mFieldConstraints.constEnd(); ++constraintIt )
4337 {
4338 int index = mFields.lookupField( constraintIt.key() );
4339 if ( index < 0 )
4340 continue;
4341
4342 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4343
4344 // always keep provider constraints intact
4345 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintNotNull ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintNotNull ) )
4347 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintUnique ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintUnique ) )
4349 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintExpression ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintExpression ) )
4351 mFields[ index ].setConstraints( constraints );
4352 }
4353
4354 QMap< QString, QPair< QString, QString > >::const_iterator constraintExpIt = mFieldConstraintExpressions.constBegin();
4355 for ( ; constraintExpIt != mFieldConstraintExpressions.constEnd(); ++constraintExpIt )
4356 {
4357 int index = mFields.lookupField( constraintExpIt.key() );
4358 if ( index < 0 )
4359 continue;
4360
4361 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4362
4363 // always keep provider constraints intact
4365 continue;
4366
4367 constraints.setConstraintExpression( constraintExpIt.value().first, constraintExpIt.value().second );
4368 mFields[ index ].setConstraints( constraints );
4369 }
4370
4371 QMap< QPair< QString, QgsFieldConstraints::Constraint >, QgsFieldConstraints::ConstraintStrength >::const_iterator constraintStrengthIt = mFieldConstraintStrength.constBegin();
4372 for ( ; constraintStrengthIt != mFieldConstraintStrength.constEnd(); ++constraintStrengthIt )
4373 {
4374 int index = mFields.lookupField( constraintStrengthIt.key().first );
4375 if ( index < 0 )
4376 continue;
4377
4378 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4379
4380 // always keep provider constraints intact
4382 continue;
4383
4384 constraints.setConstraintStrength( constraintStrengthIt.key().second, constraintStrengthIt.value() );
4385 mFields[ index ].setConstraints( constraints );
4386 }
4387
4388 auto fieldWidgetIterator = mFieldWidgetSetups.constBegin();
4389 for ( ; fieldWidgetIterator != mFieldWidgetSetups.constEnd(); ++ fieldWidgetIterator )
4390 {
4391 int index = mFields.indexOf( fieldWidgetIterator.key() );
4392 if ( index < 0 )
4393 continue;
4394
4395 mFields[index].setEditorWidgetSetup( fieldWidgetIterator.value() );
4396 }
4397
4398 if ( oldFields != mFields )
4399 {
4400 emit updatedFields();
4401 mEditFormConfig.setFields( mFields );
4402 }
4403
4404}
4405
4406QVariant QgsVectorLayer::defaultValue( int index, const QgsFeature &feature, QgsExpressionContext *context ) const
4407{
4409
4410 if ( index < 0 || index >= mFields.count() || !mDataProvider )
4411 return QVariant();
4412
4413 QString expression = mFields.at( index ).defaultValueDefinition().expression();
4414 if ( expression.isEmpty() )
4415 return mDataProvider->defaultValue( index );
4416
4417 QgsExpressionContext *evalContext = context;
4418 std::unique_ptr< QgsExpressionContext > tempContext;
4419 if ( !evalContext )
4420 {
4421 // no context passed, so we create a default one
4423 evalContext = tempContext.get();
4424 }
4425
4426 if ( feature.isValid() )
4427 {
4429 featScope->setFeature( feature );
4430 featScope->setFields( feature.fields() );
4431 evalContext->appendScope( featScope );
4432 }
4433
4434 QVariant val;
4435 QgsExpression exp( expression );
4436 exp.prepare( evalContext );
4437 if ( exp.hasEvalError() )
4438 {
4439 QgsLogger::warning( "Error evaluating default value: " + exp.evalErrorString() );
4440 }
4441 else
4442 {
4443 val = exp.evaluate( evalContext );
4444 }
4445
4446 if ( feature.isValid() )
4447 {
4448 delete evalContext->popScope();
4449 }
4450
4451 return val;
4452}
4453
4455{
4457
4458 if ( index < 0 || index >= mFields.count() )
4459 return;
4460
4461 if ( definition.isValid() )
4462 {
4463 mDefaultExpressionMap.insert( mFields.at( index ).name(), definition );
4464 }
4465 else
4466 {
4467 mDefaultExpressionMap.remove( mFields.at( index ).name() );
4468 }
4469 updateFields();
4470}
4471
4473{
4475
4476 if ( index < 0 || index >= mFields.count() )
4477 return QgsDefaultValue();
4478 else
4479 return mFields.at( index ).defaultValueDefinition();
4480}
4481
4482QSet<QVariant> QgsVectorLayer::uniqueValues( int index, int limit ) const
4483{
4485
4486 QSet<QVariant> uniqueValues;
4487 if ( !mDataProvider )
4488 {
4489 return uniqueValues;
4490 }
4491
4492 QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
4493 switch ( origin )
4494 {
4496 return uniqueValues;
4497
4498 case QgsFields::OriginProvider: //a provider field
4499 {
4500 uniqueValues = mDataProvider->uniqueValues( index, limit );
4501
4502 if ( mEditBuffer && ! mDataProvider->transaction() )
4503 {
4504 QSet<QString> vals;
4505 const auto constUniqueValues = uniqueValues;
4506 for ( const QVariant &v : constUniqueValues )
4507 {
4508 vals << v.toString();
4509 }
4510
4511 QgsFeatureMap added = mEditBuffer->addedFeatures();
4512 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4513 while ( addedIt.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
4514 {
4515 addedIt.next();
4516 QVariant v = addedIt.value().attribute( index );
4517 if ( v.isValid() )
4518 {
4519 QString vs = v.toString();
4520 if ( !vals.contains( vs ) )
4521 {
4522 vals << vs;
4523 uniqueValues << v;
4524 }
4525 }
4526 }
4527
4528 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4529 while ( it.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
4530 {
4531 it.next();
4532 QVariant v = it.value().value( index );
4533 if ( v.isValid() )
4534 {
4535 QString vs = v.toString();
4536 if ( !vals.contains( vs ) )
4537 {
4538 vals << vs;
4539 uniqueValues << v;
4540 }
4541 }
4542 }
4543 }
4544
4545 return uniqueValues;
4546 }
4547
4549 // the layer is editable, but in certain cases it can still be avoided going through all features
4550 if ( mDataProvider->transaction() || (
4551 mEditBuffer->deletedFeatureIds().isEmpty() &&
4552 mEditBuffer->addedFeatures().isEmpty() &&
4553 !mEditBuffer->deletedAttributeIds().contains( index ) &&
4554 mEditBuffer->changedAttributeValues().isEmpty() ) )
4555 {
4556 uniqueValues = mDataProvider->uniqueValues( index, limit );
4557 return uniqueValues;
4558 }
4559 [[fallthrough]];
4560 //we need to go through each feature
4563 {
4564 QgsAttributeList attList;
4565 attList << index;
4566
4569 .setSubsetOfAttributes( attList ) );
4570
4571 QgsFeature f;
4572 QVariant currentValue;
4573 QHash<QString, QVariant> val;
4574 while ( fit.nextFeature( f ) )
4575 {
4576 currentValue = f.attribute( index );
4577 val.insert( currentValue.toString(), currentValue );
4578 if ( limit >= 0 && val.size() >= limit )
4579 {
4580 break;
4581 }
4582 }
4583
4584 return qgis::listToSet( val.values() );
4585 }
4586 }
4587
4588 Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
4589 return uniqueValues;
4590}
4591
4592QStringList QgsVectorLayer::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
4593{
4595
4596 QStringList results;
4597 if ( !mDataProvider )
4598 {
4599 return results;
4600 }
4601
4602 QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
4603 switch ( origin )
4604 {
4606 return results;
4607
4608 case QgsFields::OriginProvider: //a provider field
4609 {
4610 results = mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
4611
4612 if ( mEditBuffer && ! mDataProvider->transaction() )
4613 {
4614 QgsFeatureMap added = mEditBuffer->addedFeatures();
4615 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4616 while ( addedIt.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
4617 {
4618 addedIt.next();
4619 QVariant v = addedIt.value().attribute( index );
4620 if ( v.isValid() )
4621 {
4622 QString vs = v.toString();
4623 if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
4624 {
4625 results << vs;
4626 }
4627 }
4628 }
4629
4630 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4631 while ( it.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
4632 {
4633 it.next();
4634 QVariant v = it.value().value( index );
4635 if ( v.isValid() )
4636 {
4637 QString vs = v.toString();
4638 if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
4639 {
4640 results << vs;
4641 }
4642 }
4643 }
4644 }
4645
4646 return results;
4647 }
4648
4650 // the layer is editable, but in certain cases it can still be avoided going through all features
4651 if ( mDataProvider->transaction() || ( mEditBuffer->deletedFeatureIds().isEmpty() &&
4652 mEditBuffer->addedFeatures().isEmpty() &&
4653 !mEditBuffer->deletedAttributeIds().contains( index ) &&
4654 mEditBuffer->changedAttributeValues().isEmpty() ) )
4655 {
4656 return mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
4657 }
4658 [[fallthrough]];
4659 //we need to go through each feature
4662 {
4663 QgsAttributeList attList;
4664 attList << index;
4665
4666 QgsFeatureRequest request;
4667 request.setSubsetOfAttributes( attList );
4669 QString fieldName = mFields.at( index ).name();
4670 request.setFilterExpression( QStringLiteral( "\"%1\" ILIKE '%%2%'" ).arg( fieldName, substring ) );
4671 QgsFeatureIterator fit = getFeatures( request );
4672
4673 QgsFeature f;
4674 QString currentValue;
4675 while ( fit.nextFeature( f ) )
4676 {
4677 currentValue = f.attribute( index ).toString();
4678 if ( !results.contains( currentValue ) )
4679 results << currentValue;
4680
4681 if ( ( limit >= 0 && results.size() >= limit ) || ( feedback && feedback->isCanceled() ) )
4682 {
4683 break;
4684 }
4685 }
4686
4687 return results;
4688 }
4689 }
4690
4691 Q_ASSERT_X( false, "QgsVectorLayer::uniqueStringsMatching()", "Unknown source of the field!" );
4692 return results;
4693}
4694
4695QVariant QgsVectorLayer::minimumValue( int index ) const
4696{
4698
4699 QVariant minimum;
4700 minimumOrMaximumValue( index, &minimum, nullptr );
4701 return minimum;
4702}
4703
4704QVariant QgsVectorLayer::maximumValue( int index ) const
4705{
4707
4708 QVariant maximum;
4709 minimumOrMaximumValue( index, nullptr, &maximum );
4710 return maximum;
4711}
4712
4713void QgsVectorLayer::minimumAndMaximumValue( int index, QVariant &minimum, QVariant &maximum ) const
4714{
4716
4717 minimumOrMaximumValue( index, &minimum, &maximum );
4718}
4719
4720void QgsVectorLayer::minimumOrMaximumValue( int index, QVariant *minimum, QVariant *maximum ) const
4721{
4723
4724 if ( minimum )
4725 *minimum = QVariant();
4726 if ( maximum )
4727 *maximum = QVariant();
4728
4729 if ( !mDataProvider )
4730 {
4731 return;
4732 }
4733
4734 QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
4735
4736 switch ( origin )
4737 {
4739 {
4740 return;
4741 }
4742
4743 case QgsFields::OriginProvider: //a provider field
4744 {
4745 if ( minimum )
4746 *minimum = mDataProvider->minimumValue( index );
4747 if ( maximum )
4748 *maximum = mDataProvider->maximumValue( index );
4749 if ( mEditBuffer && ! mDataProvider->transaction() )
4750 {
4751 const QgsFeatureMap added = mEditBuffer->addedFeatures();
4752 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4753 while ( addedIt.hasNext() )
4754 {
4755 addedIt.next();
4756 const QVariant v = addedIt.value().attribute( index );
4757 if ( minimum && v.isValid() && qgsVariantLessThan( v, *minimum ) )
4758 *minimum = v;
4759 if ( maximum && v.isValid() && qgsVariantGreaterThan( v, *maximum ) )
4760 *maximum = v;
4761 }
4762
4763 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4764 while ( it.hasNext() )
4765 {
4766 it.next();
4767 const QVariant v = it.value().value( index );
4768 if ( minimum && v.isValid() && qgsVariantLessThan( v, *minimum ) )
4769 *minimum = v;
4770 if ( maximum && v.isValid() && qgsVariantGreaterThan( v, *maximum ) )
4771 *maximum = v;
4772 }
4773 }
4774 return;
4775 }
4776
4778 {
4779 // the layer is editable, but in certain cases it can still be avoided going through all features
4780 if ( mDataProvider->transaction() || ( mEditBuffer->deletedFeatureIds().isEmpty() &&
4781 mEditBuffer->addedFeatures().isEmpty() &&
4782 !mEditBuffer->deletedAttributeIds().contains( index ) &&
4783 mEditBuffer->changedAttributeValues().isEmpty() ) )
4784 {
4785 if ( minimum )
4786 *minimum = mDataProvider->minimumValue( index );
4787 if ( maximum )
4788 *maximum = mDataProvider->maximumValue( index );
4789 return;
4790 }
4791 }
4792 [[fallthrough]];
4793 // no choice but to go through all features
4796 {
4797 // we need to go through each feature
4798 QgsAttributeList attList;
4799 attList << index;
4800
4803 .setSubsetOfAttributes( attList ) );
4804
4805 QgsFeature f;
4806 bool firstValue = true;
4807 while ( fit.nextFeature( f ) )
4808 {
4809 const QVariant currentValue = f.attribute( index );
4810 if ( QgsVariantUtils::isNull( currentValue ) )
4811 continue;
4812
4813 if ( firstValue )
4814 {
4815 if ( minimum )
4816 *minimum = currentValue;
4817 if ( maximum )
4818 *maximum = currentValue;
4819 firstValue = false;
4820 }
4821 else
4822 {
4823 if ( minimum && currentValue.isValid() && qgsVariantLessThan( currentValue, *minimum ) )
4824 *minimum = currentValue;
4825 if ( maximum && currentValue.isValid() && qgsVariantGreaterThan( currentValue, *maximum ) )
4826 *maximum = currentValue;
4827 }
4828 }
4829 return;
4830 }
4831 }
4832
4833 Q_ASSERT_X( false, "QgsVectorLayer::minimumOrMaximumValue()", "Unknown source of the field!" );
4834}
4835
4836void QgsVectorLayer::createEditBuffer()
4837{
4839
4840 if ( mEditBuffer )
4841 clearEditBuffer();
4842
4843 if ( mDataProvider->transaction() )
4844 {
4845 mEditBuffer = new QgsVectorLayerEditPassthrough( this );
4846
4847 connect( mDataProvider->transaction(), &QgsTransaction::dirtied, this, &QgsVectorLayer::onDirtyTransaction, Qt::UniqueConnection );
4848 }
4849 else
4850 {
4851 mEditBuffer = new QgsVectorLayerEditBuffer( this );
4852 }
4853 // forward signals
4854 connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::invalidateSymbolCountedFlag );
4855 connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::layerModified ); // TODO[MD]: necessary?
4856 //connect( mEditBuffer, SIGNAL( layerModified() ), this, SLOT( triggerRepaint() ) ); // TODO[MD]: works well?
4858 connect( mEditBuffer, &QgsVectorLayerEditBuffer::featureDeleted, this, &QgsVectorLayer::onFeatureDeleted );
4869
4870}
4871
4872void QgsVectorLayer::clearEditBuffer()
4873{
4875
4876 delete mEditBuffer;
4877 mEditBuffer = nullptr;
4878}
4879
4880QVariant QgsVectorLayer::aggregate( QgsAggregateCalculator::Aggregate aggregate, const QString &fieldOrExpression,
4882 bool *ok, QgsFeatureIds *fids, QgsFeedback *feedback, QString *error ) const
4883{
4884 // non fatal for now -- the aggregate expression functions are not thread safe and call this
4886
4887 if ( ok )
4888 *ok = false;
4889 if ( error )
4890 error->clear();
4891
4892 if ( !mDataProvider )
4893 {
4894 if ( error )
4895 *error = tr( "Layer is invalid" );
4896 return QVariant();
4897 }
4898
4899 // test if we are calculating based on a field
4900 const int attrIndex = QgsExpression::expressionToLayerFieldIndex( fieldOrExpression, this );
4901 if ( attrIndex >= 0 )
4902 {
4903 // aggregate is based on a field - if it's a provider field, we could possibly hand over the calculation
4904 // to the provider itself
4905 QgsFields::FieldOrigin origin = mFields.fieldOrigin( attrIndex );
4906 if ( origin == QgsFields::OriginProvider )
4907 {
4908 bool providerOk = false;
4909 QVariant val = mDataProvider->aggregate( aggregate, attrIndex, parameters, context, providerOk, fids );
4910 if ( providerOk )
4911 {
4912 // provider handled calculation
4913 if ( ok )
4914 *ok = true;
4915 return val;
4916 }
4917 }
4918 }
4919
4920 // fallback to using aggregate calculator to determine aggregate
4921 QgsAggregateCalculator c( this );
4922 if ( fids )
4923 c.setFidsFilter( *fids );
4924 c.setParameters( parameters );
4925 bool aggregateOk = false;
4926 const QVariant result = c.calculate( aggregate, fieldOrExpression, context, &aggregateOk, feedback );
4927 if ( ok )
4928 *ok = aggregateOk;
4929 if ( !aggregateOk && error )
4930 *error = c.lastError();
4931
4932 return result;
4933}
4934
4935void QgsVectorLayer::setFeatureBlendMode( QPainter::CompositionMode featureBlendMode )
4936{
4938
4939 if ( mFeatureBlendMode == featureBlendMode )
4940 return;
4941
4942 mFeatureBlendMode = featureBlendMode;
4945}
4946
4947QPainter::CompositionMode QgsVectorLayer::featureBlendMode() const
4948{
4949 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
4951
4952 return mFeatureBlendMode;
4953}
4954
4955void QgsVectorLayer::readSldLabeling( const QDomNode &node )
4956{
4958
4959 setLabeling( nullptr ); // start with no labeling
4960 setLabelsEnabled( false );
4961
4962 QDomElement element = node.toElement();
4963 if ( element.isNull() )
4964 return;
4965
4966 QDomElement userStyleElem = element.firstChildElement( QStringLiteral( "UserStyle" ) );
4967 if ( userStyleElem.isNull() )
4968 {
4969 QgsDebugMsgLevel( QStringLiteral( "Info: UserStyle element not found." ), 4 );
4970 return;
4971 }
4972
4973 QDomElement featTypeStyleElem = userStyleElem.firstChildElement( QStringLiteral( "FeatureTypeStyle" ) );
4974 if ( featTypeStyleElem.isNull() )
4975 {
4976 QgsDebugMsgLevel( QStringLiteral( "Info: FeatureTypeStyle element not found." ), 4 );
4977 return;
4978 }
4979
4980 // create empty FeatureTypeStyle element to merge TextSymbolizer's Rule's from all FeatureTypeStyle's
4981 QDomElement mergedFeatTypeStyle = featTypeStyleElem.cloneNode( false ).toElement();
4982
4983 // use the RuleRenderer when more rules are present or the rule
4984 // has filters or min/max scale denominators set,
4985 // otherwise use the Simple labeling
4986 bool needRuleBasedLabeling = false;
4987 int ruleCount = 0;
4988
4989 while ( !featTypeStyleElem.isNull() )
4990 {
4991 QDomElement ruleElem = featTypeStyleElem.firstChildElement( QStringLiteral( "Rule" ) );
4992 while ( !ruleElem.isNull() )
4993 {
4994 // test rule children element to check if we need to create RuleRenderer
4995 // and if the rule has a symbolizer
4996 bool hasTextSymbolizer = false;
4997 bool hasRuleBased = false;
4998 QDomElement ruleChildElem = ruleElem.firstChildElement();
4999 while ( !ruleChildElem.isNull() )
5000 {
5001 // rule has filter or min/max scale denominator, use the RuleRenderer
5002 if ( ruleChildElem.localName() == QLatin1String( "Filter" ) ||
5003 ruleChildElem.localName() == QLatin1String( "MinScaleDenominator" ) ||
5004 ruleChildElem.localName() == QLatin1String( "MaxScaleDenominator" ) )
5005 {
5006 hasRuleBased = true;
5007 }
5008 // rule has a renderer symbolizer, not a text symbolizer
5009 else if ( ruleChildElem.localName() == QLatin1String( "TextSymbolizer" ) )
5010 {
5011 QgsDebugMsgLevel( QStringLiteral( "Info: TextSymbolizer element found" ), 4 );
5012 hasTextSymbolizer = true;
5013 }
5014
5015 ruleChildElem = ruleChildElem.nextSiblingElement();
5016 }
5017
5018 if ( hasTextSymbolizer )
5019 {
5020 ruleCount++;
5021
5022 // append a clone of all Rules to the merged FeatureTypeStyle element
5023 mergedFeatTypeStyle.appendChild( ruleElem.cloneNode().toElement() );
5024
5025 if ( hasRuleBased )
5026 {
5027 QgsDebugMsgLevel( QStringLiteral( "Info: Filter or Min/MaxScaleDenominator element found: need a RuleBasedLabeling" ), 4 );
5028 needRuleBasedLabeling = true;
5029 }
5030 }
5031
5032 // more rules present, use the RuleRenderer
5033 if ( ruleCount > 1 )
5034 {
5035 QgsDebugMsgLevel( QStringLiteral( "Info: More Rule elements found: need a RuleBasedLabeling" ), 4 );
5036 needRuleBasedLabeling = true;
5037 }
5038
5039 // not use the rule based labeling if no rules with textSymbolizer
5040 if ( ruleCount == 0 )
5041 {
5042 needRuleBasedLabeling = false;
5043 }
5044
5045 ruleElem = ruleElem.nextSiblingElement( QStringLiteral( "Rule" ) );
5046 }
5047 featTypeStyleElem = featTypeStyleElem.nextSiblingElement( QStringLiteral( "FeatureTypeStyle" ) );
5048 }
5049
5050 if ( ruleCount == 0 )
5051 {
5052 QgsDebugMsgLevel( QStringLiteral( "Info: No TextSymbolizer element." ), 4 );
5053 return;
5054 }
5055
5056 QDomElement ruleElem = mergedFeatTypeStyle.firstChildElement( QStringLiteral( "Rule" ) );
5057
5058 if ( needRuleBasedLabeling )
5059 {
5060 QgsDebugMsgLevel( QStringLiteral( "Info: rule based labeling" ), 4 );
5061 QgsRuleBasedLabeling::Rule *rootRule = new QgsRuleBasedLabeling::Rule( nullptr );
5062 while ( !ruleElem.isNull() )
5063 {
5064
5065 QString label, description, filterExp;
5066 int scaleMinDenom = 0, scaleMaxDenom = 0;
5067 QgsPalLayerSettings settings;
5068
5069 // retrieve the Rule element child nodes
5070 QDomElement childElem = ruleElem.firstChildElement();
5071 while ( !childElem.isNull() )
5072 {
5073 if ( childElem.localName() == QLatin1String( "Name" ) )
5074 {
5075 // <se:Name> tag contains the rule identifier,
5076 // so prefer title tag for the label property value
5077 if ( label.isEmpty() )
5078 label = childElem.firstChild().nodeValue();
5079 }
5080 else if ( childElem.localName() == QLatin1String( "Description" ) )
5081 {
5082 // <se:Description> can contains a title and an abstract
5083 QDomElement titleElem = childElem.firstChildElement( QStringLiteral( "Title" ) );
5084 if ( !titleElem.isNull() )
5085 {
5086 label = titleElem.firstChild().nodeValue();
5087 }
5088
5089 QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( "Abstract" ) );
5090 if ( !abstractElem.isNull() )
5091 {
5092 description = abstractElem.firstChild().nodeValue();
5093 }
5094 }
5095 else if ( childElem.localName() == QLatin1String( "Abstract" ) )
5096 {
5097 // <sld:Abstract> (v1.0)
5098 description = childElem.firstChild().nodeValue();
5099 }
5100 else if ( childElem.localName() == QLatin1String( "Title" ) )
5101 {
5102 // <sld:Title> (v1.0)
5103 label = childElem.firstChild().nodeValue();
5104 }
5105 else if ( childElem.localName() == QLatin1String( "Filter" ) )
5106 {
5108 if ( filter )
5109 {
5110 if ( filter->hasParserError() )
5111 {
5112 QgsDebugMsgLevel( QStringLiteral( "SLD Filter parsing error: %1" ).arg( filter->parserErrorString() ), 3 );
5113 }
5114 else
5115 {
5116 filterExp = filter->expression();
5117 }
5118 delete filter;
5119 }
5120 }
5121 else if ( childElem.localName() == QLatin1String( "MinScaleDenominator" ) )
5122 {
5123 bool ok;
5124 int v = childElem.firstChild().nodeValue().toInt( &ok );
5125 if ( ok )
5126 scaleMinDenom = v;
5127 }
5128 else if ( childElem.localName() == QLatin1String( "MaxScaleDenominator" ) )
5129 {
5130 bool ok;
5131 int v = childElem.firstChild().nodeValue().toInt( &ok );
5132 if ( ok )
5133 scaleMaxDenom = v;
5134 }
5135 else if ( childElem.localName() == QLatin1String( "TextSymbolizer" ) )
5136 {
5137 readSldTextSymbolizer( childElem, settings );
5138 }
5139
5140 childElem = childElem.nextSiblingElement();
5141 }
5142
5143 QgsRuleBasedLabeling::Rule *ruleLabeling = new QgsRuleBasedLabeling::Rule( new QgsPalLayerSettings( settings ), scaleMinDenom, scaleMaxDenom, filterExp, label );
5144 rootRule->appendChild( ruleLabeling );
5145
5146 ruleElem = ruleElem.nextSiblingElement();
5147 }
5148
5149 setLabeling( new QgsRuleBasedLabeling( rootRule ) );
5150 setLabelsEnabled( true );
5151 }
5152 else
5153 {
5154 QgsDebugMsgLevel( QStringLiteral( "Info: simple labeling" ), 4 );
5155 // retrieve the TextSymbolizer element child node
5156 QDomElement textSymbolizerElem = ruleElem.firstChildElement( QStringLiteral( "TextSymbolizer" ) );
5158 if ( readSldTextSymbolizer( textSymbolizerElem, s ) )
5159 {
5161 setLabelsEnabled( true );
5162 }
5163 }
5164}
5165
5166bool QgsVectorLayer::readSldTextSymbolizer( const QDomNode &node, QgsPalLayerSettings &settings ) const
5167{
5169
5170 if ( node.localName() != QLatin1String( "TextSymbolizer" ) )
5171 {
5172 QgsDebugMsgLevel( QStringLiteral( "Not a TextSymbolizer element: %1" ).arg( node.localName() ), 3 );
5173 return false;
5174 }
5175 QDomElement textSymbolizerElem = node.toElement();
5176 // Label
5177 QDomElement labelElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Label" ) );
5178 if ( !labelElem.isNull() )
5179 {
5180 QDomElement propertyNameElem = labelElem.firstChildElement( QStringLiteral( "PropertyName" ) );
5181 if ( !propertyNameElem.isNull() )
5182 {
5183 // set labeling defaults
5184
5185 // label attribute
5186 QString labelAttribute = propertyNameElem.text();
5187 settings.fieldName = labelAttribute;
5188 settings.isExpression = false;
5189
5190 int fieldIndex = mFields.lookupField( labelAttribute );
5191 if ( fieldIndex == -1 )
5192 {
5193 // label attribute is not in columns, check if it is an expression
5194 QgsExpression exp( labelAttribute );
5195 if ( !exp.hasEvalError() )
5196 {
5197 settings.isExpression = true;
5198 }
5199 else
5200 {
5201 QgsDebugMsgLevel( QStringLiteral( "SLD label attribute error: %1" ).arg( exp.evalErrorString() ), 3 );
5202 }
5203 }
5204 }
5205 else
5206 {
5207 QgsDebugMsgLevel( QStringLiteral( "Info: PropertyName element not found." ), 4 );
5208 return false;
5209 }
5210 }
5211 else
5212 {
5213 QgsDebugMsgLevel( QStringLiteral( "Info: Label element not found." ), 4 );
5214 return false;
5215 }
5216
5218 if ( textSymbolizerElem.hasAttribute( QStringLiteral( "uom" ) ) )
5219 {
5220 sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( textSymbolizerElem.attribute( QStringLiteral( "uom" ) ) );
5221 }
5222
5223 QString fontFamily = QStringLiteral( "Sans-Serif" );
5224 int fontPointSize = 10;
5226 int fontWeight = -1;
5227 bool fontItalic = false;
5228 bool fontUnderline = false;
5229
5230 // Font
5231 QDomElement fontElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Font" ) );
5232 if ( !fontElem.isNull() )
5233 {
5234 QgsStringMap fontSvgParams = QgsSymbolLayerUtils::getSvgParameterList( fontElem );
5235 for ( QgsStringMap::iterator it = fontSvgParams.begin(); it != fontSvgParams.end(); ++it )
5236 {
5237 QgsDebugMsgLevel( QStringLiteral( "found fontSvgParams %1: %2" ).arg( it.key(), it.value() ), 4 );
5238
5239 if ( it.key() == QLatin1String( "font-family" ) )
5240 {
5241 fontFamily = it.value();
5242 }
5243 else if ( it.key() == QLatin1String( "font-style" ) )
5244 {
5245 fontItalic = ( it.value() == QLatin1String( "italic" ) ) || ( it.value() == QLatin1String( "Italic" ) );
5246 }
5247 else if ( it.key() == QLatin1String( "font-size" ) )
5248 {
5249 bool ok;
5250 int fontSize = it.value().toInt( &ok );
5251 if ( ok )
5252 {
5253 fontPointSize = fontSize;
5254 fontUnitSize = sldUnitSize;
5255 }
5256 }
5257 else if ( it.key() == QLatin1String( "font-weight" ) )
5258 {
5259 if ( ( it.value() == QLatin1String( "bold" ) ) || ( it.value() == QLatin1String( "Bold" ) ) )
5260 fontWeight = QFont::Bold;
5261 }
5262 else if ( it.key() == QLatin1String( "font-underline" ) )
5263 {
5264 fontUnderline = ( it.value() == QLatin1String( "underline" ) ) || ( it.value() == QLatin1String( "Underline" ) );
5265 }
5266 }
5267 }
5268
5269 QgsTextFormat format;
5270 QFont font( fontFamily, fontPointSize, fontWeight, fontItalic );
5271 font.setUnderline( fontUnderline );
5272 format.setFont( font );
5273 format.setSize( fontPointSize );
5274 format.setSizeUnit( fontUnitSize );
5275
5276 // Fill
5277 QDomElement fillElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Fill" ) );
5278 QColor textColor;
5279 Qt::BrushStyle textBrush = Qt::SolidPattern;
5280 QgsSymbolLayerUtils::fillFromSld( fillElem, textBrush, textColor );
5281 if ( textColor.isValid() )
5282 {
5283 QgsDebugMsgLevel( QStringLiteral( "Info: textColor %1." ).arg( QVariant( textColor ).toString() ), 4 );
5284 format.setColor( textColor );
5285 }
5286
5287 QgsTextBufferSettings bufferSettings;
5288
5289 // Halo
5290 QDomElement haloElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Halo" ) );
5291 if ( !haloElem.isNull() )
5292 {
5293 bufferSettings.setEnabled( true );
5294 bufferSettings.setSize( 1 );
5295
5296 QDomElement radiusElem = haloElem.firstChildElement( QStringLiteral( "Radius" ) );
5297 if ( !radiusElem.isNull() )
5298 {
5299 bool ok;
5300 double bufferSize = radiusElem.text().toDouble( &ok );
5301 if ( ok )
5302 {
5303 bufferSettings.setSize( bufferSize );
5304 bufferSettings.setSizeUnit( sldUnitSize );
5305 }
5306 }
5307
5308 QDomElement haloFillElem = haloElem.firstChildElement( QStringLiteral( "Fill" ) );
5309 QColor bufferColor;
5310 Qt::BrushStyle bufferBrush = Qt::SolidPattern;
5311 QgsSymbolLayerUtils::fillFromSld( haloFillElem, bufferBrush, bufferColor );
5312 if ( bufferColor.isValid() )
5313 {
5314 QgsDebugMsgLevel( QStringLiteral( "Info: bufferColor %1." ).arg( QVariant( bufferColor ).toString() ), 4 );
5315 bufferSettings.setColor( bufferColor );
5316 }
5317 }
5318
5319 // LabelPlacement
5320 QDomElement labelPlacementElem = textSymbolizerElem.firstChildElement( QStringLiteral( "LabelPlacement" ) );
5321 if ( !labelPlacementElem.isNull() )
5322 {
5323 // PointPlacement
5324 QDomElement pointPlacementElem = labelPlacementElem.firstChildElement( QStringLiteral( "PointPlacement" ) );
5325 if ( !pointPlacementElem.isNull() )
5326 {
5329 {
5331 }
5332
5333 QDomElement displacementElem = pointPlacementElem.firstChildElement( QStringLiteral( "Displacement" ) );
5334 if ( !displacementElem.isNull() )
5335 {
5336 QDomElement displacementXElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementX" ) );
5337 if ( !displacementXElem.isNull() )
5338 {
5339 bool ok;
5340 double xOffset = displacementXElem.text().toDouble( &ok );
5341 if ( ok )
5342 {
5343 settings.xOffset = xOffset;
5344 settings.offsetUnits = sldUnitSize;
5345 }
5346 }
5347 QDomElement displacementYElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementY" ) );
5348 if ( !displacementYElem.isNull() )
5349 {
5350 bool ok;
5351 double yOffset = displacementYElem.text().toDouble( &ok );
5352 if ( ok )
5353 {
5354 settings.yOffset = yOffset;
5355 settings.offsetUnits = sldUnitSize;
5356 }
5357 }
5358 }
5359 QDomElement anchorPointElem = pointPlacementElem.firstChildElement( QStringLiteral( "AnchorPoint" ) );
5360 if ( !anchorPointElem.isNull() )
5361 {
5362 QDomElement anchorPointXElem = anchorPointElem.firstChildElement( QStringLiteral( "AnchorPointX" ) );
5363 if ( !anchorPointXElem.isNull() )
5364 {
5365 bool ok;
5366 double xOffset = anchorPointXElem.text().toDouble( &ok );
5367 if ( ok )
5368 {
5369 settings.xOffset = xOffset;
5370 settings.offsetUnits = sldUnitSize;
5371 }
5372 }
5373 QDomElement anchorPointYElem = anchorPointElem.firstChildElement( QStringLiteral( "AnchorPointY" ) );
5374 if ( !anchorPointYElem.isNull() )
5375 {
5376 bool ok;
5377 double yOffset = anchorPointYElem.text().toDouble( &ok );
5378 if ( ok )
5379 {
5380 settings.yOffset = yOffset;
5381 settings.offsetUnits = sldUnitSize;
5382 }
5383 }
5384 }
5385
5386 QDomElement rotationElem = pointPlacementElem.firstChildElement( QStringLiteral( "Rotation" ) );
5387 if ( !rotationElem.isNull() )
5388 {
5389 bool ok;
5390 double rotation = rotationElem.text().toDouble( &ok );
5391 if ( ok )
5392 {
5393 settings.angleOffset = 360 - rotation;
5394 }
5395 }
5396 }
5397 else
5398 {
5399 // PointPlacement
5400 QDomElement linePlacementElem = labelPlacementElem.firstChildElement( QStringLiteral( "LinePlacement" ) );
5401 if ( !linePlacementElem.isNull() )
5402 {
5404 }
5405 }
5406 }
5407
5408 // read vendor options
5409 QgsStringMap vendorOptions;
5410 QDomElement vendorOptionElem = textSymbolizerElem.firstChildElement( QStringLiteral( "VendorOption" ) );
5411 while ( !vendorOptionElem.isNull() && vendorOptionElem.localName() == QLatin1String( "VendorOption" ) )
5412 {
5413 QString optionName = vendorOptionElem.attribute( QStringLiteral( "name" ) );
5414 QString optionValue;
5415 if ( vendorOptionElem.firstChild().nodeType() == QDomNode::TextNode )
5416 {
5417 optionValue = vendorOptionElem.firstChild().nodeValue();
5418 }
5419 else
5420 {
5421 if ( vendorOptionElem.firstChild().nodeType() == QDomNode::ElementNode &&
5422 vendorOptionElem.firstChild().localName() == QLatin1String( "Literal" ) )
5423 {
5424 QgsDebugMsgLevel( vendorOptionElem.firstChild().localName(), 2 );
5425 optionValue = vendorOptionElem.firstChild().firstChild().nodeValue();
5426 }
5427 else
5428 {
5429 QgsDebugError( QStringLiteral( "unexpected child of %1 named %2" ).arg( vendorOptionElem.localName(), optionName ) );
5430 }
5431 }
5432
5433 if ( !optionName.isEmpty() && !optionValue.isEmpty() )
5434 {
5435 vendorOptions[ optionName ] = optionValue;
5436 }
5437
5438 vendorOptionElem = vendorOptionElem.nextSiblingElement();
5439 }
5440 if ( !vendorOptions.isEmpty() )
5441 {
5442 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
5443 {
5444 if ( it.key() == QLatin1String( "underlineText" ) && it.value() == QLatin1String( "true" ) )
5445 {
5446 font.setUnderline( true );
5447 format.setFont( font );
5448 }
5449 else if ( it.key() == QLatin1String( "strikethroughText" ) && it.value() == QLatin1String( "true" ) )
5450 {
5451 font.setStrikeOut( true );
5452 format.setFont( font );
5453 }
5454 else if ( it.key() == QLatin1String( "maxDisplacement" ) )
5455 {
5457 }
5458 else if ( it.key() == QLatin1String( "followLine" ) && it.value() == QLatin1String( "true" ) )
5459 {
5461 {
5463 }
5464 else
5465 {
5467 }
5468 }
5469 else if ( it.key() == QLatin1String( "maxAngleDelta" ) )
5470 {
5471 bool ok;
5472 double angle = it.value().toDouble( &ok );
5473 if ( ok )
5474 {
5475 settings.maxCurvedCharAngleIn = angle;
5476 settings.maxCurvedCharAngleOut = angle;
5477 }
5478 }
5479 // miscellaneous options
5480 else if ( it.key() == QLatin1String( "conflictResolution" ) && it.value() == QLatin1String( "false" ) )
5481 {
5483 }
5484 else if ( it.key() == QLatin1String( "forceLeftToRight" ) && it.value() == QLatin1String( "false" ) )
5485 {
5487 }
5488 else if ( it.key() == QLatin1String( "group" ) && it.value() == QLatin1String( "yes" ) )
5489 {
5490 settings.lineSettings().setMergeLines( true );
5491 }
5492 else if ( it.key() == QLatin1String( "labelAllGroup" ) && it.value() == QLatin1String( "true" ) )
5493 {
5494 settings.lineSettings().setMergeLines( true );
5495 }
5496 }
5497 }
5498
5499 format.setBuffer( bufferSettings );
5500 settings.setFormat( format );
5501 return true;
5502}
5503
5505{
5507
5508 return mEditFormConfig;
5509}
5510
5512{
5514
5515 if ( mEditFormConfig == editFormConfig )
5516 return;
5517
5518 mEditFormConfig = editFormConfig;
5519 mEditFormConfig.onRelationsLoaded();
5520 emit editFormConfigChanged();
5521}
5522
5524{
5526
5527 QgsAttributeTableConfig config = mAttributeTableConfig;
5528
5529 if ( config.isEmpty() )
5530 config.update( fields() );
5531
5532 return config;
5533}
5534
5536{
5538
5539 if ( mAttributeTableConfig != attributeTableConfig )
5540 {
5541 mAttributeTableConfig = attributeTableConfig;
5542 emit configChanged();
5543 }
5544}
5545
5547{
5548 // called in a non-thread-safe way in some cases when calculating aggregates in a different thread
5550
5552}
5553
5560
5562{
5564
5565 if ( !mDiagramLayerSettings )
5566 mDiagramLayerSettings = new QgsDiagramLayerSettings();
5567 *mDiagramLayerSettings = s;
5568}
5569
5571{
5573
5574 QgsLayerMetadataFormatter htmlFormatter( metadata() );
5575 QString myMetadata = QStringLiteral( "<html><head></head>\n<body>\n" );
5576
5577 myMetadata += generalHtmlMetadata();
5578
5579 // Begin Provider section
5580 myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
5581 myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
5582
5583 // storage type
5584 if ( !storageType().isEmpty() )
5585 {
5586 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Storage" ) + QStringLiteral( "</td><td>" ) + storageType() + QStringLiteral( "</td></tr>\n" );
5587 }
5588
5589 // comment
5590 if ( !dataComment().isEmpty() )
5591 {
5592 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Comment" ) + QStringLiteral( "</td><td>" ) + dataComment() + QStringLiteral( "</td></tr>\n" );
5593 }
5594
5595 // encoding
5596 const QgsVectorDataProvider *provider = dataProvider();
5597 if ( provider )
5598 {
5599 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Encoding" ) + QStringLiteral( "</td><td>" ) + provider->encoding() + QStringLiteral( "</td></tr>\n" );
5600 }
5601
5602 if ( isSpatial() )
5603 {
5604 // geom type
5606 if ( static_cast<int>( type ) < 0 || static_cast< int >( type ) > static_cast< int >( Qgis::GeometryType::Null ) )
5607 {
5608 QgsDebugMsgLevel( QStringLiteral( "Invalid vector type" ), 2 );
5609 }
5610 else
5611 {
5612 QString typeString( QStringLiteral( "%1 (%2)" ).arg( QgsWkbTypes::geometryDisplayString( geometryType() ),
5614 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Geometry" ) + QStringLiteral( "</td><td>" ) + typeString + QStringLiteral( "</td></tr>\n" );
5615 }
5616
5617 // Extent
5618 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
5619 }
5620
5621 // feature count
5622 QLocale locale = QLocale();
5623 locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
5624 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
5625 + tr( "Feature count" ) + QStringLiteral( "</td><td>" )
5626 + ( featureCount() == -1 ? tr( "unknown" ) : locale.toString( static_cast<qlonglong>( featureCount() ) ) )
5627 + QStringLiteral( "</td></tr>\n" );
5628
5629 // End Provider section
5630 myMetadata += QLatin1String( "</table>\n<br><br>" );
5631
5632 if ( isSpatial() )
5633 {
5634 // CRS
5635 myMetadata += crsHtmlMetadata();
5636 }
5637
5638 // identification section
5639 myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
5640 myMetadata += htmlFormatter.identificationSectionHtml( );
5641 myMetadata += QLatin1String( "<br><br>\n" );
5642
5643 // extent section
5644 myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
5645 myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
5646 myMetadata += QLatin1String( "<br><br>\n" );
5647
5648 // Start the Access section
5649 myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
5650 myMetadata += htmlFormatter.accessSectionHtml( );
5651 myMetadata += QLatin1String( "<br><br>\n" );
5652
5653 // Fields section
5654 myMetadata += QStringLiteral( "<h1>" ) + tr( "Fields" ) + QStringLiteral( "</h1>\n<hr>\n<table class=\"list-view\">\n" );
5655
5656 // primary key
5658 if ( !pkAttrList.isEmpty() )
5659 {
5660 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Primary key attributes" ) + QStringLiteral( "</td><td>" );
5661 const auto constPkAttrList = pkAttrList;
5662 for ( int idx : constPkAttrList )
5663 {
5664 myMetadata += fields().at( idx ).name() + ' ';
5665 }
5666 myMetadata += QLatin1String( "</td></tr>\n" );
5667 }
5668
5669 const QgsFields myFields = fields();
5670
5671 // count fields
5672 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Count" ) + QStringLiteral( "</td><td>" ) + QString::number( myFields.size() ) + QStringLiteral( "</td></tr>\n" );
5673
5674 myMetadata += QLatin1String( "</table>\n<br><table width=\"100%\" class=\"tabular-view\">\n" );
5675 myMetadata += QLatin1String( "<tr><th>" ) + tr( "Field" ) + QLatin1String( "</th><th>" ) + tr( "Type" ) + QLatin1String( "</th><th>" ) + tr( "Length" ) + QLatin1String( "</th><th>" ) + tr( "Precision" ) + QLatin1String( "</th><th>" ) + tr( "Comment" ) + QLatin1String( "</th></tr>\n" );
5676
5677 for ( int i = 0; i < myFields.size(); ++i )
5678 {
5679 QgsField myField = myFields.at( i );
5680 QString rowClass;
5681 if ( i % 2 )
5682 rowClass = QStringLiteral( "class=\"odd-row\"" );
5683 myMetadata += QLatin1String( "<tr " ) + rowClass + QLatin1String( "><td>" ) + myField.displayNameWithAlias() + QLatin1String( "</td><td>" ) + myField.typeName() + QLatin1String( "</td><td>" ) + QString::number( myField.length() ) + QLatin1String( "</td><td>" ) + QString::number( myField.precision() ) + QLatin1String( "</td><td>" ) + myField.comment() + QLatin1String( "</td></tr>\n" );
5684 }
5685
5686 //close field list
5687 myMetadata += QLatin1String( "</table>\n<br><br>" );
5688
5689 // Start the contacts section
5690 myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
5691 myMetadata += htmlFormatter.contactsSectionHtml( );
5692 myMetadata += QLatin1String( "<br><br>\n" );
5693
5694 // Start the links section
5695 myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
5696 myMetadata += htmlFormatter.linksSectionHtml( );
5697 myMetadata += QLatin1String( "<br><br>\n" );
5698
5699 // Start the history section
5700 myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
5701 myMetadata += htmlFormatter.historySectionHtml( );
5702 myMetadata += QLatin1String( "<br><br>\n" );
5703
5704 myMetadata += QLatin1String( "\n</body>\n</html>\n" );
5705 return myMetadata;
5706}
5707
5708void QgsVectorLayer::invalidateSymbolCountedFlag()
5709{
5711
5712 mSymbolFeatureCounted = false;
5713}
5714
5715void QgsVectorLayer::onFeatureCounterCompleted()
5716{
5718
5719 onSymbolsCounted();
5720 mFeatureCounter = nullptr;
5721}
5722
5723void QgsVectorLayer::onFeatureCounterTerminated()
5724{
5726
5727 mFeatureCounter = nullptr;
5728}
5729
5730void QgsVectorLayer::onJoinedFieldsChanged()
5731{
5733
5734 // some of the fields of joined layers have changed -> we need to update this layer's fields too
5735 updateFields();
5736}
5737
5738void QgsVectorLayer::onFeatureDeleted( QgsFeatureId fid )
5739{
5741
5742 if ( mEditCommandActive || mCommitChangesActive )
5743 {
5744 mDeletedFids << fid;
5745 }
5746 else
5747 {
5748 mSelectedFeatureIds.remove( fid );
5749 emit featuresDeleted( QgsFeatureIds() << fid );
5750 }
5751
5752 emit featureDeleted( fid );
5753}
5754
5755void QgsVectorLayer::onRelationsLoaded()
5756{
5758
5759 mEditFormConfig.onRelationsLoaded();
5760}
5761
5762void QgsVectorLayer::onSymbolsCounted()
5763{
5765
5766 if ( mFeatureCounter )
5767 {
5768 mSymbolFeatureCounted = true;
5769 mSymbolFeatureCountMap = mFeatureCounter->symbolFeatureCountMap();
5770 mSymbolFeatureIdMap = mFeatureCounter->symbolFeatureIdMap();
5772 }
5773}
5774
5775QList<QgsRelation> QgsVectorLayer::referencingRelations( int idx ) const
5776{
5778
5780}
5781
5782QList<QgsWeakRelation> QgsVectorLayer::weakRelations() const
5783{
5785
5786 return mWeakRelations;
5787}
5788
5789void QgsVectorLayer::setWeakRelations( const QList<QgsWeakRelation> &relations )
5790{
5792
5793 mWeakRelations = relations;
5794}
5795
5796bool QgsVectorLayer::loadAuxiliaryLayer( const QgsAuxiliaryStorage &storage, const QString &key )
5797{
5799
5800 bool rc = false;
5801
5802 QString joinKey = mAuxiliaryLayerKey;
5803 if ( !key.isEmpty() )
5804 joinKey = key;
5805
5806 if ( storage.isValid() && !joinKey.isEmpty() )
5807 {
5808 QgsAuxiliaryLayer *alayer = nullptr;
5809
5810 int idx = fields().lookupField( joinKey );
5811
5812 if ( idx >= 0 )
5813 {
5814 alayer = storage.createAuxiliaryLayer( fields().field( idx ), this );
5815
5816 if ( alayer )
5817 {
5818 setAuxiliaryLayer( alayer );
5819 rc = true;
5820 }
5821 }
5822 }
5823
5824 return rc;
5825}
5826
5828{
5830
5831 mAuxiliaryLayerKey.clear();
5832
5833 if ( mAuxiliaryLayer )
5834 removeJoin( mAuxiliaryLayer->id() );
5835
5836 if ( alayer )
5837 {
5838 addJoin( alayer->joinInfo() );
5839
5840 if ( !alayer->isEditable() )
5841 alayer->startEditing();
5842
5843 mAuxiliaryLayerKey = alayer->joinInfo().targetFieldName();
5844 }
5845
5846 mAuxiliaryLayer.reset( alayer );
5847 if ( mAuxiliaryLayer )
5848 mAuxiliaryLayer->setParent( this );
5849 updateFields();
5850}
5851
5853{
5855
5856 return mAuxiliaryLayer.get();
5857}
5858
5860{
5862
5863 return mAuxiliaryLayer.get();
5864}
5865
5866QSet<QgsMapLayerDependency> QgsVectorLayer::dependencies() const
5867{
5869
5870 if ( mDataProvider )
5871 return mDataProvider->dependencies() + mDependencies;
5872 return mDependencies;
5873}
5874
5875void QgsVectorLayer::emitDataChanged()
5876{
5878
5879 if ( mDataChangedFired )
5880 return;
5881
5882 updateExtents(); // reset cached extent to reflect data changes
5883
5884 mDataChangedFired = true;
5885 emit dataChanged();
5886 mDataChangedFired = false;
5887}
5888
5889void QgsVectorLayer::onAfterCommitChangesDependency()
5890{
5892
5893 mDataChangedFired = true;
5894 reload();
5895 mDataChangedFired = false;
5896}
5897
5898bool QgsVectorLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
5899{
5901
5902 QSet<QgsMapLayerDependency> deps;
5903 const auto constODeps = oDeps;
5904 for ( const QgsMapLayerDependency &dep : constODeps )
5905 {
5906 if ( dep.origin() == QgsMapLayerDependency::FromUser )
5907 deps << dep;
5908 }
5909
5910 QSet<QgsMapLayerDependency> toAdd = deps - dependencies();
5911
5912 // disconnect layers that are not present in the list of dependencies anymore
5913 for ( const QgsMapLayerDependency &dep : std::as_const( mDependencies ) )
5914 {
5915 QgsVectorLayer *lyr = static_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( dep.layerId() ) );
5916 if ( !lyr )
5917 continue;
5918 disconnect( lyr, &QgsVectorLayer::featureAdded, this, &QgsVectorLayer::emitDataChanged );
5919 disconnect( lyr, &QgsVectorLayer::featureDeleted, this, &QgsVectorLayer::emitDataChanged );
5920 disconnect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
5921 disconnect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );
5923 disconnect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::onAfterCommitChangesDependency );
5924 }
5925
5926 // assign new dependencies
5927 if ( mDataProvider )
5928 mDependencies = mDataProvider->dependencies() + deps;
5929 else
5930 mDependencies = deps;
5931 emit dependenciesChanged();
5932
5933 // connect to new layers
5934 for ( const QgsMapLayerDependency &dep : std::as_const( mDependencies ) )
5935 {
5936 QgsVectorLayer *lyr = static_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( dep.layerId() ) );
5937 if ( !lyr )
5938 continue;
5939 connect( lyr, &QgsVectorLayer::featureAdded, this, &QgsVectorLayer::emitDataChanged );
5940 connect( lyr, &QgsVectorLayer::featureDeleted, this, &QgsVectorLayer::emitDataChanged );
5941 connect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
5942 connect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );
5944 connect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::onAfterCommitChangesDependency );
5945 }
5946
5947 // if new layers are present, emit a data change
5948 if ( ! toAdd.isEmpty() )
5949 emitDataChanged();
5950
5951 return true;
5952}
5953
5954QgsFieldConstraints::Constraints QgsVectorLayer::fieldConstraints( int fieldIndex ) const
5955{
5957
5958 if ( fieldIndex < 0 || fieldIndex >= mFields.count() || !mDataProvider )
5959 return QgsFieldConstraints::Constraints();
5960
5961 QgsFieldConstraints::Constraints constraints = mFields.at( fieldIndex ).constraints().constraints();
5962
5963 // make sure provider constraints are always present!
5964 if ( mFields.fieldOrigin( fieldIndex ) == QgsFields::OriginProvider )
5965 {
5966 constraints |= mDataProvider->fieldConstraints( mFields.fieldOriginIndex( fieldIndex ) );
5967 }
5968
5969 return constraints;
5970}
5971
5972QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength> QgsVectorLayer::fieldConstraintsAndStrength( int fieldIndex ) const
5973{
5975
5976 QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength > m;
5977
5978 if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
5979 return m;
5980
5981 QString name = mFields.at( fieldIndex ).name();
5982
5983 QMap< QPair< QString, QgsFieldConstraints::Constraint >, QgsFieldConstraints::ConstraintStrength >::const_iterator conIt = mFieldConstraintStrength.constBegin();
5984 for ( ; conIt != mFieldConstraintStrength.constEnd(); ++conIt )
5985 {
5986 if ( conIt.key().first == name )
5987 {
5988 m[ conIt.key().second ] = mFieldConstraintStrength.value( conIt.key() );
5989 }
5990 }
5991
5992 return m;
5993}
5994
5996{
5998
5999 if ( index < 0 || index >= mFields.count() )
6000 return;
6001
6002 QString name = mFields.at( index ).name();
6003
6004 // add constraint to existing constraints
6005 QgsFieldConstraints::Constraints constraints = mFieldConstraints.value( name, QgsFieldConstraints::Constraints() );
6006 constraints |= constraint;
6007 mFieldConstraints.insert( name, constraints );
6008
6009 mFieldConstraintStrength.insert( qMakePair( name, constraint ), strength );
6010
6011 updateFields();
6012}
6013
6015{
6017
6018 if ( index < 0 || index >= mFields.count() )
6019 return;
6020
6021 QString name = mFields.at( index ).name();
6022
6023 // remove constraint from existing constraints
6024 QgsFieldConstraints::Constraints constraints = mFieldConstraints.value( name, QgsFieldConstraints::Constraints() );
6025 constraints &= ~constraint;
6026 mFieldConstraints.insert( name, constraints );
6027
6028 mFieldConstraintStrength.remove( qMakePair( name, constraint ) );
6029
6030 updateFields();
6031}
6032
6034{
6036
6037 if ( index < 0 || index >= mFields.count() )
6038 return QString();
6039
6040 return mFields.at( index ).constraints().constraintExpression();
6041}
6042
6044{
6046
6047 if ( index < 0 || index >= mFields.count() )
6048 return QString();
6049
6050 return mFields.at( index ).constraints().constraintDescription();
6051}
6052
6053void QgsVectorLayer::setConstraintExpression( int index, const QString &expression, const QString &description )
6054{
6056
6057 if ( index < 0 || index >= mFields.count() )
6058 return;
6059
6060 if ( expression.isEmpty() )
6061 {
6062 mFieldConstraintExpressions.remove( mFields.at( index ).name() );
6063 }
6064 else
6065 {
6066 mFieldConstraintExpressions.insert( mFields.at( index ).name(), qMakePair( expression, description ) );
6067 }
6068 updateFields();
6069}
6070
6071void QgsVectorLayer::setFieldConfigurationFlags( int index, Qgis::FieldConfigurationFlags flags )
6072{
6074
6075 if ( index < 0 || index >= mFields.count() )
6076 return;
6077
6078 mFieldConfigurationFlags.insert( mFields.at( index ).name(), flags );
6079 updateFields();
6080}
6081
6083{
6085
6086 if ( index < 0 || index >= mFields.count() )
6087 return;
6088 Qgis::FieldConfigurationFlags flags = mFields.at( index ).configurationFlags();
6089 flags.setFlag( flag, active );
6091}
6092
6093Qgis::FieldConfigurationFlags QgsVectorLayer::fieldConfigurationFlags( int index ) const
6094{
6096
6097 if ( index < 0 || index >= mFields.count() )
6099
6100 return mFields.at( index ).configurationFlags();
6101}
6102
6104{
6106
6107 if ( index < 0 || index >= mFields.count() )
6108 return;
6109
6110 if ( setup.isNull() )
6111 mFieldWidgetSetups.remove( mFields.at( index ).name() );
6112 else
6113 mFieldWidgetSetups.insert( mFields.at( index ).name(), setup );
6114 updateFields();
6115}
6116
6118{
6120
6121 if ( index < 0 || index >= mFields.count() )
6122 return QgsEditorWidgetSetup();
6123
6124 return mFields.at( index ).editorWidgetSetup();
6125}
6126
6127QgsAbstractVectorLayerLabeling *QgsVectorLayer::readLabelingFromCustomProperties()
6128{
6130
6132 if ( customProperty( QStringLiteral( "labeling" ) ).toString() == QLatin1String( "pal" ) )
6133 {
6134 if ( customProperty( QStringLiteral( "labeling/enabled" ), QVariant( false ) ).toBool() )
6135 {
6136 // try to load from custom properties
6137 QgsPalLayerSettings settings;
6138 settings.readFromLayerCustomProperties( this );
6139 labeling = new QgsVectorLayerSimpleLabeling( settings );
6140 }
6141
6142 // also clear old-style labeling config
6143 removeCustomProperty( QStringLiteral( "labeling" ) );
6144 const auto constCustomPropertyKeys = customPropertyKeys();
6145 for ( const QString &key : constCustomPropertyKeys )
6146 {
6147 if ( key.startsWith( QLatin1String( "labeling/" ) ) )
6148 removeCustomProperty( key );
6149 }
6150 }
6151
6152 return labeling;
6153}
6154
6156{
6158
6159 return mAllowCommit;
6160}
6161
6162void QgsVectorLayer::setAllowCommit( bool allowCommit )
6163{
6165
6166 if ( mAllowCommit == allowCommit )
6167 return;
6168
6169 mAllowCommit = allowCommit;
6170 emit allowCommitChanged();
6171}
6172
6174{
6176
6177 return mGeometryOptions.get();
6178}
6179
6180void QgsVectorLayer::setReadExtentFromXml( bool readExtentFromXml )
6181{
6183
6184 mReadExtentFromXml = readExtentFromXml;
6185}
6186
6188{
6190
6191 return mReadExtentFromXml;
6192}
6193
6194void QgsVectorLayer::onDirtyTransaction( const QString &sql, const QString &name )
6195{
6197
6199 if ( tr && mEditBuffer )
6200 {
6201 qobject_cast<QgsVectorLayerEditPassthrough *>( mEditBuffer )->update( tr, sql, name );
6202 }
6203}
6204
6205QList<QgsVectorLayer *> QgsVectorLayer::DeleteContext::handledLayers( bool includeAuxiliaryLayers ) const
6206{
6207 QList<QgsVectorLayer *> layers;
6208 QMap<QgsVectorLayer *, QgsFeatureIds>::const_iterator i;
6209 for ( i = mHandledFeatures.begin(); i != mHandledFeatures.end(); ++i )
6210 {
6211 if ( includeAuxiliaryLayers || !qobject_cast< QgsAuxiliaryLayer * >( i.key() ) )
6212 layers.append( i.key() );
6213 }
6214 return layers;
6215}
6216
6218{
6219 return mHandledFeatures[layer];
6220}
The Qgis class provides global constants for use throughout the application.
Definition qgis.h:54
@ Composition
Fix relation, related elements are part of the parent and a parent copy will copy any children or del...
@ Association
Loose relation, related elements are not part of the parent and a parent copy will not copy any child...
GeometryOperationResult
Success or failure of a geometry operation.
Definition qgis.h:1520
@ InvalidInputGeometryType
The input geometry (ring, part, split line, etc.) has not the correct geometry type.
@ Success
Operation succeeded.
@ SelectionIsEmpty
No features were selected.
@ AddRingNotInExistingFeature
The input ring doesn't have any existing ring to fit into.
@ AddRingNotClosed
The input ring is not closed.
@ SelectionIsGreaterThanOne
More than one features were selected.
@ LayerNotEditable
Cannot edit layer.
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
@ Curved
Arranges candidates following the curvature of a line feature. Applies to line layers only.
@ AroundPoint
Arranges candidates in a circle around a point (or centroid of a polygon). Applies to point or polygo...
@ Line
Arranges candidates parallel to a generalised line representing the feature or parallel to a polygon'...
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
@ PerimeterCurved
Arranges candidates following the curvature of a polygon's boundary. Applies to polygon layers only.
@ BufferedGroups
Buffered transactional editing means that all editable layers in the buffered transaction group are t...
FieldDomainSplitPolicy
Split policy for field domains.
Definition qgis.h:2632
@ Duplicate
Duplicate original value.
BlendMode
Blending modes defining the available composition modes that can be used when painting.
Definition qgis.h:3413
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition qgis.h:255
@ Polygon
Polygons.
@ Unknown
Unknown types.
@ Null
No geometry.
@ Generated
A generated relation is a child of a polymorphic relation.
@ Normal
A normal relation.
static const float DEFAULT_MAPTOPIXEL_THRESHOLD
Default threshold between map coordinates and device coordinates for map2pixel simplification.
Definition qgis.h:4037
@ Vector
Vector layer.
RenderUnit
Rendering size units.
Definition qgis.h:3627
@ Points
Points (e.g., for font sizes)
VertexMarkerType
Editing vertex markers, used for showing vertices during a edit operation.
Definition qgis.h:1325
@ SemiTransparentCircle
Semi-transparent circle marker.
@ Cross
Cross marker.
VectorEditResult
Flags which control feature selection behavior.
Definition qgis.h:1310
@ Success
Edit operation was successful.
@ InvalidLayer
Edit failed due to invalid layer.
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:182
@ Unknown
Unknown.
FieldConfigurationFlag
Configuration flags for fields These flags are meant to be user-configurable and are not describing a...
Definition qgis.h:1213
@ HideFromWfs
Field is not available if layer is served as WFS from QGIS server.
@ NoFlag
No flag is defined.
@ HideFromWms
Field is not available if layer is served as WMS from QGIS server.
@ AllowOverlapIfRequired
Avoids overlapping labels when possible, but permit overlaps if labels for features cannot otherwise ...
@ AlwaysAllowUpsideDown
Show upside down for all labels, including dynamic ones.
SelectBehavior
Specifies how a selection should be applied.
Definition qgis.h:1263
@ SetSelection
Set selection, removing any existing selection.
@ AddToSelection
Add selection to current selection.
@ IntersectSelection
Modify current selection to include only select features which match.
@ RemoveFromSelection
Remove from current selection.
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...
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the labeling...
virtual void toSld(QDomNode &parent, const QVariantMap &props) const
Writes the SE 1.1 TextSymbolizer element based on the current layer labeling settings.
static QgsAbstractVectorLayerLabeling * create(const QDomElement &element, const QgsReadWriteContext &context)
Try to create instance of an implementation based on the XML data.
virtual QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) const =0
Returns labeling configuration as XML element.
Storage and management of actions associated with a layer.
bool writeXml(QDomNode &layer_node) const
Writes the actions out in XML format.
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.
bool readXml(const QDomNode &layer_node)
Reads the actions in in XML format.
Utility class that encapsulates an action based on vector attributes.
Definition qgsaction.h:37
Utility class for calculating aggregates for a field (or expression) over the features from a vector ...
Aggregate
Available aggregates to calculate.
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.
This is a container for configuration of the attribute table.
void readXml(const QDomNode &node)
Deserialize to XML on layer load.
void update(const QgsFields &fields)
Update the configuration with the given fields.
void writeXml(QDomNode &node) const
Serialize to XML on layer save.
A vector of attributes.
Class allowing to manage the auxiliary storage for a vector layer.
QgsVectorLayerJoinInfo joinInfo() const
Returns information to use for joining with primary key and so on.
Class 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.
The QgsConditionalLayerStyles class holds conditional style information for a layer.
bool readXml(const QDomNode &node, const QgsReadWriteContext &context)
Reads the condition styles state from a DOM node.
bool writeXml(QDomNode &node, QDomDocument &doc, const QgsReadWriteContext &context) const
Writes the condition styles state to a DOM node.
This class 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.
virtual bool leaveUpdateMode()
Leave update mode.
@ FlagLoadDefaultStyle
Reset the layer's style to the default for the datasource.
@ ForceReadOnly
Open layer in a read-only mode (since QGIS 3.28)
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
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 Qgis::ProviderStyleStorageCapabilities styleStorageCapabilities() const
Returns the style storage capabilities.
virtual QString subsetString() const
Returns the subset definition string (typically sql) currently in use by the layer and used by the pr...
virtual QgsLayerMetadata layerMetadata() const
Returns layer metadata collected from the provider's source.
virtual bool isValid() const =0
Returns true if this is a valid layer.
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
virtual void updateExtents()
Update the extents of the layer.
virtual bool setSubsetString(const QString &subset, bool updateFeatureCount=true)
Set the subset string used to create a subset of features in the layer.
virtual void reloadData()
Reloads the data from the source for providers with data caches to synchronize, changes in the data s...
virtual bool enterUpdateMode()
Enter update mode.
virtual QgsRectangle extent() const =0
Returns the extent of the layer.
virtual void setTransformContext(const QgsCoordinateTransformContext &transformContext)
Sets data coordinate transform context to transformContext.
Class for storing the component parts of a RDBMS data source URI (e.g.
bool useEstimatedMetadata() const
Returns true if estimated metadata should be used for the connection.
The QgsDefaultValue class 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.
@ Show
Whether to show the diagram.
@ PositionY
Y-coordinate data defined diagram position.
void readXml(const QDomElement &elem)
Reads the diagram settings from a DOM element.
void writeXml(QDomElement &layerElem, QDomDocument &doc) const
Writes the diagram settings to a DOM element.
Evaluates and returns the diagram settings relating to a diagram for a specific feature.
virtual void writeXml(QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context) const =0
Writes diagram state to a DOM element.
virtual QList< QgsDiagramSettings > diagramSettings() const =0
Returns list with all diagram settings in the renderer.
virtual void readXml(const QDomElement &elem, const QgsReadWriteContext &context)=0
Reads diagram state from a DOM element.
Contains configuration settings for an editor form.
void readXml(const QDomNode &node, QgsReadWriteContext &context)
Read XML information Deserialize on project load.
void writeXml(QDomNode &node, const QgsReadWriteContext &context) const
Write XML information Serialize on project save.
Holder for the widget type and its configuration for a field.
QVariantMap config() const
void clear()
Clear error messages.
Definition qgserror.h:127
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 removeExpression(int index)
Remove an expression from the buffer.
void writeXml(QDomNode &layer_node, QDomDocument &document) const
Saves expressions to xml under the layer node.
void readXml(const QDomNode &layer_node)
Reads expressions from project file.
void updateFields(QgsFields &flds) const
Adds fields with the expressions buffered in this object to a QgsFields object.
void addExpression(const QString &exp, const QgsField &fld)
Add an expression to the buffer.
QList< QgsExpressionFieldBuffer::ExpressionField > expressions() const
void updateExpression(int index, const QString &exp)
Changes the expression at a given index.
void renameExpression(int index, const QString &name)
Renames an expression field at a given index.
An expression node which takes it value from a feature's field.
Class for 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)
An interface for objects which generate feature renderers for vector layers.
static QgsFeatureRenderer * defaultRenderer(Qgis::GeometryType geomType)
Returns a new renderer - used by default in vector layers.
virtual void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const
used from subclasses to create SLD Rule elements following SLD v1.1 specs
virtual QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context)
Stores renderer properties to an XML element.
double referenceScale() const
Returns the symbology reference scale.
void setReferenceScale(double scale)
Sets the symbology reference scale.
static QgsFeatureRenderer * load(QDomElement &symbologyElem, const QgsReadWriteContext &context)
create a renderer from XML element
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
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 ...
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will 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.
@ SubsetOfAttributes
Fetch only a subset of attributes (setSubsetOfAttributes sets this flag)
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets the feature ID that should be fetched.
virtual bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags())
Adds a single feature to the sink.
virtual QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const
Returns the set of unique values contained within the specified fieldIndex from this source.
SpatialIndexPresence
Enumeration of spatial index presence states.
@ SpatialIndexUnknown
Spatial index presence cannot be determined, index may or may not exist.
FeatureAvailability
Possible return value for hasFeatures() to determine if a source is empty.
@ FeaturesMaybeAvailable
There may be features available in this source.
@ NoFeaturesAvailable
There are certainly no features available in this source.
@ FeaturesAvailable
There is at least one feature available in this source.
virtual QgsFeatureIds allFeatureIds() const
Returns a list of all feature IDs for features present in the source.
virtual SpatialIndexPresence hasSpatialIndex() const
Returns an enum value representing the presence of a valid spatial index on the source,...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:56
bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
QgsAttributes attributes
Definition qgsfeature.h:65
QgsFields fields
Definition qgsfeature.h:66
QgsFeatureId id
Definition qgsfeature.h:64
QgsGeometry geometry
Definition qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
bool isValid() const
Returns the validity of this feature.
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:45
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:54
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 ...
QString constraintExpression() const
Returns the constraint expression for the field, if set.
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().
QString constraintDescription() const
Returns the descriptive name for the constraint expression.
void setConstraint(Constraint constraint, ConstraintOrigin origin=ConstraintOriginLayer)
Sets a constraint on the field.
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:53
QString typeName() const
Gets the field type.
Definition qgsfield.cpp:150
QString name
Definition qgsfield.h:62
int precision
Definition qgsfield.h:59
int length
Definition qgsfield.h:58
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:96
QString displayName() const
Returns the name to use when displaying this field.
Definition qgsfield.cpp:88
Qgis::FieldConfigurationFlags configurationFlags
Definition qgsfield.h:66
QString alias
Definition qgsfield.h:63
QgsDefaultValue defaultValueDefinition
Definition qgsfield.h:64
QString comment
Definition qgsfield.h:61
QgsFieldConstraints constraints
Definition qgsfield.h:65
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition qgsfield.cpp:714
Container of fields for a vector layer.
Definition qgsfields.h:45
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
@ OriginExpression
Field is calculated from an expression.
Definition qgsfields.h:54
@ OriginEdit
Field has been temporarily added in editing mode (originIndex = index in the list of added attributes...
Definition qgsfields.h:53
@ OriginUnknown
It has not been specified where the field comes from.
Definition qgsfields.h:50
@ OriginJoin
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition qgsfields.h:52
@ OriginProvider
Field comes from the underlying data provider of the vector layer (originIndex = index in provider's ...
Definition qgsfields.h:51
int count() const
Returns number of items.
FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
bool isEmpty() const
Checks whether the container is empty.
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).
int fieldOriginIndex(int fieldIdx) const
Returns the field's origin index (its meaning is specific to each type of origin).
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
QStringList names() const
Returns a list with field names.
The QgsGeometryOptions class contains options to automatically adjust geometries to constraints on a ...
A geometry is the spatial representation of a feature.
bool equals(const QgsGeometry &geometry) const
Test if this geometry is exactly equal to another 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.
Class for metadata formatter.
A structured metadata store for a map layer.
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.
static void warning(const QString &msg)
Goes to qWarning.
This class 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 void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads configuration from a DOM element previously written by writeXml()
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.
Base class for all map layer types.
Definition qgsmaplayer.h:74
QString name
Definition qgsmaplayer.h:77
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 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.
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.
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
void editingStarted()
Emitted when editing on this layer has started.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:80
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.
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
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 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:79
Qgis::LayerType type
Definition qgsmaplayer.h:81
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.
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.
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 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.
void setDataSource(const QString &dataSource, const QString &baseName, const QString &provider, bool loadDefaultStyleFlag=false)
Updates the data source of the layer.
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:85
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
double opacity
Definition qgsmaplayer.h:83
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 (since QGIS 3.16)
@ 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 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:84
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 QgsDataProvider::ReadFlags providerReadFlags(const QDomNode &layerNode, QgsMapLayer::ReadFlags layerReadFlags)
Returns provider read flag deduced from layer read flags layerReadFlags and a dom node layerNode that...
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
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.
Resolves relative paths into absolute paths and vice versa.
A class to represent a 2D point.
Definition qgspointxy.h:59
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
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
The derived translate() translates with QTranslator and qm file the sourceText.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:107
QgsRelationManager * relationManager
Definition qgsproject.h:117
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.
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
bool rollBack(QStringList &rollbackErrors, bool stopEditing=true, QgsVectorLayer *vectorLayer=nullptr)
Stops a current editing operation on vectorLayer and discards any uncommitted edits.
QgsPathResolver pathResolver() const
Returns path resolver object with considering whether the project uses absolute or relative paths and...
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 a 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:46
@ 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.
The class is used as a container of context for various read/write operations on other objects.
MAYBE_UNUSED NODISCARD 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.
A rectangle specified with double values.
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double width() const
Returns the width of the rectangle.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
bool isNull() const
Test if the rectangle is null (holding no spatial information).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
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.
double height() const
Returns the height of the rectangle.
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.
QList< QgsRelation > referencingRelations(const QgsVectorLayer *layer=nullptr, int fieldIdx=-2) const
Gets all relations where the specified layer (and field) is the referencing part (i....
void relationsLoaded()
Emitted when the relations were loaded after reading a project.
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.
A child rule for QgsRuleBasedLabeling.
void appendChild(QgsRuleBasedLabeling::Rule *rule)
add child rule, take ownership, sets this as parent
Rule based labeling for a vector layer.
A boolean settings entry.
A double settings entry.
A template class for enum and flag settings entry.
static QgsSettingsTreeNode * sTreeQgis
This class is a composition of two QSettings instances:
Definition qgssettings.h:63
Renders the diagrams for all features with the same settings.
Manages stored expressions regarding creation, modification and storing in the project.
bool writeXml(QDomNode &layerNode) const
Writes the stored expressions out in XML format.
bool readXml(const QDomNode &layerNode)
Reads the stored expressions in in XML format.
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....
bool isActive() const
Returns true if the temporal property is active.
Container for settings relating to a text buffer.
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.
Container for all settings relating to text rendering.
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.
This class allows including a set of layers in a database-side transaction, provided the layer data p...
QString createSavepoint(QString &error)
creates a save point returns empty string on error returns the last created savepoint if it's not dir...
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)
Returns true if the specified variant should be considered a NULL value.
This is the base class for vector data providers.
virtual QString dataComment() const override
Returns a short comment for the data that this provider is providing access to (e....
@ ReadLayerMetadata
Provider can read layer metadata from data store. Since QGIS 3.0. See QgsDataProvider::layerMetadata(...
@ SelectAtId
Fast access to features using their ID.
@ DeleteFeatures
Allows deletion of features.
@ CreateLabeling
Provider can set labeling settings using backend-specific formatting information. Since QGIS 3....
@ CreateRenderer
Provider can create feature renderers using backend-specific formatting information....
static const int EditingCapabilities
Bitmask of all provider's editing capabilities.
long long featureCount() const override=0
Number of features in the layer.
virtual QgsFeatureRenderer * createRenderer(const QVariantMap &configuration=QVariantMap()) const
Creates a new vector layer feature renderer, using provider backend specific information.
virtual QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
virtual 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) const
Signals an error in this provider.
virtual bool isSqlQuery() const
Returns true if the layer is a query (SQL) layer.
virtual bool empty() const
Returns true if the layer does not contain any feature.
virtual QgsAttributeList pkAttributeIndexes() const
Returns list of indexes of fields that make up the primary key.
virtual void handlePostCloneOperations(QgsVectorDataProvider *source)
Handles any post-clone operations required after this vector data provider was cloned from the source...
virtual QSet< QgsMapLayerDependency > dependencies() const
Gets the list of layer ids on which this layer depends.
virtual void setEncoding(const QString &e)
Set encoding used for accessing data from layer.
virtual Qgis::VectorLayerTypeFlags vectorLayerTypeFlags() const
Returns the vector layer type flags.
QVariant maximumValue(int index) const override
Returns the maximum value of an attribute.
QgsFields fields() const override=0
Returns the fields associated with this data provider.
Qgis::WkbType wkbType() const override=0
Returns the geometry type which is returned by this layer.
QVariant minimumValue(int index) const override
Returns the minimum value of an attribute.
virtual QVariant aggregate(QgsAggregateCalculator::Aggregate aggregate, int index, const QgsAggregateCalculator::AggregateParameters &parameters, QgsExpressionContext *context, bool &ok, QgsFeatureIds *fids=nullptr) const
Calculates an aggregated value from the layer's features.
QString encoding() const
Returns the encoding which is used for accessing data.
virtual QVariant defaultValue(int fieldIndex) const
Returns any literal default values which are present at the provider for a specified field index.
QgsFieldConstraints::Constraints fieldConstraints(int fieldIndex) const
Returns any constraints which are present at the provider for a specified field index.
virtual QgsTransaction * transaction() const
Returns the transaction this data provider is included in, if any.
virtual QgsAbstractVectorLayerLabeling * createLabeling(const QVariantMap &configuration=QVariantMap()) const
Creates labeling settings, using provider backend specific information.
virtual Q_INVOKABLE QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
QgsVectorDataProviderTemporalCapabilities * temporalCapabilities() override
Returns the provider's temporal capabilities.
QString capabilitiesString() const
Returns the above in friendly format.
bool commitChanges(QStringList &commitErrors, bool stopEditing=true)
Attempts to commit any changes to disk.
void committedAttributesDeleted(const QString &layerId, const QgsAttributeList &deletedAttributes)
Signals emitted after committing changes.
virtual bool deleteFeature(QgsFeatureId fid)
Delete a feature from the layer (but does not commit it)
QgsFeatureIds deletedFeatureIds() const
Returns a list of deleted feature IDs which are not committed.
QgsChangedAttributesMap changedAttributeValues() const
Returns a map of features with changed attributes values which are not committed.
void committedAttributeValuesChanges(const QString &layerId, const QgsChangedAttributesMap &changedAttributesValues)
virtual bool renameAttribute(int attr, const QString &newName)
Renames an attribute field (but does not commit it)
void geometryChanged(QgsFeatureId fid, const QgsGeometry &geom)
Emitted when a feature's geometry is changed.
virtual bool deleteFeatures(const QgsFeatureIds &fid)
Deletes a set of features from the layer (but does not commit it)
virtual bool addAttribute(const QgsField &field)
Adds an attribute field (but does not commit it) returns true if the field was added.
void committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)
virtual bool addFeatures(QgsFeatureList &features)
Insert a copy of the given features into the layer (but does not commit it)
virtual bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues)
Changes values of attributes (but does not commit it).
QgsFeatureMap addedFeatures() const
Returns a map of new features which are not committed.
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
void updateFields(QgsFields &fields)
Updates fields.
void committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)
void featureDeleted(QgsFeatureId fid)
QgsGeometryMap changedGeometries() const
Returns a map of features with changed geometries which are not committed.
QgsVectorLayerEditBufferGroup * editBufferGroup() const
Returns the parent edit buffer group for this edit buffer, or nullptr if not part of a group.
QgsAttributeList deletedAttributeIds() const
Returns a list of deleted attributes fields which are not committed.
void attributeAdded(int idx)
void committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)
virtual bool addFeature(QgsFeature &f)
Adds a feature.
virtual void rollBack()
Stop editing and discard the edits.
void attributeDeleted(int idx)
void featureAdded(QgsFeatureId fid)
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &)
virtual bool commitChanges(QStringList &commitErrors)
Attempts to commit any changes to disk.
virtual bool deleteAttribute(int attr)
Deletes an attribute field (but does not commit it)
virtual bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant())
Changed an attribute value (but does not commit it)
virtual bool changeGeometry(QgsFeatureId fid, const QgsGeometry &geom)
Change feature's geometry.
void layerModified()
Emitted when modifications has been done on layer.
void committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)
int translateFeature(QgsFeatureId featureId, double dx, double dy)
Translates feature by dx, dy.
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.
void setDefaultsFromLayer(QgsMapLayer *layer) override
Sets default properties based on sensible choices for the given map layer.
QgsVectorLayerElevationProperties * clone() const override
Creates a clone of the properties.
Counts the features in a QgsVectorLayer in task.
QHash< QString, long long > symbolFeatureCountMap() const
Returns the count for each symbol.
void cancel() override
Notifies the task that it should terminate.
QHash< QString, QgsFeatureIds > symbolFeatureIdMap() const
Returns the QgsFeatureIds for each symbol.
Manages joined fields for a vector layer.
void resolveReferences(QgsProject *project)
Resolves layer IDs of joined layers using given project's available layers.
bool addJoin(const QgsVectorLayerJoinInfo &joinInfo)
Joins another vector layer to this layer.
void readXml(const QDomNode &layer_node)
Reads joins from project file.
void writeXml(QDomNode &layer_node, QDomDocument &document) const
Saves mVectorJoins to xml under the layer node.
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant())
Changes attribute value in joined layers.
bool removeJoin(const QString &joinLayerId)
Removes a vector layer join.
bool containsJoins() const
Quick way to test if there is any join at all.
bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues=QgsAttributeMap())
Changes attributes' values in joined layers.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a list of features in joined layers.
void joinedFieldsChanged()
Emitted whenever the list of joined fields changes (e.g.
void updateFields(QgsFields &fields)
Updates field map with joined attributes.
bool deleteFeature(QgsFeatureId fid, QgsVectorLayer::DeleteContext *context=nullptr) const
Deletes a feature from joined layers.
const QgsVectorJoinList & vectorJoins() const
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.
QDomElement writeXml(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context) override
Writes the properties to a DOM element, to be used later with readXml().
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads temporal properties from a DOM element previously written by writeXml().
Basic implementation of the labeling interface.
Implementation of map layer temporal properties for vector layers.
void guessDefaultsFromFields(const QgsFields &fields)
Attempts to setup the temporal properties by scanning a set of fields and looking for standard naming...
void setDefaultsFromDataProviderTemporalCapabilities(const QgsDataProviderTemporalCapabilities *capabilities) override
Sets the layers temporal settings to appropriate defaults based on a provider's temporal capabilities...
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...
Represents a vector layer which manages a vector based data sets.
void setLabeling(QgsAbstractVectorLayerLabeling *labeling)
Sets labeling configuration.
QString attributeDisplayName(int index) const
Convenience function that returns the attribute alias if defined or the field name else.
QVariant maximumValue(int index) const FINAL
Returns the maximum value for an attribute column or an invalid variant in case of error.
int addExpressionField(const QString &exp, const QgsField &fld)
Add a new field which is calculated by the expression specified.
void committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)
Emitted when features are added to the provider if not in transaction mode.
void setExtent(const QgsRectangle &rect) FINAL
Sets the extent.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult addPart(const QList< QgsPointXY > &ring)
Adds a new part polygon to a multipart feature.
QgsRectangle sourceExtent() const FINAL
Returns the extent of all geometries from the source.
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 writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const FINAL
bool isModified() const override
Returns true if the provider has been modified since the last commit.
bool writeStyle(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const FINAL
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 selectByRect(QgsRectangle &rect, Qgis::SelectBehavior behavior=Qgis::SelectBehavior::SetSelection)
Selects features found within the search rectangle (in layer's coordinates)
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.
void beforeRemovingExpressionField(int idx)
Will be emitted, when an expression field is going to be deleted from this vector layer.
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...
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.
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.
QSet< QgsMapLayerDependency > dependencies() const FINAL
Gets the list of dependencies.
QgsMapLayerTemporalProperties * temporalProperties() override
Returns the layer's temporal properties.
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.
QgsExpressionContextScope * createExpressionContextScope() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext) FINAL
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context.
QgsVectorLayerFeatureCounter * countSymbolFeatures(bool storeSymbolFids=false)
Count features for symbols.
QPainter::CompositionMode featureBlendMode() const
Returns the current blending mode for features.
bool hasMapTips() const FINAL
Returns true if the layer contains map tips.
QString constraintExpression(int index) const
Returns the constraint expression for for a specified field index, if set.
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.
static const QgsSettingsEntryEnumFlag< QgsVectorSimplifyMethod::SimplifyHints > * settingsSimplifyDrawingHints
void deselect(QgsFeatureId featureId)
Deselects feature by its ID.
void allowCommitChanged()
Emitted whenever the allowCommitChanged() 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,...
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
const QgsDiagramLayerSettings * diagramLayerSettings() const
void setFieldConstraint(int index, QgsFieldConstraints::Constraint constraint, QgsFieldConstraints::ConstraintStrength strength=QgsFieldConstraints::ConstraintStrengthHard)
Sets a constraint for a specified field index.
bool loadAuxiliaryLayer(const QgsAuxiliaryStorage &storage, const QString &key=QString())
Loads the auxiliary layer for this vector layer.
bool deleteFeature(QgsFeatureId fid, DeleteContext *context=nullptr)
Deletes a feature from the layer (but does not commit it).
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...
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsAbstractProfileGenerator * createProfileGenerator(const QgsProfileRequest &request) override
Given a profile request, returns a new profile generator ready for generating elevation profiles.
QString htmlMetadata() const FINAL
Obtain a formatted HTML string containing assorted metadata for this layer.
Q_INVOKABLE QgsRectangle boundingBoxOfSelected() const
Returns the bounding box of the selected features. If there is no selection, QgsRectangle(0,...
QgsFields fields() const FINAL
Returns the list of fields of this layer.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a list of features to the sink.
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.
bool readSymbology(const QDomNode &layerNode, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) FINAL
void removeFeatureRendererGenerator(const QString &id)
Removes the feature renderer with matching id from the layer.
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.
QgsFieldConstraints::Constraints fieldConstraints(int fieldIndex) const
Returns any constraints which are present for a specified field index.
bool deleteFeatures(const QgsFeatureIds &fids, DeleteContext *context=nullptr)
Deletes a set of features from the layer (but does not commit it)
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.
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 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
~QgsVectorLayer() override
QgsCoordinateReferenceSystem sourceCrs() const FINAL
Returns the coordinate reference system for features in the source.
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.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
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.
bool setDependencies(const QSet< QgsMapLayerDependency > &layers) FINAL
Sets the list of dependencies.
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.
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.
void setProviderEncoding(const QString &encoding)
Sets the text encoding of the data provider.
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 bool deleteAttribute(int attr)
Deletes an attribute field (but does not commit it).
static const QgsSettingsEntryBool * settingsSimplifyLocal
void resolveReferences(QgsProject *project) FINAL
Resolves references to other layers (kept as layer IDs after reading XML) into layer objects.
bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues=QgsAttributeMap(), bool skipDefaultValues=false)
Changes attributes' values for a feature (but does not immediately commit the changes).
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
bool removeJoin(const QString &joinLayerId)
Removes a vector layer join.
Q_INVOKABLE void invertSelectionInRectangle(QgsRectangle &rect)
Inverts selection of features found within the search rectangle (in layer's coordinates)
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.
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
QStringList commitErrors() const
Returns a list containing any error messages generated when attempting to commit changes to the layer...
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
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
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.
Q_INVOKABLE Qgis::WkbType wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
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.
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.
QVariant minimumValue(int index) const FINAL
Returns the minimum value for an attribute column or an invalid variant in case of error.
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
void setEditorWidgetSetup(int index, const QgsEditorWidgetSetup &setup)
The editor widget setup defines which QgsFieldFormatter and editor widget will be used for the field ...
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.
bool readStyle(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) FINAL
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.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
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 reselect()
Reselects the previous set of selected features.
void select(QgsFeatureId featureId)
Selects feature by its ID.
QgsEditorWidgetSetup editorWidgetSetup(int index) const
The editor widget setup defines which QgsFieldFormatter and editor widget will be used for the field ...
long long featureCount() const FINAL
Returns feature count including changes which have not yet been committed If you need only the count ...
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.
bool readSld(const QDomNode &node, QString &errorMessage) FINAL
QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
Q_INVOKABLE void selectByIds(const QgsFeatureIds &ids, Qgis::SelectBehavior behavior=Qgis::SelectBehavior::SetSelection)
Selects matching features using a list of feature IDs.
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.
QgsFeatureSource::SpatialIndexPresence hasSpatialIndex() const override
void readOnlyChanged()
Emitted when the read only state of this layer is changed.
void removeExpressionField(int index)
Removes an expression field.
virtual 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.
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false)
Changes an attribute value for a feature (but does not immediately commit the changes).
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a single feature to the sink.
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.
QgsRectangle extent() const FINAL
Returns the extent of the layer.
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.
bool readXml(const QDomNode &layer_node, QgsReadWriteContext &context) FINAL
Reads vector layer specific state from project file Dom node.
FeatureAvailability hasFeatures() const FINAL
Determines if this vector layer has features.
void afterRollBack()
Emitted after changes are rolled back.
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...
void setDiagramLayerSettings(const QgsDiagramLayerSettings &s)
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.
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.
QString sourceName() const FINAL
Returns a friendly display name for the source.
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 reload() FINAL
Synchronises with changes in the datasource.
const QList< QgsVectorLayerJoinInfo > vectorJoins() const
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.
bool simplifyDrawingCanbeApplied(const QgsRenderContext &renderContext, QgsVectorSimplifyMethod::SimplifyHint simplifyHint) const
Returns whether the VectorLayer can apply the specified simplification hint.
void beforeRollBack()
Emitted before changes are rolled back.
QgsAttributeList primaryKeyAttributes() const
Returns the list of attributes which make up the layer's primary keys.
bool writeXml(QDomNode &layer_node, QDomDocument &doc, const QgsReadWriteContext &context) const FINAL
Writes vector layer specific state to project file Dom node.
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...
static const QgsSettingsEntryEnumFlag< QgsVectorSimplifyMethod::SimplifyAlgorithm > * settingsSimplifyAlgorithm
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.
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.
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.
void beforeModifiedCheck() const
Emitted when the layer is checked for modifications. Use for last-minute additions.
Q_INVOKABLE void invertSelection()
Selects not selected features and deselects selected ones.
const QgsDiagramRenderer * diagramRenderer() const
QgsMapLayerSelectionProperties * selectionProperties() override
Returns the layer's selection properties.
QVariant aggregate(QgsAggregateCalculator::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.
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
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const FINAL
Calculates a list of unique values contained within an attribute in the layer.
void setFieldSplitPolicy(int index, Qgis::FieldDomainSplitPolicy policy)
Sets a split policy for the field with the specified index.
bool forceLocalOptimization() const
Gets where the simplification executes, after fetch the geometries from provider, or when supported,...
void setSimplifyHints(SimplifyHints simplifyHints)
Sets the simplification hints of the vector layer managed.
float maximumScale() const
Gets the maximum scale at which the layer should be simplified.
void setThreshold(float threshold)
Sets the simplification threshold of the vector layer managed.
void setSimplifyAlgorithm(SimplifyAlgorithm simplifyAlgorithm)
Sets the local simplification algorithm of the vector layer managed.
void setForceLocalOptimization(bool localOptimization)
Sets where the simplification executes, after fetch the geometries from provider, or when supported,...
SimplifyHints simplifyHints() const
Gets the simplification hints of the vector layer managed.
SimplifyAlgorithm simplifyAlgorithm() const
Gets the local simplification algorithm of the vector layer managed.
float threshold() const
Gets the simplification threshold of the vector layer managed.
SimplifyHint
Simplification flags for fast rendering of features.
@ NoSimplification
No simplification can be applied.
SimplifyAlgorithm
Types of local simplification algorithms that can be used.
@ Distance
The simplification uses the distance between points to remove duplicate points.
void setMaximumScale(float maximumScale)
Sets the maximum scale at which the layer should be simplified.
@ 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 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 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 QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
static QgsRectangle readRectangle(const QDomElement &element)
@ UnknownCount
Provider returned an unknown feature count.
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:247
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:120
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:188
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:4555
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:4536
QString qgsFlagValueToKeys(const T &value, bool *returnOk=nullptr)
Returns the value for the given keys of a flag.
Definition qgis.h:4594
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:4616
QMap< QString, QString > QgsStringMap
Definition qgis.h:4877
QVector< QgsPoint > QgsPointSequence
QMap< int, QVariant > QgsAttributeMap
QList< QgsFeature > QgsFeatureList
Definition qgsfeature.h:920
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
QList< int > QgsAttributeList
Definition qgsfield.h:27
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
#define QgsDebugError(str)
Definition qgslogger.h:38
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
#define RENDERER_TAG_NAME
Definition qgsrenderer.h:50
#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.