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