QGIS API Documentation 3.41.0-Master (181b2f43d8e)
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 "moc_qgsvectorlayer.cpp"
28#include "qgsactionmanager.h"
29#include "qgsapplication.h"
30#include "qgsconditionalstyle.h"
32#include "qgscurve.h"
33#include "qgsdatasourceuri.h"
36#include "qgsfeature.h"
37#include "qgsfeaturerequest.h"
38#include "qgsfields.h"
39#include "qgsmaplayerfactory.h"
41#include "qgsgeometry.h"
43#include "qgslogger.h"
44#include "qgsmaplayerlegend.h"
45#include "qgsmessagelog.h"
46#include "qgsogcutils.h"
47#include "qgspainting.h"
48#include "qgspointxy.h"
49#include "qgsproject.h"
50#include "qgsproviderregistry.h"
51#include "qgsrectangle.h"
52#include "qgsrelationmanager.h"
53#include "qgsweakrelation.h"
54#include "qgsrendercontext.h"
67#include "qgspoint.h"
68#include "qgsrenderer.h"
69#include "qgssymbollayer.h"
70#include "qgsdiagramrenderer.h"
71#include "qgspallabeling.h"
75#include "qgsfeedback.h"
76#include "qgsxmlutils.h"
77#include "qgstaskmanager.h"
78#include "qgstransaction.h"
79#include "qgsauxiliarystorage.h"
80#include "qgsgeometryoptions.h"
82#include "qgsruntimeprofiler.h"
84#include "qgsvectorlayerutils.h"
86#include "qgsprofilerequest.h"
87#include "qgssymbollayerutils.h"
88#include "qgsthreadingutils.h"
89
90#include <QDir>
91#include <QFile>
92#include <QImage>
93#include <QPainter>
94#include <QPainterPath>
95#include <QPolygonF>
96#include <QProgressDialog>
97#include <QString>
98#include <QDomNode>
99#include <QVector>
100#include <QStringBuilder>
101#include <QUrl>
102#include <QUndoCommand>
103#include <QUrlQuery>
104#include <QUuid>
105#include <QRegularExpression>
106#include <QTimer>
107
108#include <limits>
109#include <optional>
110
112#include "qgssettingsentryimpl.h"
113#include "qgssettingstree.h"
114
120
121
122#ifdef TESTPROVIDERLIB
123#include <dlfcn.h>
124#endif
125
126typedef bool saveStyle_t(
127 const QString &uri,
128 const QString &qmlStyle,
129 const QString &sldStyle,
130 const QString &styleName,
131 const QString &styleDescription,
132 const QString &uiFileContent,
133 bool useAsDefault,
134 QString &errCause
135);
136
137typedef QString loadStyle_t(
138 const QString &uri,
139 QString &errCause
140);
141
142typedef int listStyles_t(
143 const QString &uri,
144 QStringList &ids,
145 QStringList &names,
146 QStringList &descriptions,
147 QString &errCause
148);
149
150typedef QString getStyleById_t(
151 const QString &uri,
152 QString styleID,
153 QString &errCause
154);
155
156typedef bool deleteStyleById_t(
157 const QString &uri,
158 QString styleID,
159 QString &errCause
160);
161
162
163QgsVectorLayer::QgsVectorLayer( const QString &vectorLayerPath,
164 const QString &baseName,
165 const QString &providerKey,
166 const QgsVectorLayer::LayerOptions &options )
167 : QgsMapLayer( Qgis::LayerType::Vector, baseName, vectorLayerPath )
168 , mSelectionProperties( new QgsVectorLayerSelectionProperties( this ) )
169 , mTemporalProperties( new QgsVectorLayerTemporalProperties( this ) )
170 , mElevationProperties( new QgsVectorLayerElevationProperties( this ) )
171 , mAuxiliaryLayer( nullptr )
172 , mAuxiliaryLayerKey( QString() )
173 , mReadExtentFromXml( options.readExtentFromXml )
174 , mRefreshRendererTimer( new QTimer( this ) )
175{
177 mLoadAllStoredStyle = options.loadAllStoredStyles;
178
179 if ( options.fallbackCrs.isValid() )
180 setCrs( options.fallbackCrs, false );
181 mWkbType = options.fallbackWkbType;
182
183 setProviderType( providerKey );
184
185 mGeometryOptions = std::make_unique<QgsGeometryOptions>();
186 mActions = new QgsActionManager( this );
187 mConditionalStyles = new QgsConditionalLayerStyles( this );
188 mStoredExpressionManager = new QgsStoredExpressionManager();
189 mStoredExpressionManager->setParent( this );
190
191 mJoinBuffer = new QgsVectorLayerJoinBuffer( this );
192 mJoinBuffer->setParent( this );
193 connect( mJoinBuffer, &QgsVectorLayerJoinBuffer::joinedFieldsChanged, this, &QgsVectorLayer::onJoinedFieldsChanged );
194
195 mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
196 // if we're given a provider type, try to create and bind one to this layer
197 if ( !vectorLayerPath.isEmpty() && !mProviderKey.isEmpty() )
198 {
199 QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
200 Qgis::DataProviderReadFlags providerFlags;
201 if ( options.loadDefaultStyle )
202 {
204 }
205 if ( options.forceReadOnly )
206 {
208 mDataSourceReadOnly = true;
209 }
210 setDataSource( vectorLayerPath, baseName, providerKey, providerOptions, providerFlags );
211 }
212
213 for ( const QgsField &field : std::as_const( mFields ) )
214 {
215 if ( !mAttributeAliasMap.contains( field.name() ) )
216 mAttributeAliasMap.insert( field.name(), QString() );
217 }
218
219 if ( isValid() )
220 {
221 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
222 if ( !mTemporalProperties->isActive() )
223 {
224 // didn't populate temporal properties from provider metadata, so at least try to setup some initially nice
225 // selections
226 mTemporalProperties->guessDefaultsFromFields( mFields );
227 }
228
229 mElevationProperties->setDefaultsFromLayer( this );
230 }
231
232 connect( this, &QgsVectorLayer::selectionChanged, this, [this] { triggerRepaint(); } );
233 connect( QgsProject::instance()->relationManager(), &QgsRelationManager::relationsLoaded, this, &QgsVectorLayer::onRelationsLoaded ); // skip-keyword-check
234
238
239 // Default simplify drawing settings
240 QgsSettings settings;
241 mSimplifyMethod.setSimplifyHints( QgsVectorLayer::settingsSimplifyDrawingHints->valueWithDefaultOverride( mSimplifyMethod.simplifyHints() ) );
242 mSimplifyMethod.setSimplifyAlgorithm( QgsVectorLayer::settingsSimplifyAlgorithm->valueWithDefaultOverride( mSimplifyMethod.simplifyAlgorithm() ) );
243 mSimplifyMethod.setThreshold( QgsVectorLayer::settingsSimplifyDrawingTol->valueWithDefaultOverride( mSimplifyMethod.threshold() ) );
244 mSimplifyMethod.setForceLocalOptimization( QgsVectorLayer::settingsSimplifyLocal->valueWithDefaultOverride( mSimplifyMethod.forceLocalOptimization() ) );
245 mSimplifyMethod.setMaximumScale( QgsVectorLayer::settingsSimplifyMaxScale->valueWithDefaultOverride( mSimplifyMethod.maximumScale() ) );
246
247 connect( mRefreshRendererTimer, &QTimer::timeout, this, [this] { triggerRepaint( true ); } );
248}
249
251{
252 emit willBeDeleted();
253
254 setValid( false );
255
256 delete mDataProvider;
257 delete mEditBuffer;
258 delete mJoinBuffer;
259 delete mExpressionFieldBuffer;
260 delete mLabeling;
261 delete mDiagramLayerSettings;
262 delete mDiagramRenderer;
263
264 delete mActions;
265
266 delete mRenderer;
267 delete mConditionalStyles;
268 delete mStoredExpressionManager;
269
270 if ( mFeatureCounter )
271 mFeatureCounter->cancel();
272
273 qDeleteAll( mRendererGenerators );
274}
275
277{
279
281 // We get the data source string from the provider when
282 // possible because some providers may have changed it
283 // directly (memory provider does that).
284 QString dataSource;
285 if ( mDataProvider )
286 {
287 dataSource = mDataProvider->dataSourceUri();
288 options.transformContext = mDataProvider->transformContext();
289 }
290 else
291 {
292 dataSource = source();
293 }
294 options.forceReadOnly = mDataSourceReadOnly;
295 QgsVectorLayer *layer = new QgsVectorLayer( dataSource, name(), mProviderKey, options );
296 if ( mDataProvider && layer->dataProvider() )
297 {
298 layer->dataProvider()->handlePostCloneOperations( mDataProvider );
299 }
300 QgsMapLayer::clone( layer );
301 layer->mXmlExtent2D = mXmlExtent2D;
302 layer->mLazyExtent2D = mLazyExtent2D;
303 layer->mValidExtent2D = mValidExtent2D;
304 layer->mXmlExtent3D = mXmlExtent3D;
305 layer->mLazyExtent3D = mLazyExtent3D;
306 layer->mValidExtent3D = mValidExtent3D;
307
308 QList<QgsVectorLayerJoinInfo> joins = vectorJoins();
309 const auto constJoins = joins;
310 for ( const QgsVectorLayerJoinInfo &join : constJoins )
311 {
312 // do not copy join information for auxiliary layer
313 if ( !auxiliaryLayer()
314 || ( auxiliaryLayer() && auxiliaryLayer()->id() != join.joinLayerId() ) )
315 layer->addJoin( join );
316 }
317
318 if ( mDataProvider )
319 layer->setProviderEncoding( mDataProvider->encoding() );
320 layer->setSubsetString( subsetString() );
324 layer->setReadOnly( isReadOnly() );
329
330 const auto constActions = actions()->actions();
331 for ( const QgsAction &action : constActions )
332 {
333 layer->actions()->addAction( action );
334 }
335
336 if ( auto *lRenderer = renderer() )
337 {
338 layer->setRenderer( lRenderer->clone() );
339 }
340
341 if ( auto *lLabeling = labeling() )
342 {
343 layer->setLabeling( lLabeling->clone() );
344 }
346
348
349 if ( auto *lDiagramRenderer = diagramRenderer() )
350 {
351 layer->setDiagramRenderer( lDiagramRenderer->clone() );
352 }
353
354 if ( auto *lDiagramLayerSettings = diagramLayerSettings() )
355 {
356 layer->setDiagramLayerSettings( *lDiagramLayerSettings );
357 }
358
359 for ( int i = 0; i < fields().count(); i++ )
360 {
361 layer->setFieldAlias( i, attributeAlias( i ) );
363 layer->setEditorWidgetSetup( i, editorWidgetSetup( i ) );
366
367 QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength> constraints = fieldConstraintsAndStrength( i );
368 auto constraintIt = constraints.constBegin();
369 for ( ; constraintIt != constraints.constEnd(); ++ constraintIt )
370 {
371 layer->setFieldConstraint( i, constraintIt.key(), constraintIt.value() );
372 }
373
374 if ( fields().fieldOrigin( i ) == Qgis::FieldOrigin::Expression )
375 {
376 layer->addExpressionField( expressionField( i ), fields().at( i ) );
377 }
378 }
379
381
382 if ( auto *lAuxiliaryLayer = auxiliaryLayer() )
383 layer->setAuxiliaryLayer( lAuxiliaryLayer->clone( layer ) );
384
385 layer->mElevationProperties = mElevationProperties->clone();
386 layer->mElevationProperties->setParent( layer );
387
388 layer->mSelectionProperties = mSelectionProperties->clone();
389 layer->mSelectionProperties->setParent( layer );
390
391 return layer;
392}
393
395{
397
398 if ( mDataProvider )
399 {
400 return mDataProvider->storageType();
401 }
402 return QString();
403}
404
405
407{
409
410 if ( mDataProvider )
411 {
412 return mDataProvider->capabilitiesString();
413 }
414 return QString();
415}
416
418{
420
421 return mDataProvider && mDataProvider->isSqlQuery();
422}
423
430
432{
434
435 if ( mDataProvider )
436 {
437 return mDataProvider->dataComment();
438 }
439 return QString();
440}
441
448
450{
452
453 return name();
454}
455
457{
458 // non fatal for now -- the QgsVirtualLayerTask class is not thread safe and calls this
460
461 if ( mDataProvider )
462 {
463 mDataProvider->reloadData();
464 updateFields();
465 }
466}
467
469{
470 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
472
473 return new QgsVectorLayerRenderer( this, rendererContext );
474}
475
476
477void QgsVectorLayer::drawVertexMarker( double x, double y, QPainter &p, Qgis::VertexMarkerType type, int m )
478{
479 switch ( type )
480 {
482 p.setPen( QColor( 50, 100, 120, 200 ) );
483 p.setBrush( QColor( 200, 200, 210, 120 ) );
484 p.drawEllipse( x - m, y - m, m * 2 + 1, m * 2 + 1 );
485 break;
486
488 p.setPen( QColor( 255, 0, 0 ) );
489 p.drawLine( x - m, y + m, x + m, y - m );
490 p.drawLine( x - m, y - m, x + m, y + m );
491 break;
492
494 break;
495 }
496}
497
499{
501
502 mSelectedFeatureIds.insert( fid );
503 mPreviousSelectedFeatureIds.clear();
504
505 emit selectionChanged( QgsFeatureIds() << fid, QgsFeatureIds(), false );
506}
507
508void QgsVectorLayer::select( const QgsFeatureIds &featureIds )
509{
511
512 mSelectedFeatureIds.unite( featureIds );
513 mPreviousSelectedFeatureIds.clear();
514
515 emit selectionChanged( featureIds, QgsFeatureIds(), false );
516}
517
519{
521
522 mSelectedFeatureIds.remove( fid );
523 mPreviousSelectedFeatureIds.clear();
524
525 emit selectionChanged( QgsFeatureIds(), QgsFeatureIds() << fid, false );
526}
527
529{
531
532 mSelectedFeatureIds.subtract( featureIds );
533 mPreviousSelectedFeatureIds.clear();
534
535 emit selectionChanged( QgsFeatureIds(), featureIds, false );
536}
537
539{
541
542 // normalize the rectangle
543 rect.normalize();
544
545 QgsFeatureIds newSelection;
546
548 .setFilterRect( rect )
550 .setNoAttributes() );
551
552 QgsFeature feat;
553 while ( features.nextFeature( feat ) )
554 {
555 newSelection << feat.id();
556 }
557 features.close();
558
559 selectByIds( newSelection, behavior );
560}
561
562void QgsVectorLayer::selectByExpression( const QString &expression, Qgis::SelectBehavior behavior, QgsExpressionContext *context )
563{
565
566 QgsFeatureIds newSelection;
567
568 std::optional< QgsExpressionContext > defaultContext;
569 if ( !context )
570 {
571 defaultContext.emplace( QgsExpressionContextUtils::globalProjectLayerScopes( this ) );
572 context = &defaultContext.value();
573 }
574
576 {
578 .setExpressionContext( *context )
581
582 QgsFeatureIterator features = getFeatures( request );
583
584 if ( behavior == Qgis::SelectBehavior::AddToSelection )
585 {
586 newSelection = selectedFeatureIds();
587 }
588 QgsFeature feat;
589 while ( features.nextFeature( feat ) )
590 {
591 newSelection << feat.id();
592 }
593 features.close();
594 }
596 {
597 QgsExpression exp( expression );
598 exp.prepare( context );
599
600 QgsFeatureIds oldSelection = selectedFeatureIds();
601 QgsFeatureRequest request = QgsFeatureRequest().setFilterFids( oldSelection );
602
603 //refine request
604 if ( !exp.needsGeometry() )
607
608 QgsFeatureIterator features = getFeatures( request );
609 QgsFeature feat;
610 while ( features.nextFeature( feat ) )
611 {
612 context->setFeature( feat );
613 bool matches = exp.evaluate( context ).toBool();
614
615 if ( matches && behavior == Qgis::SelectBehavior::IntersectSelection )
616 {
617 newSelection << feat.id();
618 }
619 else if ( !matches && behavior == Qgis::SelectBehavior::RemoveFromSelection )
620 {
621 newSelection << feat.id();
622 }
623 }
624 }
625
626 selectByIds( newSelection );
627}
628
630{
632
633 QgsFeatureIds newSelection;
634
635 switch ( behavior )
636 {
638 newSelection = ids;
639 break;
640
642 newSelection = mSelectedFeatureIds + ids;
643 break;
644
646 newSelection = mSelectedFeatureIds - ids;
647 break;
648
650 newSelection = mSelectedFeatureIds.intersect( ids );
651 break;
652 }
653
654 QgsFeatureIds deselectedFeatures = mSelectedFeatureIds - newSelection;
655 mSelectedFeatureIds = newSelection;
656 mPreviousSelectedFeatureIds.clear();
657
658 emit selectionChanged( newSelection, deselectedFeatures, true );
659}
660
661void QgsVectorLayer::modifySelection( const QgsFeatureIds &selectIds, const QgsFeatureIds &deselectIds )
662{
664
665 QgsFeatureIds intersectingIds = selectIds & deselectIds;
666 if ( !intersectingIds.isEmpty() )
667 {
668 QgsDebugMsgLevel( QStringLiteral( "Trying to select and deselect the same item at the same time. Unsure what to do. Selecting dubious items." ), 3 );
669 }
670
671 mSelectedFeatureIds -= deselectIds;
672 mSelectedFeatureIds += selectIds;
673 mPreviousSelectedFeatureIds.clear();
674
675 emit selectionChanged( selectIds, deselectIds - intersectingIds, false );
676}
677
679{
681
683 ids.subtract( mSelectedFeatureIds );
684 selectByIds( ids );
685}
686
693
695{
697
698 // normalize the rectangle
699 rect.normalize();
700
702 .setFilterRect( rect )
704 .setNoAttributes() );
705
706 QgsFeatureIds selectIds;
707 QgsFeatureIds deselectIds;
708
709 QgsFeature fet;
710 while ( fit.nextFeature( fet ) )
711 {
712 if ( mSelectedFeatureIds.contains( fet.id() ) )
713 {
714 deselectIds << fet.id();
715 }
716 else
717 {
718 selectIds << fet.id();
719 }
720 }
721
722 modifySelection( selectIds, deselectIds );
723}
724
726{
728
729 if ( mSelectedFeatureIds.isEmpty() )
730 return;
731
732 const QgsFeatureIds previous = mSelectedFeatureIds;
734 mPreviousSelectedFeatureIds = previous;
735}
736
738{
740
741 if ( mPreviousSelectedFeatureIds.isEmpty() || !mSelectedFeatureIds.empty() )
742 return;
743
744 selectByIds( mPreviousSelectedFeatureIds );
745}
746
748{
749 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
751
752 return mDataProvider;
753}
754
756{
757 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
759
760 return mDataProvider;
761}
762
764{
765 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
767
768 return mSelectionProperties;
769}
770
777
784
786{
788
789 QgsProfileRequest modifiedRequest( request );
790 modifiedRequest.expressionContext().appendScope( createExpressionContextScope() );
791 return new QgsVectorLayerProfileGenerator( this, modifiedRequest );
792}
793
794void QgsVectorLayer::setProviderEncoding( const QString &encoding )
795{
797
798 if ( isValid() && mDataProvider && mDataProvider->encoding() != encoding )
799 {
800 mDataProvider->setEncoding( encoding );
801 updateFields();
802 }
803}
804
806{
808
809 delete mDiagramRenderer;
810 mDiagramRenderer = r;
811 emit rendererChanged();
812 emit styleChanged();
813}
814
816{
817 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
819
820 return QgsWkbTypes::geometryType( mWkbType );
821}
822
824{
826
827 return mWkbType;
828}
829
831{
833
834 if ( !isValid() || !isSpatial() || mSelectedFeatureIds.isEmpty() || !mDataProvider ) //no selected features
835 {
836 return QgsRectangle( 0, 0, 0, 0 );
837 }
838
839 QgsRectangle r, retval;
840 retval.setNull();
841
842 QgsFeature fet;
844 {
846 .setFilterFids( mSelectedFeatureIds )
847 .setNoAttributes() );
848
849 while ( fit.nextFeature( fet ) )
850 {
851 if ( !fet.hasGeometry() )
852 continue;
853 r = fet.geometry().boundingBox();
854 retval.combineExtentWith( r );
855 }
856 }
857 else
858 {
860 .setNoAttributes() );
861
862 while ( fit.nextFeature( fet ) )
863 {
864 if ( mSelectedFeatureIds.contains( fet.id() ) )
865 {
866 if ( fet.hasGeometry() )
867 {
868 r = fet.geometry().boundingBox();
869 retval.combineExtentWith( r );
870 }
871 }
872 }
873 }
874
875 if ( retval.width() == 0.0 || retval.height() == 0.0 )
876 {
877 // If all of the features are at the one point, buffer the
878 // rectangle a bit. If they are all at zero, do something a bit
879 // more crude.
880
881 if ( retval.xMinimum() == 0.0 && retval.xMaximum() == 0.0 &&
882 retval.yMinimum() == 0.0 && retval.yMaximum() == 0.0 )
883 {
884 retval.set( -1.0, -1.0, 1.0, 1.0 );
885 }
886 }
887
888 return retval;
889}
890
892{
893 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
895
896 return mLabelsEnabled && static_cast< bool >( mLabeling );
897}
898
900{
902
903 mLabelsEnabled = enabled;
904}
905
907{
908 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
910
911 if ( !mDiagramRenderer || !mDiagramLayerSettings )
912 return false;
913
914 QList<QgsDiagramSettings> settingList = mDiagramRenderer->diagramSettings();
915 if ( !settingList.isEmpty() )
916 {
917 return settingList.at( 0 ).enabled;
918 }
919 return false;
920}
921
922long long QgsVectorLayer::featureCount( const QString &legendKey ) const
923{
925
926 if ( !mSymbolFeatureCounted )
927 return -1;
928
929 return mSymbolFeatureCountMap.value( legendKey, -1 );
930}
931
932QgsFeatureIds QgsVectorLayer::symbolFeatureIds( const QString &legendKey ) const
933{
935
936 if ( !mSymbolFeatureCounted )
937 return QgsFeatureIds();
938
939 return mSymbolFeatureIdMap.value( legendKey, QgsFeatureIds() );
940}
942{
944
945 if ( ( mSymbolFeatureCounted || mFeatureCounter ) && !( storeSymbolFids && mSymbolFeatureIdMap.isEmpty() ) )
946 return mFeatureCounter;
947
948 mSymbolFeatureCountMap.clear();
949 mSymbolFeatureIdMap.clear();
950
951 if ( !isValid() )
952 {
953 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer" ), 3 );
954 return mFeatureCounter;
955 }
956 if ( !mDataProvider )
957 {
958 QgsDebugMsgLevel( QStringLiteral( "invoked with null mDataProvider" ), 3 );
959 return mFeatureCounter;
960 }
961 if ( !mRenderer )
962 {
963 QgsDebugMsgLevel( QStringLiteral( "invoked with null mRenderer" ), 3 );
964 return mFeatureCounter;
965 }
966
967 if ( !mFeatureCounter || ( storeSymbolFids && mSymbolFeatureIdMap.isEmpty() ) )
968 {
969 mFeatureCounter = new QgsVectorLayerFeatureCounter( this, QgsExpressionContext(), storeSymbolFids );
970 connect( mFeatureCounter, &QgsTask::taskCompleted, this, &QgsVectorLayer::onFeatureCounterCompleted, Qt::UniqueConnection );
971 connect( mFeatureCounter, &QgsTask::taskTerminated, this, &QgsVectorLayer::onFeatureCounterTerminated, Qt::UniqueConnection );
972 QgsApplication::taskManager()->addTask( mFeatureCounter );
973 }
974
975 return mFeatureCounter;
976}
977
979{
981
982 // do not update extent by default when trust project option is activated
983 if ( force || !mReadExtentFromXml || ( mReadExtentFromXml && mXmlExtent2D.isNull() && mXmlExtent3D.isNull() ) )
984 {
985 mValidExtent2D = false;
986 mValidExtent3D = false;
987 }
988}
989
991{
993
995 mValidExtent2D = true;
996}
997
999{
1001
1003 mValidExtent3D = true;
1004}
1005
1006void QgsVectorLayer::updateDefaultValues( QgsFeatureId fid, QgsFeature feature, QgsExpressionContext *context )
1007{
1009
1010 if ( !mDefaultValueOnUpdateFields.isEmpty() )
1011 {
1012 if ( !feature.isValid() )
1013 feature = getFeature( fid );
1014
1015 int size = mFields.size();
1016 for ( int idx : std::as_const( mDefaultValueOnUpdateFields ) )
1017 {
1018 if ( idx < 0 || idx >= size )
1019 continue;
1020 feature.setAttribute( idx, defaultValue( idx, feature, context ) );
1021 updateFeature( feature, true );
1022 }
1023 }
1024}
1025
1027{
1029
1030 QgsRectangle rect;
1031 rect.setNull();
1032
1033 if ( !isSpatial() )
1034 return rect;
1035
1036 if ( mDataProvider && mDataProvider->isValid() && ( mDataProvider->flags() & Qgis::DataProviderFlag::FastExtent2D ) )
1037 {
1038 // Provider has a trivial 2D extent calculation => always get extent from provider.
1039 // Things are nice and simple this way, e.g. we can always trust that this extent is
1040 // accurate and up to date.
1041 updateExtent( mDataProvider->extent() );
1042 mValidExtent2D = true;
1043 mLazyExtent2D = false;
1044 }
1045 else
1046 {
1047 if ( !mValidExtent2D && mLazyExtent2D && mReadExtentFromXml && !mXmlExtent2D.isNull() )
1048 {
1049 updateExtent( mXmlExtent2D );
1050 mValidExtent2D = true;
1051 mLazyExtent2D = false;
1052 }
1053
1054 if ( !mValidExtent2D && mLazyExtent2D && mDataProvider && mDataProvider->isValid() )
1055 {
1056 // store the extent
1057 updateExtent( mDataProvider->extent() );
1058 mValidExtent2D = true;
1059 mLazyExtent2D = false;
1060
1061 // show the extent
1062 QgsDebugMsgLevel( QStringLiteral( "2D Extent of layer: %1" ).arg( mExtent2D.toString() ), 3 );
1063 }
1064 }
1065
1066 if ( mValidExtent2D )
1067 return QgsMapLayer::extent();
1068
1069 if ( !isValid() || !mDataProvider )
1070 {
1071 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
1072 return rect;
1073 }
1074
1075 if ( !mEditBuffer ||
1076 ( !mDataProvider->transaction() && ( mEditBuffer->deletedFeatureIds().isEmpty() && mEditBuffer->changedGeometries().isEmpty() ) ) ||
1078 {
1079 mDataProvider->updateExtents();
1080
1081 // get the extent of the layer from the provider
1082 // but only when there are some features already
1083 if ( mDataProvider->featureCount() != 0 )
1084 {
1085 const QgsRectangle r = mDataProvider->extent();
1086 rect.combineExtentWith( r );
1087 }
1088
1089 if ( mEditBuffer && !mDataProvider->transaction() )
1090 {
1091 const auto addedFeatures = mEditBuffer->addedFeatures();
1092 for ( QgsFeatureMap::const_iterator it = addedFeatures.constBegin(); it != addedFeatures.constEnd(); ++it )
1093 {
1094 if ( it->hasGeometry() )
1095 {
1096 const QgsRectangle r = it->geometry().boundingBox();
1097 rect.combineExtentWith( r );
1098 }
1099 }
1100 }
1101 }
1102 else
1103 {
1105 .setNoAttributes() );
1106
1107 QgsFeature fet;
1108 while ( fit.nextFeature( fet ) )
1109 {
1110 if ( fet.hasGeometry() && fet.geometry().type() != Qgis::GeometryType::Unknown )
1111 {
1112 const QgsRectangle bb = fet.geometry().boundingBox();
1113 rect.combineExtentWith( bb );
1114 }
1115 }
1116 }
1117
1118 if ( rect.xMinimum() > rect.xMaximum() && rect.yMinimum() > rect.yMaximum() )
1119 {
1120 // special case when there are no features in provider nor any added
1121 rect = QgsRectangle(); // use rectangle with zero coordinates
1122 }
1123
1124 updateExtent( rect );
1125 mValidExtent2D = true;
1126
1127 // Send this (hopefully) up the chain to the map canvas
1128 emit recalculateExtents();
1129
1130 return rect;
1131}
1132
1134{
1136
1137 // if data is 2D, redirect to 2D extend computation, and save it as 2D extent (in 3D bbox)
1138 if ( mDataProvider && mDataProvider->elevationProperties() && !mDataProvider->elevationProperties()->containsElevationData() )
1139 {
1140 return QgsBox3D( extent() );
1141 }
1142
1144 extent.setNull();
1145
1146 if ( !isSpatial() )
1147 return extent;
1148
1149 if ( mDataProvider && mDataProvider->isValid() && ( mDataProvider->flags() & Qgis::DataProviderFlag::FastExtent3D ) )
1150 {
1151 // Provider has a trivial 3D extent calculation => always get extent from provider.
1152 // Things are nice and simple this way, e.g. we can always trust that this extent is
1153 // accurate and up to date.
1154 updateExtent( mDataProvider->extent3D() );
1155 mValidExtent3D = true;
1156 mLazyExtent3D = false;
1157 }
1158 else
1159 {
1160 if ( !mValidExtent3D && mLazyExtent3D && mReadExtentFromXml && !mXmlExtent3D.isNull() )
1161 {
1162 updateExtent( mXmlExtent3D );
1163 mValidExtent3D = true;
1164 mLazyExtent3D = false;
1165 }
1166
1167 if ( !mValidExtent3D && mLazyExtent3D && mDataProvider && mDataProvider->isValid() )
1168 {
1169 // store the extent
1170 updateExtent( mDataProvider->extent3D() );
1171 mValidExtent3D = true;
1172 mLazyExtent3D = false;
1173
1174 // show the extent
1175 QgsDebugMsgLevel( QStringLiteral( "3D Extent of layer: %1" ).arg( mExtent3D.toString() ), 3 );
1176 }
1177 }
1178
1179 if ( mValidExtent3D )
1180 return QgsMapLayer::extent3D();
1181
1182 if ( !isValid() || !mDataProvider )
1183 {
1184 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
1185 return extent;
1186 }
1187
1188 if ( !mEditBuffer ||
1189 ( !mDataProvider->transaction() && ( mEditBuffer->deletedFeatureIds().isEmpty() && mEditBuffer->changedGeometries().isEmpty() ) ) ||
1191 {
1192 mDataProvider->updateExtents();
1193
1194 // get the extent of the layer from the provider
1195 // but only when there are some features already
1196 if ( mDataProvider->featureCount() != 0 )
1197 {
1198 const QgsBox3D ext = mDataProvider->extent3D();
1199 extent.combineWith( ext );
1200 }
1201
1202 if ( mEditBuffer && !mDataProvider->transaction() )
1203 {
1204 const auto addedFeatures = mEditBuffer->addedFeatures();
1205 for ( QgsFeatureMap::const_iterator it = addedFeatures.constBegin(); it != addedFeatures.constEnd(); ++it )
1206 {
1207 if ( it->hasGeometry() )
1208 {
1209 const QgsBox3D bbox = it->geometry().boundingBox3D();
1210 extent.combineWith( bbox );
1211 }
1212 }
1213 }
1214 }
1215 else
1216 {
1218 .setNoAttributes() );
1219
1220 QgsFeature fet;
1221 while ( fit.nextFeature( fet ) )
1222 {
1223 if ( fet.hasGeometry() && fet.geometry().type() != Qgis::GeometryType::Unknown )
1224 {
1225 const QgsBox3D bb = fet.geometry().boundingBox3D();
1226 extent.combineWith( bb );
1227 }
1228 }
1229 }
1230
1231 if ( extent.xMinimum() > extent.xMaximum() && extent.yMinimum() > extent.yMaximum() && extent.zMinimum() > extent.zMaximum() )
1232 {
1233 // special case when there are no features in provider nor any added
1234 extent = QgsBox3D(); // use rectangle with zero coordinates
1235 }
1236
1237 updateExtent( extent );
1238 mValidExtent3D = true;
1239
1240 // Send this (hopefully) up the chain to the map canvas
1241 emit recalculateExtents();
1242
1243 return extent;
1244}
1245
1252
1259
1261{
1263
1264 if ( !isValid() || !mDataProvider )
1265 {
1266 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
1267 return customProperty( QStringLiteral( "storedSubsetString" ) ).toString();
1268 }
1269 return mDataProvider->subsetString();
1270}
1271
1272bool QgsVectorLayer::setSubsetString( const QString &subset )
1273{
1275
1276 if ( !isValid() || !mDataProvider )
1277 {
1278 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider or while editing" ), 3 );
1279 setCustomProperty( QStringLiteral( "storedSubsetString" ), subset );
1280 return false;
1281 }
1282 else if ( mEditBuffer )
1283 {
1284 QgsDebugMsgLevel( QStringLiteral( "invoked while editing" ), 3 );
1285 return false;
1286 }
1287
1288 if ( subset == mDataProvider->subsetString() )
1289 return true;
1290
1291 bool res = mDataProvider->setSubsetString( subset );
1292
1293 // get the updated data source string from the provider
1294 mDataSource = mDataProvider->dataSourceUri();
1295 updateExtents();
1296 updateFields();
1297
1298 if ( res )
1299 {
1300 emit subsetStringChanged();
1302 }
1303
1304 return res;
1305}
1306
1308{
1309 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
1311
1312 if ( isValid() && mDataProvider && !mEditBuffer && ( isSpatial() && geometryType() != Qgis::GeometryType::Point ) && ( mSimplifyMethod.simplifyHints() & simplifyHint ) && renderContext.useRenderingOptimization() )
1313 {
1314 double maximumSimplificationScale = mSimplifyMethod.maximumScale();
1315
1316 // check maximum scale at which generalisation should be carried out
1317 return !( maximumSimplificationScale > 1 && renderContext.rendererScale() <= maximumSimplificationScale );
1318 }
1319 return false;
1320}
1321
1323{
1325
1326 return mConditionalStyles;
1327}
1328
1330{
1331 // non fatal for now -- the aggregate expression functions are not thread safe and call this
1333
1334 if ( !isValid() || !mDataProvider )
1335 return QgsFeatureIterator();
1336
1337 return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( new QgsVectorLayerFeatureSource( this ), true, request ) );
1338}
1339
1341{
1343
1344 QgsFeature feature;
1346 if ( feature.isValid() )
1347 return feature.geometry();
1348 else
1349 return QgsGeometry();
1350}
1351
1353{
1355
1356 if ( !isValid() || !mEditBuffer || !mDataProvider )
1357 return false;
1358
1359
1360 if ( mGeometryOptions->isActive() )
1361 {
1362 QgsGeometry geom = feature.geometry();
1363 mGeometryOptions->apply( geom );
1364 feature.setGeometry( geom );
1365 }
1366
1367 bool success = mEditBuffer->addFeature( feature );
1368
1369 if ( success )
1370 {
1371 updateExtents();
1372
1373 if ( mJoinBuffer->containsJoins() )
1374 success = mJoinBuffer->addFeature( feature );
1375 }
1376
1377 return success;
1378}
1379
1380bool QgsVectorLayer::updateFeature( QgsFeature &updatedFeature, bool skipDefaultValues )
1381{
1383
1384 if ( !mEditBuffer || !mDataProvider )
1385 {
1386 return false;
1387 }
1388
1389 QgsFeature currentFeature = getFeature( updatedFeature.id() );
1390 if ( currentFeature.isValid() )
1391 {
1392 bool hasChanged = false;
1393 bool hasError = false;
1394
1395 if ( ( updatedFeature.hasGeometry() || currentFeature.hasGeometry() ) && !updatedFeature.geometry().equals( currentFeature.geometry() ) )
1396 {
1397 QgsGeometry geometry = updatedFeature.geometry();
1398 if ( changeGeometry( updatedFeature.id(), geometry, true ) )
1399 {
1400 hasChanged = true;
1401 updatedFeature.setGeometry( geometry );
1402 }
1403 else
1404 {
1405 QgsDebugMsgLevel( QStringLiteral( "geometry of feature %1 could not be changed." ).arg( updatedFeature.id() ), 3 );
1406 }
1407 }
1408
1409 QgsAttributes fa = updatedFeature.attributes();
1410 QgsAttributes ca = currentFeature.attributes();
1411
1412 for ( int attr = 0; attr < fa.count(); ++attr )
1413 {
1414 if ( !qgsVariantEqual( fa.at( attr ), ca.at( attr ) ) )
1415 {
1416 if ( changeAttributeValue( updatedFeature.id(), attr, fa.at( attr ), ca.at( attr ), true ) )
1417 {
1418 hasChanged = true;
1419 }
1420 else
1421 {
1422 QgsDebugMsgLevel( QStringLiteral( "attribute %1 of feature %2 could not be changed." ).arg( attr ).arg( updatedFeature.id() ), 3 );
1423 hasError = true;
1424 }
1425 }
1426 }
1427 if ( hasChanged && !mDefaultValueOnUpdateFields.isEmpty() && !skipDefaultValues )
1428 updateDefaultValues( updatedFeature.id(), updatedFeature );
1429
1430 return !hasError;
1431 }
1432 else
1433 {
1434 QgsDebugMsgLevel( QStringLiteral( "feature %1 could not be retrieved" ).arg( updatedFeature.id() ), 3 );
1435 return false;
1436 }
1437}
1438
1439
1440bool QgsVectorLayer::insertVertex( double x, double y, QgsFeatureId atFeatureId, int beforeVertex )
1441{
1443
1444 if ( !isValid() || !mEditBuffer || !mDataProvider )
1445 return false;
1446
1447 QgsVectorLayerEditUtils utils( this );
1448 bool result = utils.insertVertex( x, y, atFeatureId, beforeVertex );
1449 if ( result )
1450 updateExtents();
1451 return result;
1452}
1453
1454
1455bool QgsVectorLayer::insertVertex( const QgsPoint &point, QgsFeatureId atFeatureId, int beforeVertex )
1456{
1458
1459 if ( !isValid() || !mEditBuffer || !mDataProvider )
1460 return false;
1461
1462 QgsVectorLayerEditUtils utils( this );
1463 bool result = utils.insertVertex( point, atFeatureId, beforeVertex );
1464 if ( result )
1465 updateExtents();
1466 return result;
1467}
1468
1469
1470bool QgsVectorLayer::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
1471{
1473
1474 if ( !isValid() || !mEditBuffer || !mDataProvider )
1475 return false;
1476
1477 QgsVectorLayerEditUtils utils( this );
1478 bool result = utils.moveVertex( x, y, atFeatureId, atVertex );
1479
1480 if ( result )
1481 updateExtents();
1482 return result;
1483}
1484
1485bool QgsVectorLayer::moveVertex( const QgsPoint &p, QgsFeatureId atFeatureId, int atVertex )
1486{
1488
1489 if ( !isValid() || !mEditBuffer || !mDataProvider )
1490 return false;
1491
1492 QgsVectorLayerEditUtils utils( this );
1493 bool result = utils.moveVertex( p, atFeatureId, atVertex );
1494
1495 if ( result )
1496 updateExtents();
1497 return result;
1498}
1499
1501{
1503
1504 if ( !isValid() || !mEditBuffer || !mDataProvider )
1506
1507 QgsVectorLayerEditUtils utils( this );
1508 Qgis::VectorEditResult result = utils.deleteVertex( featureId, vertex );
1509
1510 if ( result == Qgis::VectorEditResult::Success )
1511 updateExtents();
1512 return result;
1513}
1514
1515
1517{
1519
1520 if ( !isValid() || !mDataProvider || !( mDataProvider->capabilities() & Qgis::VectorProviderCapability::DeleteFeatures ) )
1521 {
1522 return false;
1523 }
1524
1525 if ( !isEditable() )
1526 {
1527 return false;
1528 }
1529
1530 int deleted = 0;
1531 int count = mSelectedFeatureIds.size();
1532 // Make a copy since deleteFeature modifies mSelectedFeatureIds
1533 QgsFeatureIds selectedFeatures( mSelectedFeatureIds );
1534 for ( QgsFeatureId fid : std::as_const( selectedFeatures ) )
1535 {
1536 deleted += deleteFeature( fid, context ); // removes from selection
1537 }
1538
1540 updateExtents();
1541
1542 if ( deletedCount )
1543 {
1544 *deletedCount = deleted;
1545 }
1546
1547 return deleted == count;
1548}
1549
1550static const QgsPointSequence vectorPointXY2pointSequence( const QVector<QgsPointXY> &points )
1551{
1552 QgsPointSequence pts;
1553 pts.reserve( points.size() );
1554 QVector<QgsPointXY>::const_iterator it = points.constBegin();
1555 while ( it != points.constEnd() )
1556 {
1557 pts.append( QgsPoint( *it ) );
1558 ++it;
1559 }
1560 return pts;
1561}
1562Qgis::GeometryOperationResult QgsVectorLayer::addRing( const QVector<QgsPointXY> &ring, QgsFeatureId *featureId )
1563{
1565
1566 return addRing( vectorPointXY2pointSequence( ring ), featureId );
1567}
1568
1570{
1572
1573 if ( !isValid() || !mEditBuffer || !mDataProvider )
1575
1576 QgsVectorLayerEditUtils utils( this );
1578
1579 //first try with selected features
1580 if ( !mSelectedFeatureIds.isEmpty() )
1581 {
1582 result = utils.addRing( ring, mSelectedFeatureIds, featureId );
1583 }
1584
1586 {
1587 //try with all intersecting features
1588 result = utils.addRing( ring, QgsFeatureIds(), featureId );
1589 }
1590
1591 return result;
1592}
1593
1595{
1597
1598 if ( !isValid() || !mEditBuffer || !mDataProvider )
1599 {
1600 delete ring;
1602 }
1603
1604 if ( !ring )
1605 {
1607 }
1608
1609 if ( !ring->isClosed() )
1610 {
1611 delete ring;
1613 }
1614
1615 QgsVectorLayerEditUtils utils( this );
1617
1618 //first try with selected features
1619 if ( !mSelectedFeatureIds.isEmpty() )
1620 {
1621 result = utils.addRing( static_cast< QgsCurve * >( ring->clone() ), mSelectedFeatureIds, featureId );
1622 }
1623
1625 {
1626 //try with all intersecting features
1627 result = utils.addRing( static_cast< QgsCurve * >( ring->clone() ), QgsFeatureIds(), featureId );
1628 }
1629
1630 delete ring;
1631 return result;
1632}
1633
1635{
1637
1638 QgsPointSequence pts;
1639 pts.reserve( points.size() );
1640 for ( QList<QgsPointXY>::const_iterator it = points.constBegin(); it != points.constEnd() ; ++it )
1641 {
1642 pts.append( QgsPoint( *it ) );
1643 }
1644 return addPart( pts );
1645}
1646
1647#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1648Qgis::GeometryOperationResult QgsVectorLayer::addPart( const QVector<QgsPointXY> &points )
1649{
1651
1652 return addPart( vectorPointXY2pointSequence( points ) );
1653}
1654#endif
1655
1657{
1659
1660 if ( !isValid() || !mEditBuffer || !mDataProvider )
1662
1663 //number of selected features must be 1
1664
1665 if ( mSelectedFeatureIds.empty() )
1666 {
1667 QgsDebugMsgLevel( QStringLiteral( "Number of selected features <1" ), 3 );
1669 }
1670 else if ( mSelectedFeatureIds.size() > 1 )
1671 {
1672 QgsDebugMsgLevel( QStringLiteral( "Number of selected features >1" ), 3 );
1674 }
1675
1676 QgsVectorLayerEditUtils utils( this );
1677 Qgis::GeometryOperationResult result = utils.addPart( points, *mSelectedFeatureIds.constBegin() );
1678
1680 updateExtents();
1681 return result;
1682}
1683
1685{
1687
1688 if ( !isValid() || !mEditBuffer || !mDataProvider )
1690
1691 //number of selected features must be 1
1692
1693 if ( mSelectedFeatureIds.empty() )
1694 {
1695 QgsDebugMsgLevel( QStringLiteral( "Number of selected features <1" ), 3 );
1697 }
1698 else if ( mSelectedFeatureIds.size() > 1 )
1699 {
1700 QgsDebugMsgLevel( QStringLiteral( "Number of selected features >1" ), 3 );
1702 }
1703
1704 QgsVectorLayerEditUtils utils( this );
1705 Qgis::GeometryOperationResult result = utils.addPart( ring, *mSelectedFeatureIds.constBegin() );
1706
1708 updateExtents();
1709 return result;
1710}
1711
1712// TODO QGIS 4.0 -- this should return Qgis::GeometryOperationResult, not int
1713int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double dy )
1714{
1716
1717 if ( !isValid() || !mEditBuffer || !mDataProvider )
1718 return static_cast< int >( Qgis::GeometryOperationResult::LayerNotEditable );
1719
1720 QgsVectorLayerEditUtils utils( this );
1721 int result = utils.translateFeature( featureId, dx, dy );
1722
1723 if ( result == static_cast< int >( Qgis::GeometryOperationResult::Success ) )
1724 updateExtents();
1725 return result;
1726}
1727
1728Qgis::GeometryOperationResult QgsVectorLayer::splitParts( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
1729{
1731
1732 return splitParts( vectorPointXY2pointSequence( splitLine ), topologicalEditing );
1733}
1734
1736{
1738
1739 if ( !isValid() || !mEditBuffer || !mDataProvider )
1741
1742 QgsVectorLayerEditUtils utils( this );
1743 return utils.splitParts( splitLine, topologicalEditing );
1744}
1745
1746Qgis::GeometryOperationResult QgsVectorLayer::splitFeatures( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
1747{
1749
1750 return splitFeatures( vectorPointXY2pointSequence( splitLine ), topologicalEditing );
1751}
1752
1754{
1756
1757 QgsLineString splitLineString( splitLine );
1758 QgsPointSequence topologyTestPoints;
1759 bool preserveCircular = false;
1760 return splitFeatures( &splitLineString, topologyTestPoints, preserveCircular, topologicalEditing );
1761}
1762
1763Qgis::GeometryOperationResult QgsVectorLayer::splitFeatures( const QgsCurve *curve, QgsPointSequence &topologyTestPoints, bool preserveCircular, bool topologicalEditing )
1764{
1766
1767 if ( !isValid() || !mEditBuffer || !mDataProvider )
1769
1770 QgsVectorLayerEditUtils utils( this );
1771 return utils.splitFeatures( curve, topologyTestPoints, preserveCircular, topologicalEditing );
1772}
1773
1775{
1777
1778 if ( !isValid() || !mEditBuffer || !mDataProvider )
1779 return -1;
1780
1781 QgsVectorLayerEditUtils utils( this );
1782 return utils.addTopologicalPoints( geom );
1783}
1784
1791
1793{
1795
1796 if ( !isValid() || !mEditBuffer || !mDataProvider )
1797 return -1;
1798
1799 QgsVectorLayerEditUtils utils( this );
1800 return utils.addTopologicalPoints( p );
1801}
1802
1804{
1806
1807 if ( !mValid || !mEditBuffer || !mDataProvider )
1808 return -1;
1809
1810 QgsVectorLayerEditUtils utils( this );
1811 return utils.addTopologicalPoints( ps );
1812}
1813
1815{
1817
1818 if ( mLabeling == labeling )
1819 return;
1820
1821 delete mLabeling;
1822 mLabeling = labeling;
1823}
1824
1826{
1828
1829 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
1830 return project()->startEditing( this );
1831
1832 if ( !isValid() || !mDataProvider )
1833 {
1834 return false;
1835 }
1836
1837 // allow editing if provider supports any of the capabilities
1838 if ( !supportsEditing() )
1839 {
1840 return false;
1841 }
1842
1843 if ( mEditBuffer )
1844 {
1845 // editing already underway
1846 return false;
1847 }
1848
1849 mDataProvider->enterUpdateMode();
1850
1851 emit beforeEditingStarted();
1852
1853 createEditBuffer();
1854
1855 updateFields();
1856
1857 emit editingStarted();
1858
1859 return true;
1860}
1861
1863{
1865
1866 if ( mDataProvider )
1867 mDataProvider->setTransformContext( transformContext );
1868}
1869
1876
1878{
1880
1881 if ( mRenderer )
1882 if ( !mRenderer->accept( visitor ) )
1883 return false;
1884
1885 if ( mLabeling )
1886 if ( !mLabeling->accept( visitor ) )
1887 return false;
1888
1889 return true;
1890}
1891
1892bool QgsVectorLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1893{
1895
1896 QgsDebugMsgLevel( QStringLiteral( "Datasource in QgsVectorLayer::readXml: %1" ).arg( mDataSource.toLocal8Bit().data() ), 3 );
1897
1898 //process provider key
1899 QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
1900
1901 if ( pkeyNode.isNull() )
1902 {
1903 mProviderKey.clear();
1904 }
1905 else
1906 {
1907 QDomElement pkeyElt = pkeyNode.toElement();
1908 mProviderKey = pkeyElt.text();
1909 }
1910
1911 // determine type of vector layer
1912 if ( !mProviderKey.isNull() )
1913 {
1914 // if the provider string isn't empty, then we successfully
1915 // got the stored provider
1916 }
1917 else if ( mDataSource.contains( QLatin1String( "dbname=" ) ) )
1918 {
1919 mProviderKey = QStringLiteral( "postgres" );
1920 }
1921 else
1922 {
1923 mProviderKey = QStringLiteral( "ogr" );
1924 }
1925
1926 const QDomElement elem = layer_node.toElement();
1928
1929 mDataSourceReadOnly = mReadFlags & QgsMapLayer::FlagForceReadOnly;
1931
1932 if ( ( mReadFlags & QgsMapLayer::FlagDontResolveLayers ) || !setDataProvider( mProviderKey, options, flags ) )
1933 {
1935 {
1936 QgsDebugError( QStringLiteral( "Could not set data provider for layer %1" ).arg( publicSource() ) );
1937 }
1938
1939 // for invalid layer sources, we fallback to stored wkbType if available
1940 if ( elem.hasAttribute( QStringLiteral( "wkbType" ) ) )
1941 mWkbType = qgsEnumKeyToValue( elem.attribute( QStringLiteral( "wkbType" ) ), mWkbType );
1942 }
1943
1944 QDomElement pkeyElem = pkeyNode.toElement();
1945 if ( !pkeyElem.isNull() )
1946 {
1947 QString encodingString = pkeyElem.attribute( QStringLiteral( "encoding" ) );
1948 if ( mDataProvider && !encodingString.isEmpty() )
1949 {
1950 mDataProvider->setEncoding( encodingString );
1951 }
1952 }
1953
1954 // load vector joins - does not resolve references to layers yet
1955 mJoinBuffer->readXml( layer_node );
1956
1957 updateFields();
1958
1959 // If style doesn't include a legend, we'll need to make a default one later...
1960 mSetLegendFromStyle = false;
1961
1962 QString errorMsg;
1963 if ( !readSymbology( layer_node, errorMsg, context ) )
1964 {
1965 return false;
1966 }
1967
1968 readStyleManager( layer_node );
1969
1970 QDomNode depsNode = layer_node.namedItem( QStringLiteral( "dataDependencies" ) );
1971 QDomNodeList depsNodes = depsNode.childNodes();
1972 QSet<QgsMapLayerDependency> sources;
1973 for ( int i = 0; i < depsNodes.count(); i++ )
1974 {
1975 QString source = depsNodes.at( i ).toElement().attribute( QStringLiteral( "id" ) );
1976 sources << QgsMapLayerDependency( source );
1977 }
1978 setDependencies( sources );
1979
1980 if ( !mSetLegendFromStyle )
1982
1983 // read extent
1985 {
1986 mReadExtentFromXml = true;
1987 }
1988 if ( mReadExtentFromXml )
1989 {
1990 const QDomNode extentNode = layer_node.namedItem( QStringLiteral( "extent" ) );
1991 if ( !extentNode.isNull() )
1992 {
1993 mXmlExtent2D = QgsXmlUtils::readRectangle( extentNode.toElement() );
1994 }
1995 const QDomNode extent3DNode = layer_node.namedItem( QStringLiteral( "extent3D" ) );
1996 if ( !extent3DNode.isNull() )
1997 {
1998 mXmlExtent3D = QgsXmlUtils::readBox3D( extent3DNode.toElement() );
1999 }
2000 }
2001
2002 // auxiliary layer
2003 const QDomNode asNode = layer_node.namedItem( QStringLiteral( "auxiliaryLayer" ) );
2004 const QDomElement asElem = asNode.toElement();
2005 if ( !asElem.isNull() )
2006 {
2007 mAuxiliaryLayerKey = asElem.attribute( QStringLiteral( "key" ) );
2008 }
2009
2010 // QGIS Server WMS Dimensions
2011 mServerProperties->readXml( layer_node );
2012
2013 return isValid(); // should be true if read successfully
2014
2015} // void QgsVectorLayer::readXml
2016
2017
2018void QgsVectorLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider,
2020{
2022
2023 Qgis::GeometryType geomType = geometryType();
2024
2025 mDataSource = dataSource;
2026 setName( baseName );
2027 setDataProvider( provider, options, flags );
2028
2029 if ( !isValid() )
2030 {
2031 return;
2032 }
2033
2034 // Always set crs
2036
2037 bool loadDefaultStyleFlag = false;
2039 {
2040 loadDefaultStyleFlag = true;
2041 }
2042
2043 // reset style if loading default style, style is missing, or geometry type is has changed (and layer is valid)
2044 if ( !renderer() || !legend() || ( isValid() && geomType != geometryType() ) || loadDefaultStyleFlag )
2045 {
2046 std::unique_ptr< QgsScopedRuntimeProfile > profile;
2047 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
2048 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Load layer style" ), QStringLiteral( "projectload" ) );
2049
2050 bool defaultLoadedFlag = false;
2051
2052 // defer style changed signal until we've set the renderer, labeling, everything.
2053 // we don't want multiple signals!
2054 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
2055
2056 // need to check whether the default style included a legend, and if not, we need to make a default legend
2057 // later...
2058 mSetLegendFromStyle = false;
2059
2060 // first check if there is a default style / propertysheet defined
2061 // for this layer and if so apply it
2062 // this should take precedence over all
2063 if ( !defaultLoadedFlag && loadDefaultStyleFlag )
2064 {
2065 loadDefaultStyle( defaultLoadedFlag );
2066 }
2067
2068 if ( loadDefaultStyleFlag && !defaultLoadedFlag && isSpatial() && mDataProvider->capabilities() & Qgis::VectorProviderCapability::CreateRenderer )
2069 {
2070 // if we didn't load a default style for this layer, try to create a renderer directly from the data provider
2071 std::unique_ptr< QgsFeatureRenderer > defaultRenderer( mDataProvider->createRenderer() );
2072 if ( defaultRenderer )
2073 {
2074 defaultLoadedFlag = true;
2075 setRenderer( defaultRenderer.release() );
2076 }
2077 }
2078
2079 // if the default style failed to load or was disabled use some very basic defaults
2080 if ( !defaultLoadedFlag )
2081 {
2082 // add single symbol renderer for spatial layers
2084 }
2085
2086 if ( !mSetLegendFromStyle )
2088
2090 {
2091 std::unique_ptr< QgsAbstractVectorLayerLabeling > defaultLabeling( mDataProvider->createLabeling() );
2092 if ( defaultLabeling )
2093 {
2094 setLabeling( defaultLabeling.release() );
2095 setLabelsEnabled( true );
2096 }
2097 }
2098
2099 styleChangedSignalBlocker.release();
2101 }
2102}
2103
2104QString QgsVectorLayer::loadDefaultStyle( bool &resultFlag )
2105{
2107
2108 // first try to load a user-defined default style - this should always take precedence
2109 QString styleXml = QgsMapLayer::loadDefaultStyle( resultFlag );
2110
2111 if ( resultFlag )
2112 {
2113 // Try to load all stored styles from DB
2114 if ( mLoadAllStoredStyle && mDataProvider && mDataProvider->styleStorageCapabilities().testFlag( Qgis::ProviderStyleStorageCapability::LoadFromDatabase ) )
2115 {
2116 QStringList ids, names, descriptions;
2117 QString errorMessage;
2118 // Get the number of styles related to current layer.
2119 const int relatedStylesCount { listStylesInDatabase( ids, names, descriptions, errorMessage ) };
2120 Q_ASSERT( ids.count() == names.count() );
2121 const QString currentStyleName { mStyleManager->currentStyle() };
2122 for ( int i = 0; i < relatedStylesCount; ++i )
2123 {
2124 if ( names.at( i ) == currentStyleName )
2125 {
2126 continue;
2127 }
2128 errorMessage.clear();
2129 const QString styleXml { getStyleFromDatabase( ids.at( i ), errorMessage ) };
2130 if ( ! styleXml.isEmpty() && errorMessage.isEmpty() )
2131 {
2132 mStyleManager->addStyle( names.at( i ), QgsMapLayerStyle( styleXml ) );
2133 }
2134 else
2135 {
2136 QgsDebugMsgLevel( QStringLiteral( "Error retrieving style %1 from DB: %2" ).arg( ids.at( i ), errorMessage ), 2 );
2137 }
2138 }
2139 }
2140 return styleXml ;
2141 }
2142
2144 {
2145 // otherwise try to create a renderer directly from the data provider
2146 std::unique_ptr< QgsFeatureRenderer > defaultRenderer( mDataProvider->createRenderer() );
2147 if ( defaultRenderer )
2148 {
2149 resultFlag = true;
2150 setRenderer( defaultRenderer.release() );
2151 return QString();
2152 }
2153 }
2154
2155 return QString();
2156}
2157
2158bool QgsVectorLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
2159{
2161
2162 mProviderKey = provider;
2163 delete mDataProvider;
2164
2165 // For Postgres provider primary key unicity is tested at construction time,
2166 // so it has to be set before initializing the provider,
2167 // this manipulation is necessary to preserve default behavior when
2168 // "trust layer metadata" project level option is set and checkPrimaryKeyUnicity
2169 // was not explicitly passed in the uri
2170 if ( provider.compare( QLatin1String( "postgres" ) ) == 0 )
2171 {
2172 const QString checkUnicityKey { QStringLiteral( "checkPrimaryKeyUnicity" ) };
2174 if ( ! uri.hasParam( checkUnicityKey ) )
2175 {
2176 uri.setParam( checkUnicityKey, mReadExtentFromXml ? "0" : "1" );
2177 mDataSource = uri.uri( false );
2178 }
2179 }
2180
2181 std::unique_ptr< QgsScopedRuntimeProfile > profile;
2182 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
2183 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), QStringLiteral( "projectload" ) );
2184
2185 if ( mPreloadedProvider )
2186 mDataProvider = qobject_cast< QgsVectorDataProvider * >( mPreloadedProvider.release() );
2187 else
2188 mDataProvider = qobject_cast<QgsVectorDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, mDataSource, options, flags ) );
2189
2190 if ( !mDataProvider )
2191 {
2192 setValid( false );
2193 QgsDebugMsgLevel( QStringLiteral( "Unable to get data provider" ), 2 );
2194 return false;
2195 }
2196
2197 mDataProvider->setParent( this );
2198 connect( mDataProvider, &QgsVectorDataProvider::raiseError, this, &QgsVectorLayer::raiseError );
2199
2200 QgsDebugMsgLevel( QStringLiteral( "Instantiated the data provider plugin" ), 2 );
2201
2202 setValid( mDataProvider->isValid() );
2203 if ( !isValid() )
2204 {
2205 QgsDebugMsgLevel( QStringLiteral( "Invalid provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
2206 return false;
2207 }
2208
2209 if ( profile )
2210 profile->switchTask( tr( "Read layer metadata" ) );
2212 {
2213 // we combine the provider metadata with the layer's existing metadata, so as not to reset any user customizations to the metadata
2214 // back to the default if a layer's data source is changed
2215 QgsLayerMetadata newMetadata = mDataProvider->layerMetadata();
2216 // this overwrites the provider metadata with any properties which are non-empty from the existing layer metadata
2217 newMetadata.combine( &mMetadata );
2218
2219 setMetadata( newMetadata );
2220 QgsDebugMsgLevel( QStringLiteral( "Set Data provider QgsLayerMetadata identifier[%1]" ).arg( metadata().identifier() ), 4 );
2221 }
2222
2223 // TODO: Check if the provider has the capability to send fullExtentCalculated
2224 connect( mDataProvider, &QgsVectorDataProvider::fullExtentCalculated, this, [this] { updateExtents(); } );
2225
2226 // get and store the feature type
2227 mWkbType = mDataProvider->wkbType();
2228
2229 // before we update the layer fields from the provider, we first copy any default set alias and
2230 // editor widget config from the data provider fields, if present
2231 const QgsFields providerFields = mDataProvider->fields();
2232 for ( const QgsField &field : providerFields )
2233 {
2234 // we only copy defaults from the provider if we aren't overriding any configuration made in the layer
2235 if ( !field.editorWidgetSetup().isNull() && mFieldWidgetSetups.value( field.name() ).isNull() )
2236 {
2237 mFieldWidgetSetups[ field.name() ] = field.editorWidgetSetup();
2238 }
2239 if ( !field.alias().isEmpty() && mAttributeAliasMap.value( field.name() ).isEmpty() )
2240 {
2241 mAttributeAliasMap[ field.name() ] = field.alias();
2242 }
2243 if ( !mAttributeSplitPolicy.contains( field.name() ) )
2244 {
2245 mAttributeSplitPolicy[ field.name() ] = field.splitPolicy();
2246 }
2247 if ( !mAttributeDuplicatePolicy.contains( field.name() ) )
2248 {
2249 mAttributeDuplicatePolicy[ field.name() ] = field.duplicatePolicy();
2250 }
2251 }
2252
2253 if ( profile )
2254 profile->switchTask( tr( "Read layer fields" ) );
2255 updateFields();
2256
2257 if ( mProviderKey == QLatin1String( "postgres" ) )
2258 {
2259 // update datasource from data provider computed one
2260 mDataSource = mDataProvider->dataSourceUri( false );
2261
2262 QgsDebugMsgLevel( QStringLiteral( "Beautifying layer name %1" ).arg( name() ), 3 );
2263
2264 // adjust the display name for postgres layers
2265 const thread_local QRegularExpression reg( R"lit("[^"]+"\."([^"] + )"( \‍([^)]+\))?)lit" );
2266 const QRegularExpressionMatch match = reg.match( name() );
2267 if ( match.hasMatch() )
2268 {
2269 QStringList stuff = match.capturedTexts();
2270 QString lName = stuff[1];
2271
2272 const QMap<QString, QgsMapLayer *> &layers = QgsProject::instance()->mapLayers(); // skip-keyword-check
2273
2274 QMap<QString, QgsMapLayer *>::const_iterator it;
2275 for ( it = layers.constBegin(); it != layers.constEnd() && ( *it )->name() != lName; ++it )
2276 ;
2277
2278 if ( it != layers.constEnd() && stuff.size() > 2 )
2279 {
2280 lName += '.' + stuff[2].mid( 2, stuff[2].length() - 3 );
2281 }
2282
2283 if ( !lName.isEmpty() )
2284 setName( lName );
2285 }
2286 QgsDebugMsgLevel( QStringLiteral( "Beautified layer name %1" ).arg( name() ), 3 );
2287 }
2288 else if ( mProviderKey == QLatin1String( "osm" ) )
2289 {
2290 // make sure that the "observer" has been removed from URI to avoid crashes
2291 mDataSource = mDataProvider->dataSourceUri();
2292 }
2293 else if ( provider == QLatin1String( "ogr" ) )
2294 {
2295 // make sure that the /vsigzip or /vsizip is added to uri, if applicable
2296 mDataSource = mDataProvider->dataSourceUri();
2297 if ( mDataSource.right( 10 ) == QLatin1String( "|layerid=0" ) )
2298 mDataSource.chop( 10 );
2299 }
2300 else if ( provider == QLatin1String( "memory" ) )
2301 {
2302 // required so that source differs between memory layers
2303 mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
2304 }
2305 else if ( provider == QLatin1String( "hana" ) )
2306 {
2307 // update datasource from data provider computed one
2308 mDataSource = mDataProvider->dataSourceUri( false );
2309 }
2310
2311 connect( mDataProvider, &QgsVectorDataProvider::dataChanged, this, &QgsVectorLayer::emitDataChanged );
2313
2314 return true;
2315} // QgsVectorLayer:: setDataProvider
2316
2317
2318
2319
2320/* virtual */
2321bool QgsVectorLayer::writeXml( QDomNode &layer_node,
2322 QDomDocument &document,
2323 const QgsReadWriteContext &context ) const
2324{
2326
2327 // first get the layer element so that we can append the type attribute
2328
2329 QDomElement mapLayerNode = layer_node.toElement();
2330
2331 if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) )
2332 {
2333 QgsDebugMsgLevel( QStringLiteral( "can't find <maplayer>" ), 2 );
2334 return false;
2335 }
2336
2337 mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( Qgis::LayerType::Vector ) );
2338
2339 // set the geometry type
2340 mapLayerNode.setAttribute( QStringLiteral( "geometry" ), QgsWkbTypes::geometryDisplayString( geometryType() ) );
2341 mapLayerNode.setAttribute( QStringLiteral( "wkbType" ), qgsEnumValueToKey( wkbType() ) );
2342
2343 // add provider node
2344 if ( mDataProvider )
2345 {
2346 QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
2347 provider.setAttribute( QStringLiteral( "encoding" ), mDataProvider->encoding() );
2348 QDomText providerText = document.createTextNode( providerType() );
2349 provider.appendChild( providerText );
2350 layer_node.appendChild( provider );
2351 }
2352
2353 //save joins
2354 mJoinBuffer->writeXml( layer_node, document );
2355
2356 // dependencies
2357 QDomElement dependenciesElement = document.createElement( QStringLiteral( "layerDependencies" ) );
2358 const auto constDependencies = dependencies();
2359 for ( const QgsMapLayerDependency &dep : constDependencies )
2360 {
2362 continue;
2363 QDomElement depElem = document.createElement( QStringLiteral( "layer" ) );
2364 depElem.setAttribute( QStringLiteral( "id" ), dep.layerId() );
2365 dependenciesElement.appendChild( depElem );
2366 }
2367 layer_node.appendChild( dependenciesElement );
2368
2369 // change dependencies
2370 QDomElement dataDependenciesElement = document.createElement( QStringLiteral( "dataDependencies" ) );
2371 for ( const QgsMapLayerDependency &dep : constDependencies )
2372 {
2373 if ( dep.type() != QgsMapLayerDependency::DataDependency )
2374 continue;
2375 QDomElement depElem = document.createElement( QStringLiteral( "layer" ) );
2376 depElem.setAttribute( QStringLiteral( "id" ), dep.layerId() );
2377 dataDependenciesElement.appendChild( depElem );
2378 }
2379 layer_node.appendChild( dataDependenciesElement );
2380
2381 // save expression fields
2382 mExpressionFieldBuffer->writeXml( layer_node, document );
2383
2384 writeStyleManager( layer_node, document );
2385
2386 // auxiliary layer
2387 QDomElement asElem = document.createElement( QStringLiteral( "auxiliaryLayer" ) );
2388 if ( mAuxiliaryLayer )
2389 {
2390 const QString pkField = mAuxiliaryLayer->joinInfo().targetFieldName();
2391 asElem.setAttribute( QStringLiteral( "key" ), pkField );
2392 }
2393 layer_node.appendChild( asElem );
2394
2395 // save QGIS Server properties (WMS Dimension, metadata URLS...)
2396 mServerProperties->writeXml( layer_node, document );
2397
2398 // renderer specific settings
2399 QString errorMsg;
2400 return writeSymbology( layer_node, document, errorMsg, context );
2401}
2402
2403QString QgsVectorLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
2404{
2406
2407 if ( providerType() == QLatin1String( "memory" ) )
2408 {
2409 // Refetch the source from the provider, because adding fields actually changes the source for this provider.
2410 return dataProvider()->dataSourceUri();
2411 }
2412
2414}
2415
2416QString QgsVectorLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
2417{
2419
2420 return QgsProviderRegistry::instance()->relativeToAbsoluteUri( provider, source, context );
2421}
2422
2423
2424
2432
2433
2434bool QgsVectorLayer::readSymbology( const QDomNode &layerNode, QString &errorMessage,
2436{
2438
2439 if ( categories.testFlag( Fields ) )
2440 {
2441 if ( !mExpressionFieldBuffer )
2442 mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
2443 mExpressionFieldBuffer->readXml( layerNode );
2444
2445 updateFields();
2446 }
2447
2448 if ( categories.testFlag( Relations ) )
2449 {
2450 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Relations" ) );
2451
2452 // Restore referenced layers: relations where "this" is the child layer (the referencing part, that holds the FK)
2453 QDomNodeList referencedLayersNodeList = layerNode.toElement().elementsByTagName( QStringLiteral( "referencedLayers" ) );
2454 if ( referencedLayersNodeList.size() > 0 )
2455 {
2456 const QDomNodeList relationNodes { referencedLayersNodeList.at( 0 ).childNodes() };
2457 for ( int i = 0; i < relationNodes.length(); ++i )
2458 {
2459 const QDomElement relationElement = relationNodes.at( i ).toElement();
2460
2461 mWeakRelations.push_back( QgsWeakRelation::readXml( this, QgsWeakRelation::Referencing, relationElement, context.pathResolver() ) );
2462 }
2463 }
2464
2465 // Restore referencing layers: relations where "this" is the parent layer (the referenced part where the FK points to)
2466 QDomNodeList referencingLayersNodeList = layerNode.toElement().elementsByTagName( QStringLiteral( "referencingLayers" ) );
2467 if ( referencingLayersNodeList.size() > 0 )
2468 {
2469 const QDomNodeList relationNodes { referencingLayersNodeList.at( 0 ).childNodes() };
2470 for ( int i = 0; i < relationNodes.length(); ++i )
2471 {
2472 const QDomElement relationElement = relationNodes.at( i ).toElement();
2473 mWeakRelations.push_back( QgsWeakRelation::readXml( this, QgsWeakRelation::Referenced, relationElement, context.pathResolver() ) );
2474 }
2475 }
2476 }
2477
2478 QDomElement layerElement = layerNode.toElement();
2479
2480 readCommonStyle( layerElement, context, categories );
2481
2482 readStyle( layerNode, errorMessage, context, categories );
2483
2484 if ( categories.testFlag( MapTips ) )
2485 {
2486 QDomElement mapTipElem = layerNode.namedItem( QStringLiteral( "mapTip" ) ).toElement();
2487 setMapTipTemplate( mapTipElem.text() );
2488 setMapTipsEnabled( mapTipElem.attribute( QStringLiteral( "enabled" ), QStringLiteral( "1" ) ).toInt() == 1 );
2489 }
2490
2491 if ( categories.testFlag( LayerConfiguration ) )
2492 mDisplayExpression = layerNode.namedItem( QStringLiteral( "previewExpression" ) ).toElement().text();
2493
2494 // Try to migrate pre QGIS 3.0 display field property
2495 QString displayField = layerNode.namedItem( QStringLiteral( "displayfield" ) ).toElement().text();
2496 if ( mFields.lookupField( displayField ) < 0 )
2497 {
2498 // if it's not a field, it's a maptip
2499 if ( mMapTipTemplate.isEmpty() && categories.testFlag( MapTips ) )
2500 mMapTipTemplate = displayField;
2501 }
2502 else
2503 {
2504 if ( mDisplayExpression.isEmpty() && categories.testFlag( LayerConfiguration ) )
2505 mDisplayExpression = QgsExpression::quotedColumnRef( displayField );
2506 }
2507
2508 // process the attribute actions
2509 if ( categories.testFlag( Actions ) )
2510 mActions->readXml( layerNode );
2511
2512 if ( categories.testFlag( Fields ) )
2513 {
2514 // IMPORTANT - we don't clear mAttributeAliasMap here, as it may contain aliases which are coming direct
2515 // from the data provider. Instead we leave any existing aliases and only overwrite them if the style
2516 // has a specific value for that field's alias
2517 QDomNode aliasesNode = layerNode.namedItem( QStringLiteral( "aliases" ) );
2518 if ( !aliasesNode.isNull() )
2519 {
2520 QDomElement aliasElem;
2521
2522 QDomNodeList aliasNodeList = aliasesNode.toElement().elementsByTagName( QStringLiteral( "alias" ) );
2523 for ( int i = 0; i < aliasNodeList.size(); ++i )
2524 {
2525 aliasElem = aliasNodeList.at( i ).toElement();
2526
2527 QString field;
2528 if ( aliasElem.hasAttribute( QStringLiteral( "field" ) ) )
2529 {
2530 field = aliasElem.attribute( QStringLiteral( "field" ) );
2531 }
2532 else
2533 {
2534 int index = aliasElem.attribute( QStringLiteral( "index" ) ).toInt();
2535
2536 if ( index >= 0 && index < fields().count() )
2537 field = fields().at( index ).name();
2538 }
2539
2540 QString alias;
2541
2542 if ( !aliasElem.attribute( QStringLiteral( "name" ) ).isEmpty() )
2543 {
2544 //if it has alias
2545 alias = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ), aliasElem.attribute( QStringLiteral( "name" ) ) );
2546 QgsDebugMsgLevel( "context" + QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ) + " source " + aliasElem.attribute( QStringLiteral( "name" ) ), 3 );
2547 }
2548 else
2549 {
2550 //if it has no alias, it should be the fields translation
2551 alias = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ), field );
2552 QgsDebugMsgLevel( "context" + QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ) + " source " + field, 3 );
2553 //if it gets the exact field value, there has been no translation (or not even translation loaded) - so no alias should be generated;
2554 if ( alias == aliasElem.attribute( QStringLiteral( "field" ) ) )
2555 alias.clear();
2556 }
2557
2558 QgsDebugMsgLevel( "field " + field + " origalias " + aliasElem.attribute( QStringLiteral( "name" ) ) + " trans " + alias, 3 );
2559 mAttributeAliasMap.insert( field, alias );
2560 }
2561 }
2562
2563 // IMPORTANT - we don't clear mAttributeSplitPolicy here, as it may contain policies which are coming direct
2564 // from the data provider. Instead we leave any existing policies and only overwrite them if the style
2565 // has a specific value for that field's policy
2566 const QDomNode splitPoliciesNode = layerNode.namedItem( QStringLiteral( "splitPolicies" ) );
2567 if ( !splitPoliciesNode.isNull() )
2568 {
2569 const QDomNodeList splitPolicyNodeList = splitPoliciesNode.toElement().elementsByTagName( QStringLiteral( "policy" ) );
2570 for ( int i = 0; i < splitPolicyNodeList.size(); ++i )
2571 {
2572 const QDomElement splitPolicyElem = splitPolicyNodeList.at( i ).toElement();
2573 const QString field = splitPolicyElem.attribute( QStringLiteral( "field" ) );
2574 const Qgis::FieldDomainSplitPolicy policy = qgsEnumKeyToValue( splitPolicyElem.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDomainSplitPolicy::Duplicate );
2575 mAttributeSplitPolicy.insert( field, policy );
2576 }
2577 }
2578
2579 // The duplicate policy is - unlike alias and split policy - never defined by the data provider, so we clear the map
2580 mAttributeDuplicatePolicy.clear();
2581 const QDomNode duplicatePoliciesNode = layerNode.namedItem( QStringLiteral( "duplicatePolicies" ) );
2582 if ( !duplicatePoliciesNode.isNull() )
2583 {
2584 const QDomNodeList duplicatePolicyNodeList = duplicatePoliciesNode.toElement().elementsByTagName( QStringLiteral( "policy" ) );
2585 for ( int i = 0; i < duplicatePolicyNodeList.size(); ++i )
2586 {
2587 const QDomElement duplicatePolicyElem = duplicatePolicyNodeList.at( i ).toElement();
2588 const QString field = duplicatePolicyElem.attribute( QStringLiteral( "field" ) );
2589 const Qgis::FieldDuplicatePolicy policy = qgsEnumKeyToValue( duplicatePolicyElem.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDuplicatePolicy::Duplicate );
2590 mAttributeDuplicatePolicy.insert( field, policy );
2591 }
2592 }
2593
2594 // default expressions
2595 mDefaultExpressionMap.clear();
2596 QDomNode defaultsNode = layerNode.namedItem( QStringLiteral( "defaults" ) );
2597 if ( !defaultsNode.isNull() )
2598 {
2599 QDomNodeList defaultNodeList = defaultsNode.toElement().elementsByTagName( QStringLiteral( "default" ) );
2600 for ( int i = 0; i < defaultNodeList.size(); ++i )
2601 {
2602 QDomElement defaultElem = defaultNodeList.at( i ).toElement();
2603
2604 QString field = defaultElem.attribute( QStringLiteral( "field" ), QString() );
2605 QString expression = defaultElem.attribute( QStringLiteral( "expression" ), QString() );
2606 bool applyOnUpdate = defaultElem.attribute( QStringLiteral( "applyOnUpdate" ), QStringLiteral( "0" ) ) == QLatin1String( "1" );
2607 if ( field.isEmpty() || expression.isEmpty() )
2608 continue;
2609
2610 mDefaultExpressionMap.insert( field, QgsDefaultValue( expression, applyOnUpdate ) );
2611 }
2612 }
2613
2614 // constraints
2615 mFieldConstraints.clear();
2616 mFieldConstraintStrength.clear();
2617 QDomNode constraintsNode = layerNode.namedItem( QStringLiteral( "constraints" ) );
2618 if ( !constraintsNode.isNull() )
2619 {
2620 QDomNodeList constraintNodeList = constraintsNode.toElement().elementsByTagName( QStringLiteral( "constraint" ) );
2621 for ( int i = 0; i < constraintNodeList.size(); ++i )
2622 {
2623 QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2624
2625 QString field = constraintElem.attribute( QStringLiteral( "field" ), QString() );
2626 int constraints = constraintElem.attribute( QStringLiteral( "constraints" ), QStringLiteral( "0" ) ).toInt();
2627 if ( field.isEmpty() || constraints == 0 )
2628 continue;
2629
2630 mFieldConstraints.insert( field, static_cast< QgsFieldConstraints::Constraints >( constraints ) );
2631
2632 int uniqueStrength = constraintElem.attribute( QStringLiteral( "unique_strength" ), QStringLiteral( "1" ) ).toInt();
2633 int notNullStrength = constraintElem.attribute( QStringLiteral( "notnull_strength" ), QStringLiteral( "1" ) ).toInt();
2634 int expStrength = constraintElem.attribute( QStringLiteral( "exp_strength" ), QStringLiteral( "1" ) ).toInt();
2635
2636 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintUnique ), static_cast< QgsFieldConstraints::ConstraintStrength >( uniqueStrength ) );
2637 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintNotNull ), static_cast< QgsFieldConstraints::ConstraintStrength >( notNullStrength ) );
2638 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintExpression ), static_cast< QgsFieldConstraints::ConstraintStrength >( expStrength ) );
2639 }
2640 }
2641 mFieldConstraintExpressions.clear();
2642 QDomNode constraintExpressionsNode = layerNode.namedItem( QStringLiteral( "constraintExpressions" ) );
2643 if ( !constraintExpressionsNode.isNull() )
2644 {
2645 QDomNodeList constraintNodeList = constraintExpressionsNode.toElement().elementsByTagName( QStringLiteral( "constraint" ) );
2646 for ( int i = 0; i < constraintNodeList.size(); ++i )
2647 {
2648 QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2649
2650 QString field = constraintElem.attribute( QStringLiteral( "field" ), QString() );
2651 QString exp = constraintElem.attribute( QStringLiteral( "exp" ), QString() );
2652 QString desc = constraintElem.attribute( QStringLiteral( "desc" ), QString() );
2653 if ( field.isEmpty() || exp.isEmpty() )
2654 continue;
2655
2656 mFieldConstraintExpressions.insert( field, qMakePair( exp, desc ) );
2657 }
2658 }
2659
2660 updateFields();
2661 }
2662
2663 // load field configuration
2664 if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
2665 {
2666 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Forms" ) );
2667
2668 QDomElement widgetsElem = layerNode.namedItem( QStringLiteral( "fieldConfiguration" ) ).toElement();
2669 QDomNodeList fieldConfigurationElementList = widgetsElem.elementsByTagName( QStringLiteral( "field" ) );
2670 for ( int i = 0; i < fieldConfigurationElementList.size(); ++i )
2671 {
2672 const QDomElement fieldConfigElement = fieldConfigurationElementList.at( i ).toElement();
2673 const QDomElement fieldWidgetElement = fieldConfigElement.elementsByTagName( QStringLiteral( "editWidget" ) ).at( 0 ).toElement();
2674
2675 QString fieldName = fieldConfigElement.attribute( QStringLiteral( "name" ) );
2676
2677 if ( categories.testFlag( Fields ) )
2678 mFieldConfigurationFlags[fieldName] = qgsFlagKeysToValue( fieldConfigElement.attribute( QStringLiteral( "configurationFlags" ) ), Qgis::FieldConfigurationFlag::NoFlag );
2679
2680 // Load editor widget configuration
2681 if ( categories.testFlag( Forms ) )
2682 {
2683 const QString widgetType = fieldWidgetElement.attribute( QStringLiteral( "type" ) );
2684 const QDomElement cfgElem = fieldConfigElement.elementsByTagName( QStringLiteral( "config" ) ).at( 0 ).toElement();
2685 const QDomElement optionsElem = cfgElem.childNodes().at( 0 ).toElement();
2686 QVariantMap optionsMap = QgsXmlUtils::readVariant( optionsElem ).toMap();
2687 if ( widgetType == QLatin1String( "ValueRelation" ) )
2688 {
2689 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() );
2690 }
2691 QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( widgetType, optionsMap );
2692 mFieldWidgetSetups[fieldName] = setup;
2693 }
2694 }
2695 }
2696
2697 // Legacy reading for QGIS 3.14 and older projects
2698 // Attributes excluded from WMS and WFS
2699 if ( categories.testFlag( Fields ) )
2700 {
2701 const QList<QPair<QString, Qgis::FieldConfigurationFlag>> legacyConfig
2702 {
2703 qMakePair( QStringLiteral( "excludeAttributesWMS" ), Qgis::FieldConfigurationFlag::HideFromWms ),
2704 qMakePair( QStringLiteral( "excludeAttributesWFS" ), Qgis::FieldConfigurationFlag::HideFromWfs )
2705 };
2706 for ( const auto &config : legacyConfig )
2707 {
2708 QDomNode excludeNode = layerNode.namedItem( config.first );
2709 if ( !excludeNode.isNull() )
2710 {
2711 QDomNodeList attributeNodeList = excludeNode.toElement().elementsByTagName( QStringLiteral( "attribute" ) );
2712 for ( int i = 0; i < attributeNodeList.size(); ++i )
2713 {
2714 QString fieldName = attributeNodeList.at( i ).toElement().text();
2715 if ( !mFieldConfigurationFlags.contains( fieldName ) )
2716 mFieldConfigurationFlags[fieldName] = config.second;
2717 else
2718 mFieldConfigurationFlags[fieldName].setFlag( config.second, true );
2719 }
2720 }
2721 }
2722 }
2723
2724 if ( categories.testFlag( GeometryOptions ) )
2725 mGeometryOptions->readXml( layerNode.namedItem( QStringLiteral( "geometryOptions" ) ) );
2726
2727 if ( categories.testFlag( Forms ) )
2728 mEditFormConfig.readXml( layerNode, context );
2729
2730 if ( categories.testFlag( AttributeTable ) )
2731 {
2732 mAttributeTableConfig.readXml( layerNode );
2733 mConditionalStyles->readXml( layerNode, context );
2734 mStoredExpressionManager->readXml( layerNode );
2735 }
2736
2737 if ( categories.testFlag( CustomProperties ) )
2738 readCustomProperties( layerNode, QStringLiteral( "variable" ) );
2739
2740 QDomElement mapLayerNode = layerNode.toElement();
2741 if ( categories.testFlag( LayerConfiguration )
2742 && mapLayerNode.attribute( QStringLiteral( "readOnly" ), QStringLiteral( "0" ) ).toInt() == 1 )
2743 mReadOnly = true;
2744
2745 updateFields();
2746
2747 if ( categories.testFlag( Legend ) )
2748 {
2749 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Legend" ) );
2750
2751 const QDomElement legendElem = layerNode.firstChildElement( QStringLiteral( "legend" ) );
2752 if ( !legendElem.isNull() )
2753 {
2754 std::unique_ptr< QgsMapLayerLegend > legend( QgsMapLayerLegend::defaultVectorLegend( this ) );
2755 legend->readXml( legendElem, context );
2756 setLegend( legend.release() );
2757 mSetLegendFromStyle = true;
2758 }
2759 }
2760
2761 return true;
2762}
2763
2764bool QgsVectorLayer::readStyle( const QDomNode &node, QString &errorMessage,
2766{
2768
2769 bool result = true;
2770 emit readCustomSymbology( node.toElement(), errorMessage );
2771
2772 // we must try to restore a renderer if our geometry type is unknown
2773 // as this allows the renderer to be correctly restored even for layers
2774 // with broken sources
2775 if ( isSpatial() || mWkbType == Qgis::WkbType::Unknown )
2776 {
2777 // defer style changed signal until we've set the renderer, labeling, everything.
2778 // we don't want multiple signals!
2779 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
2780
2781 // try renderer v2 first
2782 if ( categories.testFlag( Symbology ) )
2783 {
2784 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Symbology" ) );
2785
2786 QDomElement rendererElement = node.firstChildElement( RENDERER_TAG_NAME );
2787 if ( !rendererElement.isNull() )
2788 {
2789 QgsFeatureRenderer *r = QgsFeatureRenderer::load( rendererElement, context );
2790 if ( r )
2791 {
2792 setRenderer( r );
2793 }
2794 else
2795 {
2796 result = false;
2797 }
2798 }
2799 // make sure layer has a renderer - if none exists, fallback to a default renderer
2800 if ( isSpatial() && !renderer() )
2801 {
2803 }
2804
2805 if ( mSelectionProperties )
2806 mSelectionProperties->readXml( node.toElement(), context );
2807 }
2808
2809 // read labeling definition
2810 if ( categories.testFlag( Labeling ) )
2811 {
2812 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Labeling" ) );
2813
2814 QDomElement labelingElement = node.firstChildElement( QStringLiteral( "labeling" ) );
2816 if ( labelingElement.isNull() ||
2817 ( labelingElement.attribute( QStringLiteral( "type" ) ) == QLatin1String( "simple" ) && labelingElement.firstChildElement( QStringLiteral( "settings" ) ).isNull() ) )
2818 {
2819 // make sure we have custom properties for labeling for 2.x projects
2820 // (custom properties should be already loaded when reading the whole layer from XML,
2821 // but when reading style, custom properties are not read)
2822 readCustomProperties( node, QStringLiteral( "labeling" ) );
2823
2824 // support for pre-QGIS 3 labeling configurations written in custom properties
2825 labeling = readLabelingFromCustomProperties();
2826 }
2827 else
2828 {
2829 labeling = QgsAbstractVectorLayerLabeling::create( labelingElement, context );
2830 }
2832
2833 if ( node.toElement().hasAttribute( QStringLiteral( "labelsEnabled" ) ) )
2834 mLabelsEnabled = node.toElement().attribute( QStringLiteral( "labelsEnabled" ) ).toInt();
2835 else
2836 mLabelsEnabled = true;
2837 }
2838
2839 if ( categories.testFlag( Symbology ) )
2840 {
2841 // get and set the blend mode if it exists
2842 QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
2843 if ( !blendModeNode.isNull() )
2844 {
2845 QDomElement e = blendModeNode.toElement();
2846 setBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
2847 }
2848
2849 // get and set the feature blend mode if it exists
2850 QDomNode featureBlendModeNode = node.namedItem( QStringLiteral( "featureBlendMode" ) );
2851 if ( !featureBlendModeNode.isNull() )
2852 {
2853 QDomElement e = featureBlendModeNode.toElement();
2854 setFeatureBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
2855 }
2856 }
2857
2858 // get and set the layer transparency and scale visibility if they exists
2859 if ( categories.testFlag( Rendering ) )
2860 {
2861 QDomNode layerTransparencyNode = node.namedItem( QStringLiteral( "layerTransparency" ) );
2862 if ( !layerTransparencyNode.isNull() )
2863 {
2864 QDomElement e = layerTransparencyNode.toElement();
2865 setOpacity( 1.0 - e.text().toInt() / 100.0 );
2866 }
2867 QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
2868 if ( !layerOpacityNode.isNull() )
2869 {
2870 QDomElement e = layerOpacityNode.toElement();
2871 setOpacity( e.text().toDouble() );
2872 }
2873
2874 const bool hasScaleBasedVisibiliy { node.attributes().namedItem( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).nodeValue() == '1' };
2875 setScaleBasedVisibility( hasScaleBasedVisibiliy );
2876 bool ok;
2877 const double maxScale { node.attributes().namedItem( QStringLiteral( "maxScale" ) ).nodeValue().toDouble( &ok ) };
2878 if ( ok )
2879 {
2880 setMaximumScale( maxScale );
2881 }
2882 const double minScale { node.attributes().namedItem( QStringLiteral( "minScale" ) ).nodeValue().toDouble( &ok ) };
2883 if ( ok )
2884 {
2885 setMinimumScale( minScale );
2886 }
2887
2888 QDomElement e = node.toElement();
2889
2890 // get the simplification drawing settings
2891 mSimplifyMethod.setSimplifyHints( static_cast< Qgis::VectorRenderingSimplificationFlags >( e.attribute( QStringLiteral( "simplifyDrawingHints" ), QStringLiteral( "1" ) ).toInt() ) );
2892 mSimplifyMethod.setSimplifyAlgorithm( static_cast< Qgis::VectorSimplificationAlgorithm >( e.attribute( QStringLiteral( "simplifyAlgorithm" ), QStringLiteral( "0" ) ).toInt() ) );
2893 mSimplifyMethod.setThreshold( e.attribute( QStringLiteral( "simplifyDrawingTol" ), QStringLiteral( "1" ) ).toFloat() );
2894 mSimplifyMethod.setForceLocalOptimization( e.attribute( QStringLiteral( "simplifyLocal" ), QStringLiteral( "1" ) ).toInt() );
2895 mSimplifyMethod.setMaximumScale( e.attribute( QStringLiteral( "simplifyMaxScale" ), QStringLiteral( "1" ) ).toFloat() );
2896
2897 if ( mRenderer )
2898 mRenderer->setReferenceScale( e.attribute( QStringLiteral( "symbologyReferenceScale" ), QStringLiteral( "-1" ) ).toDouble() );
2899 }
2900
2901 //diagram renderer and diagram layer settings
2902 if ( categories.testFlag( Diagrams ) )
2903 {
2904 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Diagrams" ) );
2905
2906 delete mDiagramRenderer;
2907 mDiagramRenderer = nullptr;
2908 QDomElement singleCatDiagramElem = node.firstChildElement( QStringLiteral( "SingleCategoryDiagramRenderer" ) );
2909 if ( !singleCatDiagramElem.isNull() )
2910 {
2911 mDiagramRenderer = new QgsSingleCategoryDiagramRenderer();
2912 mDiagramRenderer->readXml( singleCatDiagramElem, context );
2913 }
2914 QDomElement linearDiagramElem = node.firstChildElement( QStringLiteral( "LinearlyInterpolatedDiagramRenderer" ) );
2915 if ( !linearDiagramElem.isNull() )
2916 {
2917 if ( linearDiagramElem.hasAttribute( QStringLiteral( "classificationAttribute" ) ) )
2918 {
2919 // fix project from before QGIS 3.0
2920 int idx = linearDiagramElem.attribute( QStringLiteral( "classificationAttribute" ) ).toInt();
2921 if ( idx >= 0 && idx < mFields.count() )
2922 linearDiagramElem.setAttribute( QStringLiteral( "classificationField" ), mFields.at( idx ).name() );
2923 }
2924
2925 mDiagramRenderer = new QgsLinearlyInterpolatedDiagramRenderer();
2926 mDiagramRenderer->readXml( linearDiagramElem, context );
2927 }
2928 QDomElement stackedDiagramElem = node.firstChildElement( QStringLiteral( "StackedDiagramRenderer" ) );
2929 if ( !stackedDiagramElem.isNull() )
2930 {
2931 mDiagramRenderer = new QgsStackedDiagramRenderer();
2932 mDiagramRenderer->readXml( stackedDiagramElem, context );
2933 }
2934
2935 if ( mDiagramRenderer )
2936 {
2937 QDomElement diagramSettingsElem = node.firstChildElement( QStringLiteral( "DiagramLayerSettings" ) );
2938 if ( !diagramSettingsElem.isNull() )
2939 {
2940 bool oldXPos = diagramSettingsElem.hasAttribute( QStringLiteral( "xPosColumn" ) );
2941 bool oldYPos = diagramSettingsElem.hasAttribute( QStringLiteral( "yPosColumn" ) );
2942 bool oldShow = diagramSettingsElem.hasAttribute( QStringLiteral( "showColumn" ) );
2943 if ( oldXPos || oldYPos || oldShow )
2944 {
2945 // fix project from before QGIS 3.0
2947 if ( oldXPos )
2948 {
2949 int xPosColumn = diagramSettingsElem.attribute( QStringLiteral( "xPosColumn" ) ).toInt();
2950 if ( xPosColumn >= 0 && xPosColumn < mFields.count() )
2952 }
2953 if ( oldYPos )
2954 {
2955 int yPosColumn = diagramSettingsElem.attribute( QStringLiteral( "yPosColumn" ) ).toInt();
2956 if ( yPosColumn >= 0 && yPosColumn < mFields.count() )
2958 }
2959 if ( oldShow )
2960 {
2961 int showColumn = diagramSettingsElem.attribute( QStringLiteral( "showColumn" ) ).toInt();
2962 if ( showColumn >= 0 && showColumn < mFields.count() )
2963 ddp.setProperty( QgsDiagramLayerSettings::Property::Show, QgsProperty::fromField( mFields.at( showColumn ).name(), true ) );
2964 }
2965 QDomElement propertiesElem = diagramSettingsElem.ownerDocument().createElement( QStringLiteral( "properties" ) );
2967 {
2968 { static_cast< int >( QgsDiagramLayerSettings::Property::PositionX ), QgsPropertyDefinition( "positionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double ) },
2969 { static_cast< int >( QgsDiagramLayerSettings::Property::PositionY ), QgsPropertyDefinition( "positionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double ) },
2970 { static_cast< int >( QgsDiagramLayerSettings::Property::Show ), QgsPropertyDefinition( "show", QObject::tr( "Show diagram" ), QgsPropertyDefinition::Boolean ) },
2971 };
2972 ddp.writeXml( propertiesElem, defs );
2973 diagramSettingsElem.appendChild( propertiesElem );
2974 }
2975
2976 delete mDiagramLayerSettings;
2977 mDiagramLayerSettings = new QgsDiagramLayerSettings();
2978 mDiagramLayerSettings->readXml( diagramSettingsElem );
2979 }
2980 }
2981 }
2982 // end diagram
2983
2984 styleChangedSignalBlocker.release();
2986 }
2987 return result;
2988}
2989
2990
2991bool QgsVectorLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
2992 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
2993{
2995
2996 QDomElement layerElement = node.toElement();
2997 writeCommonStyle( layerElement, doc, context, categories );
2998
2999 ( void )writeStyle( node, doc, errorMessage, context, categories );
3000
3001 if ( categories.testFlag( GeometryOptions ) )
3002 mGeometryOptions->writeXml( node );
3003
3004 if ( categories.testFlag( Legend ) && legend() )
3005 {
3006 QDomElement legendElement = legend()->writeXml( doc, context );
3007 if ( !legendElement.isNull() )
3008 node.appendChild( legendElement );
3009 }
3010
3011 // Relation information for both referenced and referencing sides
3012 if ( categories.testFlag( Relations ) )
3013 {
3014 if ( QgsProject *p = project() )
3015 {
3016 // Store referenced layers: relations where "this" is the child layer (the referencing part, that holds the FK)
3017 QDomElement referencedLayersElement = doc.createElement( QStringLiteral( "referencedLayers" ) );
3018 node.appendChild( referencedLayersElement );
3019
3020 const QList<QgsRelation> referencingRelations { p->relationManager()->referencingRelations( this ) };
3021 for ( const QgsRelation &rel : referencingRelations )
3022 {
3023 switch ( rel.type() )
3024 {
3026 QgsWeakRelation::writeXml( this, QgsWeakRelation::Referencing, rel, referencedLayersElement, doc );
3027 break;
3029 break;
3030 }
3031 }
3032
3033 // Store referencing layers: relations where "this" is the parent layer (the referenced part, that holds the FK)
3034 QDomElement referencingLayersElement = doc.createElement( QStringLiteral( "referencingLayers" ) );
3035 node.appendChild( referencedLayersElement );
3036
3037 const QList<QgsRelation> referencedRelations { p->relationManager()->referencedRelations( this ) };
3038 for ( const QgsRelation &rel : referencedRelations )
3039 {
3040 switch ( rel.type() )
3041 {
3043 QgsWeakRelation::writeXml( this, QgsWeakRelation::Referenced, rel, referencingLayersElement, doc );
3044 break;
3046 break;
3047 }
3048 }
3049 }
3050 }
3051
3052 // write field configurations
3053 if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
3054 {
3055 QDomElement fieldConfigurationElement;
3056 // field configuration flag
3057 fieldConfigurationElement = doc.createElement( QStringLiteral( "fieldConfiguration" ) );
3058 node.appendChild( fieldConfigurationElement );
3059
3060 for ( const QgsField &field : std::as_const( mFields ) )
3061 {
3062 QDomElement fieldElement = doc.createElement( QStringLiteral( "field" ) );
3063 fieldElement.setAttribute( QStringLiteral( "name" ), field.name() );
3064 fieldConfigurationElement.appendChild( fieldElement );
3065
3066 if ( categories.testFlag( Fields ) )
3067 {
3068 fieldElement.setAttribute( QStringLiteral( "configurationFlags" ), qgsFlagValueToKeys( field.configurationFlags() ) );
3069 }
3070
3071 if ( categories.testFlag( Forms ) )
3072 {
3073 QgsEditorWidgetSetup widgetSetup = field.editorWidgetSetup();
3074
3075 // TODO : wrap this part in an if to only save if it was user-modified
3076 QDomElement editWidgetElement = doc.createElement( QStringLiteral( "editWidget" ) );
3077 fieldElement.appendChild( editWidgetElement );
3078 editWidgetElement.setAttribute( QStringLiteral( "type" ), field.editorWidgetSetup().type() );
3079 QDomElement editWidgetConfigElement = doc.createElement( QStringLiteral( "config" ) );
3080
3081 editWidgetConfigElement.appendChild( QgsXmlUtils::writeVariant( widgetSetup.config(), doc ) );
3082 editWidgetElement.appendChild( editWidgetConfigElement );
3083 // END TODO : wrap this part in an if to only save if it was user-modified
3084 }
3085 }
3086 }
3087
3088 if ( categories.testFlag( Fields ) )
3089 {
3090 //attribute aliases
3091 QDomElement aliasElem = doc.createElement( QStringLiteral( "aliases" ) );
3092 for ( const QgsField &field : std::as_const( mFields ) )
3093 {
3094 QDomElement aliasEntryElem = doc.createElement( QStringLiteral( "alias" ) );
3095 aliasEntryElem.setAttribute( QStringLiteral( "field" ), field.name() );
3096 aliasEntryElem.setAttribute( QStringLiteral( "index" ), mFields.indexFromName( field.name() ) );
3097 aliasEntryElem.setAttribute( QStringLiteral( "name" ), field.alias() );
3098 aliasElem.appendChild( aliasEntryElem );
3099 }
3100 node.appendChild( aliasElem );
3101
3102 //split policies
3103 {
3104 QDomElement splitPoliciesElement = doc.createElement( QStringLiteral( "splitPolicies" ) );
3105 for ( const QgsField &field : std::as_const( mFields ) )
3106 {
3107 QDomElement splitPolicyElem = doc.createElement( QStringLiteral( "policy" ) );
3108 splitPolicyElem.setAttribute( QStringLiteral( "field" ), field.name() );
3109 splitPolicyElem.setAttribute( QStringLiteral( "policy" ), qgsEnumValueToKey( field.splitPolicy() ) );
3110 splitPoliciesElement.appendChild( splitPolicyElem );
3111 }
3112 node.appendChild( splitPoliciesElement );
3113 }
3114
3115 //duplicate policies
3116 {
3117 QDomElement duplicatePoliciesElement = doc.createElement( QStringLiteral( "duplicatePolicies" ) );
3118 for ( const QgsField &field : std::as_const( mFields ) )
3119 {
3120 QDomElement duplicatePolicyElem = doc.createElement( QStringLiteral( "policy" ) );
3121 duplicatePolicyElem.setAttribute( QStringLiteral( "field" ), field.name() );
3122 duplicatePolicyElem.setAttribute( QStringLiteral( "policy" ), qgsEnumValueToKey( field.duplicatePolicy() ) );
3123 duplicatePoliciesElement.appendChild( duplicatePolicyElem );
3124 }
3125 node.appendChild( duplicatePoliciesElement );
3126 }
3127
3128 //default expressions
3129 QDomElement defaultsElem = doc.createElement( QStringLiteral( "defaults" ) );
3130 for ( const QgsField &field : std::as_const( mFields ) )
3131 {
3132 QDomElement defaultElem = doc.createElement( QStringLiteral( "default" ) );
3133 defaultElem.setAttribute( QStringLiteral( "field" ), field.name() );
3134 defaultElem.setAttribute( QStringLiteral( "expression" ), field.defaultValueDefinition().expression() );
3135 defaultElem.setAttribute( QStringLiteral( "applyOnUpdate" ), field.defaultValueDefinition().applyOnUpdate() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
3136 defaultsElem.appendChild( defaultElem );
3137 }
3138 node.appendChild( defaultsElem );
3139
3140 // constraints
3141 QDomElement constraintsElem = doc.createElement( QStringLiteral( "constraints" ) );
3142 for ( const QgsField &field : std::as_const( mFields ) )
3143 {
3144 QDomElement constraintElem = doc.createElement( QStringLiteral( "constraint" ) );
3145 constraintElem.setAttribute( QStringLiteral( "field" ), field.name() );
3146 constraintElem.setAttribute( QStringLiteral( "constraints" ), field.constraints().constraints() );
3147 constraintElem.setAttribute( QStringLiteral( "unique_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintUnique ) );
3148 constraintElem.setAttribute( QStringLiteral( "notnull_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintNotNull ) );
3149 constraintElem.setAttribute( QStringLiteral( "exp_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintExpression ) );
3150
3151 constraintsElem.appendChild( constraintElem );
3152 }
3153 node.appendChild( constraintsElem );
3154
3155 // constraint expressions
3156 QDomElement constraintExpressionsElem = doc.createElement( QStringLiteral( "constraintExpressions" ) );
3157 for ( const QgsField &field : std::as_const( mFields ) )
3158 {
3159 QDomElement constraintExpressionElem = doc.createElement( QStringLiteral( "constraint" ) );
3160 constraintExpressionElem.setAttribute( QStringLiteral( "field" ), field.name() );
3161 constraintExpressionElem.setAttribute( QStringLiteral( "exp" ), field.constraints().constraintExpression() );
3162 constraintExpressionElem.setAttribute( QStringLiteral( "desc" ), field.constraints().constraintDescription() );
3163 constraintExpressionsElem.appendChild( constraintExpressionElem );
3164 }
3165 node.appendChild( constraintExpressionsElem );
3166
3167 // save expression fields
3168 if ( !mExpressionFieldBuffer )
3169 {
3170 // can happen when saving style on a invalid layer
3172 dummy.writeXml( node, doc );
3173 }
3174 else
3175 {
3176 mExpressionFieldBuffer->writeXml( node, doc );
3177 }
3178 }
3179
3180 // add attribute actions
3181 if ( categories.testFlag( Actions ) )
3182 mActions->writeXml( node );
3183
3184 if ( categories.testFlag( AttributeTable ) )
3185 {
3186 mAttributeTableConfig.writeXml( node );
3187 mConditionalStyles->writeXml( node, doc, context );
3188 mStoredExpressionManager->writeXml( node );
3189 }
3190
3191 if ( categories.testFlag( Forms ) )
3192 mEditFormConfig.writeXml( node, context );
3193
3194 // save readonly state
3195 if ( categories.testFlag( LayerConfiguration ) )
3196 node.toElement().setAttribute( QStringLiteral( "readOnly" ), mReadOnly );
3197
3198 // save preview expression
3199 if ( categories.testFlag( LayerConfiguration ) )
3200 {
3201 QDomElement prevExpElem = doc.createElement( QStringLiteral( "previewExpression" ) );
3202 QDomText prevExpText = doc.createTextNode( mDisplayExpression );
3203 prevExpElem.appendChild( prevExpText );
3204 node.appendChild( prevExpElem );
3205 }
3206
3207 // save map tip
3208 if ( categories.testFlag( MapTips ) )
3209 {
3210 QDomElement mapTipElem = doc.createElement( QStringLiteral( "mapTip" ) );
3211 mapTipElem.setAttribute( QStringLiteral( "enabled" ), mapTipsEnabled() );
3212 QDomText mapTipText = doc.createTextNode( mMapTipTemplate );
3213 mapTipElem.appendChild( mapTipText );
3214 node.toElement().appendChild( mapTipElem );
3215 }
3216
3217 return true;
3218}
3219
3220bool QgsVectorLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
3221 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
3222{
3224
3225 QDomElement mapLayerNode = node.toElement();
3226
3227 emit writeCustomSymbology( mapLayerNode, doc, errorMessage );
3228
3229 // we must try to write the renderer if our geometry type is unknown
3230 // as this allows the renderer to be correctly restored even for layers
3231 // with broken sources
3232 if ( isSpatial() || mWkbType == Qgis::WkbType::Unknown )
3233 {
3234 if ( categories.testFlag( Symbology ) )
3235 {
3236 if ( mRenderer )
3237 {
3238 QDomElement rendererElement = mRenderer->save( doc, context );
3239 node.appendChild( rendererElement );
3240 }
3241 if ( mSelectionProperties )
3242 {
3243 mSelectionProperties->writeXml( mapLayerNode, doc, context );
3244 }
3245 }
3246
3247 if ( categories.testFlag( Labeling ) )
3248 {
3249 if ( mLabeling )
3250 {
3251 QDomElement labelingElement = mLabeling->save( doc, context );
3252 node.appendChild( labelingElement );
3253 }
3254 mapLayerNode.setAttribute( QStringLiteral( "labelsEnabled" ), mLabelsEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
3255 }
3256
3257 // save the simplification drawing settings
3258 if ( categories.testFlag( Rendering ) )
3259 {
3260 mapLayerNode.setAttribute( QStringLiteral( "simplifyDrawingHints" ), QString::number( static_cast< int >( mSimplifyMethod.simplifyHints() ) ) );
3261 mapLayerNode.setAttribute( QStringLiteral( "simplifyAlgorithm" ), QString::number( static_cast< int >( mSimplifyMethod.simplifyAlgorithm() ) ) );
3262 mapLayerNode.setAttribute( QStringLiteral( "simplifyDrawingTol" ), QString::number( mSimplifyMethod.threshold() ) );
3263 mapLayerNode.setAttribute( QStringLiteral( "simplifyLocal" ), mSimplifyMethod.forceLocalOptimization() ? 1 : 0 );
3264 mapLayerNode.setAttribute( QStringLiteral( "simplifyMaxScale" ), QString::number( mSimplifyMethod.maximumScale() ) );
3265 }
3266
3267 //save customproperties
3268 if ( categories.testFlag( CustomProperties ) )
3269 {
3270 writeCustomProperties( node, doc );
3271 }
3272
3273 if ( categories.testFlag( Symbology ) )
3274 {
3275 // add the blend mode field
3276 QDomElement blendModeElem = doc.createElement( QStringLiteral( "blendMode" ) );
3277 QDomText blendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( blendMode() ) ) ) );
3278 blendModeElem.appendChild( blendModeText );
3279 node.appendChild( blendModeElem );
3280
3281 // add the feature blend mode field
3282 QDomElement featureBlendModeElem = doc.createElement( QStringLiteral( "featureBlendMode" ) );
3283 QDomText featureBlendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( featureBlendMode() ) ) ) );
3284 featureBlendModeElem.appendChild( featureBlendModeText );
3285 node.appendChild( featureBlendModeElem );
3286 }
3287
3288 // add the layer opacity and scale visibility
3289 if ( categories.testFlag( Rendering ) )
3290 {
3291 QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
3292 QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
3293 layerOpacityElem.appendChild( layerOpacityText );
3294 node.appendChild( layerOpacityElem );
3295 mapLayerNode.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
3296 mapLayerNode.setAttribute( QStringLiteral( "maxScale" ), maximumScale() );
3297 mapLayerNode.setAttribute( QStringLiteral( "minScale" ), minimumScale() );
3298
3299 mapLayerNode.setAttribute( QStringLiteral( "symbologyReferenceScale" ), mRenderer ? mRenderer->referenceScale() : -1 );
3300 }
3301
3302 if ( categories.testFlag( Diagrams ) && mDiagramRenderer )
3303 {
3304 mDiagramRenderer->writeXml( mapLayerNode, doc, context );
3305 if ( mDiagramLayerSettings )
3306 mDiagramLayerSettings->writeXml( mapLayerNode, doc );
3307 }
3308 }
3309 return true;
3310}
3311
3312bool QgsVectorLayer::readSld( const QDomNode &node, QString &errorMessage )
3313{
3315
3316 // get the Name element
3317 QDomElement nameElem = node.firstChildElement( QStringLiteral( "Name" ) );
3318 if ( nameElem.isNull() )
3319 {
3320 errorMessage = QStringLiteral( "Warning: Name element not found within NamedLayer while it's required." );
3321 }
3322
3323 if ( isSpatial() )
3324 {
3325 QgsFeatureRenderer *r = QgsFeatureRenderer::loadSld( node, geometryType(), errorMessage );
3326 if ( !r )
3327 return false;
3328
3329 // defer style changed signal until we've set the renderer, labeling, everything.
3330 // we don't want multiple signals!
3331 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
3332
3333 setRenderer( r );
3334
3335 // labeling
3336 readSldLabeling( node );
3337
3338 styleChangedSignalBlocker.release();
3340 }
3341 return true;
3342}
3343
3344bool QgsVectorLayer::writeSld( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QVariantMap &props ) const
3345{
3347
3348 Q_UNUSED( errorMessage )
3349
3350 QVariantMap localProps = QVariantMap( props );
3352 {
3354 }
3355
3356 if ( isSpatial() )
3357 {
3358 // store the Name element
3359 QDomElement nameNode = doc.createElement( QStringLiteral( "se:Name" ) );
3360 nameNode.appendChild( doc.createTextNode( name() ) );
3361 node.appendChild( nameNode );
3362
3363 QDomElement userStyleElem = doc.createElement( QStringLiteral( "UserStyle" ) );
3364 node.appendChild( userStyleElem );
3365
3366 QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
3367 nameElem.appendChild( doc.createTextNode( name() ) );
3368
3369 userStyleElem.appendChild( nameElem );
3370
3371 QDomElement featureTypeStyleElem = doc.createElement( QStringLiteral( "se:FeatureTypeStyle" ) );
3372 userStyleElem.appendChild( featureTypeStyleElem );
3373
3374 mRenderer->toSld( doc, featureTypeStyleElem, localProps );
3375 if ( labelsEnabled() )
3376 {
3377 mLabeling->toSld( featureTypeStyleElem, localProps );
3378 }
3379 }
3380 return true;
3381}
3382
3383
3384bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, QgsGeometry &geom, bool skipDefaultValue )
3385{
3387
3388 if ( !mEditBuffer || !mDataProvider )
3389 {
3390 return false;
3391 }
3392
3393 if ( mGeometryOptions->isActive() )
3394 mGeometryOptions->apply( geom );
3395
3396 updateExtents();
3397
3398 bool result = mEditBuffer->changeGeometry( fid, geom );
3399
3400 if ( result )
3401 {
3402 updateExtents();
3403 if ( !skipDefaultValue && !mDefaultValueOnUpdateFields.isEmpty() )
3404 updateDefaultValues( fid );
3405 }
3406 return result;
3407}
3408
3409
3410bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue, bool skipDefaultValues, QgsVectorLayerToolsContext *context )
3411{
3413
3414 bool result = false;
3415
3416 switch ( fields().fieldOrigin( field ) )
3417 {
3419 result = mJoinBuffer->changeAttributeValue( fid, field, newValue, oldValue );
3420 if ( result )
3421 emit attributeValueChanged( fid, field, newValue );
3422 break;
3423
3427 {
3428 if ( mEditBuffer && mDataProvider )
3429 result = mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
3430 break;
3431 }
3432
3434 break;
3435 }
3436
3437 if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
3438 updateDefaultValues( fid, QgsFeature(), context ? context->expressionContext() : nullptr );
3439
3440 return result;
3441}
3442
3443bool QgsVectorLayer::changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues, bool skipDefaultValues, QgsVectorLayerToolsContext *context )
3444{
3446
3447 bool result = true;
3448
3449 QgsAttributeMap newValuesJoin;
3450 QgsAttributeMap oldValuesJoin;
3451
3452 QgsAttributeMap newValuesNotJoin;
3453 QgsAttributeMap oldValuesNotJoin;
3454
3455 for ( auto it = newValues.constBegin(); it != newValues.constEnd(); ++it )
3456 {
3457 const int field = it.key();
3458 const QVariant newValue = it.value();
3459 QVariant oldValue;
3460
3461 if ( oldValues.contains( field ) )
3462 oldValue = oldValues[field];
3463
3464 switch ( fields().fieldOrigin( field ) )
3465 {
3467 newValuesJoin[field] = newValue;
3468 oldValuesJoin[field] = oldValue;
3469 break;
3470
3474 {
3475 newValuesNotJoin[field] = newValue;
3476 oldValuesNotJoin[field] = oldValue;
3477 break;
3478 }
3479
3481 break;
3482 }
3483 }
3484
3485 if ( ! newValuesJoin.isEmpty() && mJoinBuffer )
3486 {
3487 result = mJoinBuffer->changeAttributeValues( fid, newValuesJoin, oldValuesJoin );
3488 }
3489
3490 if ( ! newValuesNotJoin.isEmpty() )
3491 {
3492 if ( mEditBuffer && mDataProvider )
3493 result &= mEditBuffer->changeAttributeValues( fid, newValuesNotJoin, oldValues );
3494 else
3495 result = false;
3496 }
3497
3498 if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
3499 {
3500 updateDefaultValues( fid, QgsFeature(), context ? context->expressionContext() : nullptr );
3501 }
3502
3503 return result;
3504}
3505
3507{
3509
3510 if ( !mEditBuffer || !mDataProvider )
3511 return false;
3512
3513 return mEditBuffer->addAttribute( field );
3514}
3515
3517{
3519
3520 if ( attIndex < 0 || attIndex >= fields().count() )
3521 return;
3522
3523 QString name = fields().at( attIndex ).name();
3524 mFields[ attIndex ].setAlias( QString() );
3525 if ( mAttributeAliasMap.contains( name ) )
3526 {
3527 mAttributeAliasMap.remove( name );
3528 updateFields();
3529 mEditFormConfig.setFields( mFields );
3530 emit layerModified();
3531 }
3532}
3533
3534bool QgsVectorLayer::renameAttribute( int index, const QString &newName )
3535{
3537
3538 if ( index < 0 || index >= fields().count() )
3539 return false;
3540
3541 switch ( mFields.fieldOrigin( index ) )
3542 {
3544 {
3545 if ( mExpressionFieldBuffer )
3546 {
3547 int oi = mFields.fieldOriginIndex( index );
3548 mExpressionFieldBuffer->renameExpression( oi, newName );
3549 updateFields();
3550 return true;
3551 }
3552 else
3553 {
3554 return false;
3555 }
3556 }
3557
3560
3561 if ( !mEditBuffer || !mDataProvider )
3562 return false;
3563
3564 return mEditBuffer->renameAttribute( index, newName );
3565
3568 return false;
3569
3570 }
3571
3572 return false; // avoid warning
3573}
3574
3575void QgsVectorLayer::setFieldAlias( int attIndex, const QString &aliasString )
3576{
3578
3579 if ( attIndex < 0 || attIndex >= fields().count() )
3580 return;
3581
3582 QString name = fields().at( attIndex ).name();
3583
3584 mAttributeAliasMap.insert( name, aliasString );
3585 mFields[ attIndex ].setAlias( aliasString );
3586 mEditFormConfig.setFields( mFields );
3587 emit layerModified(); // TODO[MD]: should have a different signal?
3588}
3589
3590QString QgsVectorLayer::attributeAlias( int index ) const
3591{
3593
3594 if ( index < 0 || index >= fields().count() )
3595 return QString();
3596
3597 return fields().at( index ).alias();
3598}
3599
3601{
3603
3604 if ( index >= 0 && index < mFields.count() )
3605 return mFields.at( index ).displayName();
3606 else
3607 return QString();
3608}
3609
3611{
3613
3614 return mAttributeAliasMap;
3615}
3616
3618{
3620
3621 if ( index < 0 || index >= fields().count() )
3622 return;
3623
3624 const QString name = fields().at( index ).name();
3625
3626 mAttributeSplitPolicy.insert( name, policy );
3627 mFields[ index ].setSplitPolicy( policy );
3628 mEditFormConfig.setFields( mFields );
3629 emit layerModified(); // TODO[MD]: should have a different signal?
3630}
3631
3633{
3635
3636 if ( index < 0 || index >= fields().count() )
3637 return;
3638
3639 const QString name = fields().at( index ).name();
3640
3641 mAttributeDuplicatePolicy.insert( name, policy );
3642 mFields[ index ].setDuplicatePolicy( policy );
3643 mEditFormConfig.setFields( mFields );
3644 emit layerModified(); // TODO[MD]: should have a different signal?
3645}
3646
3647
3649{
3651
3652 QSet<QString> excludeList;
3653 QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
3654 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
3655 {
3656 if ( flagsIt->testFlag( Qgis::FieldConfigurationFlag::HideFromWms ) )
3657 {
3658 excludeList << flagsIt.key();
3659 }
3660 }
3661 return excludeList;
3662}
3663
3664void QgsVectorLayer::setExcludeAttributesWms( const QSet<QString> &att )
3665{
3667
3668 QMap< QString, Qgis::FieldConfigurationFlags >::iterator flagsIt = mFieldConfigurationFlags.begin();
3669 for ( ; flagsIt != mFieldConfigurationFlags.end(); ++flagsIt )
3670 {
3671 flagsIt->setFlag( Qgis::FieldConfigurationFlag::HideFromWms, att.contains( flagsIt.key() ) );
3672 }
3673 updateFields();
3674}
3675
3677{
3679
3680 QSet<QString> excludeList;
3681 QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
3682 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
3683 {
3684 if ( flagsIt->testFlag( Qgis::FieldConfigurationFlag::HideFromWfs ) )
3685 {
3686 excludeList << flagsIt.key();
3687 }
3688 }
3689 return excludeList;
3690}
3691
3692void QgsVectorLayer::setExcludeAttributesWfs( const QSet<QString> &att )
3693{
3695
3696 QMap< QString, Qgis::FieldConfigurationFlags >::iterator flagsIt = mFieldConfigurationFlags.begin();
3697 for ( ; flagsIt != mFieldConfigurationFlags.end(); ++flagsIt )
3698 {
3699 flagsIt->setFlag( Qgis::FieldConfigurationFlag::HideFromWfs, att.contains( flagsIt.key() ) );
3700 }
3701 updateFields();
3702}
3703
3705{
3707
3708 if ( index < 0 || index >= fields().count() )
3709 return false;
3710
3711 if ( mFields.fieldOrigin( index ) == Qgis::FieldOrigin::Expression )
3712 {
3713 removeExpressionField( index );
3714 return true;
3715 }
3716
3717 if ( !mEditBuffer || !mDataProvider )
3718 return false;
3719
3720 return mEditBuffer->deleteAttribute( index );
3721}
3722
3723bool QgsVectorLayer::deleteAttributes( const QList<int> &attrs )
3724{
3726
3727 bool deleted = false;
3728
3729 // Remove multiple occurrences of same attribute
3730 QList<int> attrList = qgis::setToList( qgis::listToSet( attrs ) );
3731
3732 std::sort( attrList.begin(), attrList.end(), std::greater<int>() );
3733
3734 for ( int attr : std::as_const( attrList ) )
3735 {
3736 if ( deleteAttribute( attr ) )
3737 {
3738 deleted = true;
3739 }
3740 }
3741
3742 return deleted;
3743}
3744
3745bool QgsVectorLayer::deleteFeatureCascade( QgsFeatureId fid, QgsVectorLayer::DeleteContext *context )
3746{
3748
3749 if ( !mEditBuffer )
3750 return false;
3751
3752 if ( context && context->cascade )
3753 {
3754 const QList<QgsRelation> relations = context->project->relationManager()->referencedRelations( this );
3755 const bool hasRelationsOrJoins = !relations.empty() || mJoinBuffer->containsJoins();
3756 if ( hasRelationsOrJoins )
3757 {
3758 if ( context->mHandledFeatures.contains( this ) )
3759 {
3760 QgsFeatureIds &handledFeatureIds = context->mHandledFeatures[ this ];
3761 if ( handledFeatureIds.contains( fid ) )
3762 {
3763 // avoid endless recursion
3764 return false;
3765 }
3766 else
3767 {
3768 // add feature id
3769 handledFeatureIds << fid;
3770 }
3771 }
3772 else
3773 {
3774 // add layer and feature id
3775 context->mHandledFeatures.insert( this, QgsFeatureIds() << fid );
3776 }
3777
3778 for ( const QgsRelation &relation : relations )
3779 {
3780 //check if composition (and not association)
3781 switch ( relation.strength() )
3782 {
3784 {
3785 //get features connected over this relation
3786 QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( getFeature( fid ) );
3787 QgsFeatureIds childFeatureIds;
3788 QgsFeature childFeature;
3789 while ( relatedFeaturesIt.nextFeature( childFeature ) )
3790 {
3791 childFeatureIds.insert( childFeature.id() );
3792 }
3793 if ( childFeatureIds.count() > 0 )
3794 {
3795 relation.referencingLayer()->startEditing();
3796 relation.referencingLayer()->deleteFeatures( childFeatureIds, context );
3797 }
3798 break;
3799 }
3800
3802 break;
3803 }
3804 }
3805 }
3806 }
3807
3808 if ( mJoinBuffer->containsJoins() )
3809 mJoinBuffer->deleteFeature( fid, context );
3810
3811 bool res = mEditBuffer->deleteFeature( fid );
3812
3813 return res;
3814}
3815
3817{
3819
3820 if ( !mEditBuffer )
3821 return false;
3822
3823 bool res = deleteFeatureCascade( fid, context );
3824
3825 if ( res )
3826 {
3827 updateExtents();
3828 }
3829
3830 return res;
3831}
3832
3834{
3836
3837 bool res = true;
3838
3839 if ( ( context && context->cascade ) || mJoinBuffer->containsJoins() )
3840 {
3841 // should ideally be "deleteFeaturesCascade" for performance!
3842 for ( QgsFeatureId fid : fids )
3843 res = deleteFeatureCascade( fid, context ) && res;
3844 }
3845 else
3846 {
3847 res = mEditBuffer && mEditBuffer->deleteFeatures( fids );
3848 }
3849
3850 if ( res )
3851 {
3852 mSelectedFeatureIds.subtract( fids ); // remove it from selection
3853 updateExtents();
3854 }
3855
3856 return res;
3857}
3858
3860{
3861 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
3863
3864 return mFields;
3865}
3866
3868{
3870
3871 QgsAttributeList pkAttributesList;
3872 if ( !mDataProvider )
3873 return pkAttributesList;
3874
3875 QgsAttributeList providerIndexes = mDataProvider->pkAttributeIndexes();
3876 for ( int i = 0; i < mFields.count(); ++i )
3877 {
3878 if ( mFields.fieldOrigin( i ) == Qgis::FieldOrigin::Provider &&
3879 providerIndexes.contains( mFields.fieldOriginIndex( i ) ) )
3880 pkAttributesList << i;
3881 }
3882
3883 return pkAttributesList;
3884}
3885
3887{
3889
3890 if ( !mDataProvider )
3891 return static_cast< long long >( Qgis::FeatureCountState::UnknownCount );
3892 return mDataProvider->featureCount() +
3893 ( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->addedFeatures().size() - mEditBuffer->deletedFeatureIds().size() : 0 );
3894}
3895
3897{
3899
3900 const QgsFeatureIds deletedFeatures( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->deletedFeatureIds() : QgsFeatureIds() );
3901 const QgsFeatureMap addedFeatures( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->addedFeatures() : QgsFeatureMap() );
3902
3903 if ( mEditBuffer && !deletedFeatures.empty() )
3904 {
3905 if ( addedFeatures.size() > deletedFeatures.size() )
3907 else
3909 }
3910
3911 if ( ( !mEditBuffer || addedFeatures.empty() ) && mDataProvider && mDataProvider->empty() )
3913 else
3915}
3916
3917bool QgsVectorLayer::commitChanges( bool stopEditing )
3918{
3920
3921 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
3922 return project()->commitChanges( mCommitErrors, stopEditing, this );
3923
3924 mCommitErrors.clear();
3925
3926 if ( !mDataProvider )
3927 {
3928 mCommitErrors << tr( "ERROR: no provider" );
3929 return false;
3930 }
3931
3932 if ( !mEditBuffer )
3933 {
3934 mCommitErrors << tr( "ERROR: layer not editable" );
3935 return false;
3936 }
3937
3938 emit beforeCommitChanges( stopEditing );
3939
3940 if ( !mAllowCommit )
3941 return false;
3942
3943 mCommitChangesActive = true;
3944
3945 bool success = false;
3946 if ( mEditBuffer->editBufferGroup() )
3947 success = mEditBuffer->editBufferGroup()->commitChanges( mCommitErrors, stopEditing );
3948 else
3949 success = mEditBuffer->commitChanges( mCommitErrors );
3950
3951 mCommitChangesActive = false;
3952
3953 if ( !mDeletedFids.empty() )
3954 {
3955 emit featuresDeleted( mDeletedFids );
3956 mDeletedFids.clear();
3957 }
3958
3959 if ( success )
3960 {
3961 if ( stopEditing )
3962 {
3963 clearEditBuffer();
3964 }
3965 undoStack()->clear();
3966 emit afterCommitChanges();
3967 if ( stopEditing )
3968 emit editingStopped();
3969 }
3970 else
3971 {
3972 QgsMessageLog::logMessage( tr( "Commit errors:\n %1" ).arg( mCommitErrors.join( QLatin1String( "\n " ) ) ) );
3973 }
3974
3975 updateFields();
3976
3977 mDataProvider->updateExtents();
3978
3979 if ( stopEditing )
3980 {
3981 mDataProvider->leaveUpdateMode();
3982 }
3983
3984 // This second call is required because OGR provider with JSON
3985 // driver might have changed fields order after the call to
3986 // leaveUpdateMode
3987 if ( mFields.names() != mDataProvider->fields().names() )
3988 {
3989 updateFields();
3990 }
3991
3993
3994 return success;
3995}
3996
3998{
4000
4001 return mCommitErrors;
4002}
4003
4004bool QgsVectorLayer::rollBack( bool deleteBuffer )
4005{
4007
4008 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
4009 return project()->rollBack( mCommitErrors, deleteBuffer, this );
4010
4011 if ( !mEditBuffer )
4012 {
4013 return false;
4014 }
4015
4016 if ( !mDataProvider )
4017 {
4018 mCommitErrors << tr( "ERROR: no provider" );
4019 return false;
4020 }
4021
4022 bool rollbackExtent = !mDataProvider->transaction() && ( !mEditBuffer->deletedFeatureIds().isEmpty() ||
4023 !mEditBuffer->addedFeatures().isEmpty() ||
4024 !mEditBuffer->changedGeometries().isEmpty() );
4025
4026 emit beforeRollBack();
4027
4028 mEditBuffer->rollBack();
4029
4030 emit afterRollBack();
4031
4032 if ( isModified() )
4033 {
4034 // new undo stack roll back method
4035 // old method of calling every undo could cause many canvas refreshes
4036 undoStack()->setIndex( 0 );
4037 }
4038
4039 updateFields();
4040
4041 if ( deleteBuffer )
4042 {
4043 delete mEditBuffer;
4044 mEditBuffer = nullptr;
4045 undoStack()->clear();
4046 }
4047 emit editingStopped();
4048
4049 if ( rollbackExtent )
4050 updateExtents();
4051
4052 mDataProvider->leaveUpdateMode();
4053
4055 return true;
4056}
4057
4059{
4061
4062 return mSelectedFeatureIds.size();
4063}
4064
4066{
4067 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
4069
4070 return mSelectedFeatureIds;
4071}
4072
4074{
4076
4077 QgsFeatureList features;
4078 features.reserve( mSelectedFeatureIds.count() );
4079 QgsFeature f;
4080
4082
4083 while ( it.nextFeature( f ) )
4084 {
4085 features.push_back( f );
4086 }
4087
4088 return features;
4089}
4090
4092{
4094
4095 if ( mSelectedFeatureIds.isEmpty() )
4096 return QgsFeatureIterator();
4097
4100
4101 if ( mSelectedFeatureIds.count() == 1 )
4102 request.setFilterFid( *mSelectedFeatureIds.constBegin() );
4103 else
4104 request.setFilterFids( mSelectedFeatureIds );
4105
4106 return getFeatures( request );
4107}
4108
4110{
4112
4113 if ( !mEditBuffer || !mDataProvider )
4114 return false;
4115
4116 if ( mGeometryOptions->isActive() )
4117 {
4118 for ( auto feature = features.begin(); feature != features.end(); ++feature )
4119 {
4120 QgsGeometry geom = feature->geometry();
4121 mGeometryOptions->apply( geom );
4122 feature->setGeometry( geom );
4123 }
4124 }
4125
4126 bool res = mEditBuffer->addFeatures( features );
4127 updateExtents();
4128
4129 if ( res && mJoinBuffer->containsJoins() )
4130 res = mJoinBuffer->addFeatures( features );
4131
4132 return res;
4133}
4134
4136{
4138
4139 // if layer is not spatial, it has not CRS!
4140 setCrs( ( isSpatial() && mDataProvider ) ? mDataProvider->crs() : QgsCoordinateReferenceSystem() );
4141}
4142
4144{
4146
4148 if ( exp.isField() )
4149 {
4150 return static_cast<const QgsExpressionNodeColumnRef *>( exp.rootNode() )->name();
4151 }
4152
4153 return QString();
4154}
4155
4156void QgsVectorLayer::setDisplayExpression( const QString &displayExpression )
4157{
4159
4160 if ( mDisplayExpression == displayExpression )
4161 return;
4162
4163 mDisplayExpression = displayExpression;
4165}
4166
4168{
4170
4171 if ( !mDisplayExpression.isEmpty() || mFields.isEmpty() )
4172 {
4173 return mDisplayExpression;
4174 }
4175 else
4176 {
4177 const QString candidateName = QgsVectorLayerUtils::guessFriendlyIdentifierField( mFields );
4178 if ( !candidateName.isEmpty() )
4179 {
4180 return QgsExpression::quotedColumnRef( candidateName );
4181 }
4182 else
4183 {
4184 return QString();
4185 }
4186 }
4187}
4188
4190{
4192
4193 // display expressions are used as a fallback when no explicit map tip template is set
4194 return mapTipsEnabled() && ( !mapTipTemplate().isEmpty() || !displayExpression().isEmpty() );
4195}
4196
4198{
4200
4201 return ( mEditBuffer && mDataProvider );
4202}
4203
4205{
4206 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
4208
4211}
4212
4213bool QgsVectorLayer::isReadOnly() const
4214{
4216
4217 return mDataSourceReadOnly || mReadOnly;
4218}
4219
4220bool QgsVectorLayer::setReadOnly( bool readonly )
4221{
4223
4224 // exit if the layer is in editing mode
4225 if ( readonly && mEditBuffer )
4226 return false;
4227
4228 // exit if the data source is in read-only mode
4229 if ( !readonly && mDataSourceReadOnly )
4230 return false;
4231
4232 mReadOnly = readonly;
4233 emit readOnlyChanged();
4234 return true;
4235}
4236
4238{
4240
4241 if ( ! mDataProvider )
4242 return false;
4243
4244 if ( mDataSourceReadOnly )
4245 return false;
4246
4247 return mDataProvider->capabilities() & QgsVectorDataProvider::EditingCapabilities && ! mReadOnly;
4248}
4249
4251{
4253
4254 emit beforeModifiedCheck();
4255 return mEditBuffer && mEditBuffer->isModified();
4256}
4257
4258bool QgsVectorLayer::isAuxiliaryField( int index, int &srcIndex ) const
4259{
4261
4262 bool auxiliaryField = false;
4263 srcIndex = -1;
4264
4265 if ( !auxiliaryLayer() )
4266 return auxiliaryField;
4267
4268 if ( index >= 0 && fields().fieldOrigin( index ) == Qgis::FieldOrigin::Join )
4269 {
4270 const QgsVectorLayerJoinInfo *info = mJoinBuffer->joinForFieldIndex( index, fields(), srcIndex );
4271
4272 if ( info && info->joinLayerId() == auxiliaryLayer()->id() )
4273 auxiliaryField = true;
4274 }
4275
4276 return auxiliaryField;
4277}
4278
4280{
4282
4283 // we must allow setting a renderer if our geometry type is unknown
4284 // as this allows the renderer to be correctly set even for layers
4285 // with broken sources
4286 // (note that we allow REMOVING the renderer for non-spatial layers,
4287 // e.g. to permit removing the renderer when the layer changes from
4288 // a spatial layer to a non-spatial one)
4289 if ( r && !isSpatial() && mWkbType != Qgis::WkbType::Unknown )
4290 return;
4291
4292 if ( r != mRenderer )
4293 {
4294 delete mRenderer;
4295 mRenderer = r;
4296 mSymbolFeatureCounted = false;
4297 mSymbolFeatureCountMap.clear();
4298 mSymbolFeatureIdMap.clear();
4299
4300 if ( mRenderer )
4301 {
4302 const double refreshRate = QgsSymbolLayerUtils::rendererFrameRate( mRenderer );
4303 if ( refreshRate <= 0 )
4304 {
4305 mRefreshRendererTimer->stop();
4306 mRefreshRendererTimer->setInterval( 0 );
4307 }
4308 else
4309 {
4310 mRefreshRendererTimer->setInterval( 1000 / refreshRate );
4311 mRefreshRendererTimer->start();
4312 }
4313 }
4314
4315 emit rendererChanged();
4317 }
4318}
4319
4321{
4323
4324 if ( generator )
4325 {
4326 mRendererGenerators << generator;
4327 }
4328}
4329
4331{
4333
4334 for ( int i = mRendererGenerators.count() - 1; i >= 0; --i )
4335 {
4336 if ( mRendererGenerators.at( i )->id() == id )
4337 {
4338 delete mRendererGenerators.at( i );
4339 mRendererGenerators.removeAt( i );
4340 }
4341 }
4342}
4343
4344QList<const QgsFeatureRendererGenerator *> QgsVectorLayer::featureRendererGenerators() const
4345{
4346 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
4348
4349 QList< const QgsFeatureRendererGenerator * > res;
4350 for ( const QgsFeatureRendererGenerator *generator : mRendererGenerators )
4351 res << generator;
4352 return res;
4353}
4354
4355void QgsVectorLayer::beginEditCommand( const QString &text )
4356{
4358
4359 if ( !mDataProvider )
4360 {
4361 return;
4362 }
4363 if ( mDataProvider->transaction() )
4364 {
4365 QString ignoredError;
4366 mDataProvider->transaction()->createSavepoint( ignoredError );
4367 }
4368 undoStack()->beginMacro( text );
4369 mEditCommandActive = true;
4370 emit editCommandStarted( text );
4371}
4372
4374{
4376
4377 if ( !mDataProvider )
4378 {
4379 return;
4380 }
4381 undoStack()->endMacro();
4382 mEditCommandActive = false;
4383 if ( !mDeletedFids.isEmpty() )
4384 {
4385 if ( selectedFeatureCount() > 0 )
4386 {
4387 mSelectedFeatureIds.subtract( mDeletedFids );
4388 }
4389 emit featuresDeleted( mDeletedFids );
4390 mDeletedFids.clear();
4391 }
4392 emit editCommandEnded();
4393}
4394
4396{
4398
4399 if ( !mDataProvider )
4400 {
4401 return;
4402 }
4403 undoStack()->endMacro();
4404 undoStack()->undo();
4405
4406 // it's not directly possible to pop the last command off the stack (the destroyed one)
4407 // and delete, so we add a dummy obsolete command to force this to occur.
4408 // Pushing the new command deletes the destroyed one, and since the new
4409 // command is obsolete it's automatically deleted by the undo stack.
4410 std::unique_ptr< QUndoCommand > command = std::make_unique< QUndoCommand >();
4411 command->setObsolete( true );
4412 undoStack()->push( command.release() );
4413
4414 mEditCommandActive = false;
4415 mDeletedFids.clear();
4416 emit editCommandDestroyed();
4417}
4418
4420{
4422
4423 return mJoinBuffer->addJoin( joinInfo );
4424}
4425
4426bool QgsVectorLayer::removeJoin( const QString &joinLayerId )
4427{
4429
4430 return mJoinBuffer->removeJoin( joinLayerId );
4431}
4432
4433const QList< QgsVectorLayerJoinInfo > QgsVectorLayer::vectorJoins() const
4434{
4436
4437 return mJoinBuffer->vectorJoins();
4438}
4439
4440int QgsVectorLayer::addExpressionField( const QString &exp, const QgsField &fld )
4441{
4443
4444 emit beforeAddingExpressionField( fld.name() );
4445 mExpressionFieldBuffer->addExpression( exp, fld );
4446 updateFields();
4447 int idx = mFields.indexFromName( fld.name() );
4448 emit attributeAdded( idx );
4449 return idx;
4450}
4451
4453{
4455
4456 emit beforeRemovingExpressionField( index );
4457 int oi = mFields.fieldOriginIndex( index );
4458 mExpressionFieldBuffer->removeExpression( oi );
4459 updateFields();
4460 emit attributeDeleted( index );
4461}
4462
4463QString QgsVectorLayer::expressionField( int index ) const
4464{
4466
4467 if ( mFields.fieldOrigin( index ) != Qgis::FieldOrigin::Expression )
4468 return QString();
4469
4470 int oi = mFields.fieldOriginIndex( index );
4471 if ( oi < 0 || oi >= mExpressionFieldBuffer->expressions().size() )
4472 return QString();
4473
4474 return mExpressionFieldBuffer->expressions().at( oi ).cachedExpression.expression();
4475}
4476
4477void QgsVectorLayer::updateExpressionField( int index, const QString &exp )
4478{
4480
4481 int oi = mFields.fieldOriginIndex( index );
4482 mExpressionFieldBuffer->updateExpression( oi, exp );
4483}
4484
4486{
4487 // non fatal for now -- the QgsVirtualLayerTask class is not thread safe and calls this
4489
4490 if ( !mDataProvider )
4491 return;
4492
4493 QgsFields oldFields = mFields;
4494
4495 mFields = mDataProvider->fields();
4496
4497 // added / removed fields
4498 if ( mEditBuffer )
4499 mEditBuffer->updateFields( mFields );
4500
4501 // joined fields
4502 if ( mJoinBuffer->containsJoins() )
4503 mJoinBuffer->updateFields( mFields );
4504
4505 if ( mExpressionFieldBuffer )
4506 mExpressionFieldBuffer->updateFields( mFields );
4507
4508 // set aliases and default values
4509 for ( auto aliasIt = mAttributeAliasMap.constBegin(); aliasIt != mAttributeAliasMap.constEnd(); ++aliasIt )
4510 {
4511 int index = mFields.lookupField( aliasIt.key() );
4512 if ( index < 0 )
4513 continue;
4514
4515 mFields[ index ].setAlias( aliasIt.value() );
4516 }
4517
4518 for ( auto splitPolicyIt = mAttributeSplitPolicy.constBegin(); splitPolicyIt != mAttributeSplitPolicy.constEnd(); ++splitPolicyIt )
4519 {
4520 int index = mFields.lookupField( splitPolicyIt.key() );
4521 if ( index < 0 )
4522 continue;
4523
4524 mFields[ index ].setSplitPolicy( splitPolicyIt.value() );
4525 }
4526
4527 for ( auto duplicatePolicyIt = mAttributeDuplicatePolicy.constBegin(); duplicatePolicyIt != mAttributeDuplicatePolicy.constEnd(); ++duplicatePolicyIt )
4528 {
4529 int index = mFields.lookupField( duplicatePolicyIt.key() );
4530 if ( index < 0 )
4531 continue;
4532
4533 mFields[ index ].setDuplicatePolicy( duplicatePolicyIt.value() );
4534 }
4535
4536 // Update configuration flags
4537 QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
4538 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
4539 {
4540 int index = mFields.lookupField( flagsIt.key() );
4541 if ( index < 0 )
4542 continue;
4543
4544 mFields[index].setConfigurationFlags( flagsIt.value() );
4545 }
4546
4547 // Update default values
4548 mDefaultValueOnUpdateFields.clear();
4549 QMap< QString, QgsDefaultValue >::const_iterator defaultIt = mDefaultExpressionMap.constBegin();
4550 for ( ; defaultIt != mDefaultExpressionMap.constEnd(); ++defaultIt )
4551 {
4552 int index = mFields.lookupField( defaultIt.key() );
4553 if ( index < 0 )
4554 continue;
4555
4556 mFields[ index ].setDefaultValueDefinition( defaultIt.value() );
4557 if ( defaultIt.value().applyOnUpdate() )
4558 mDefaultValueOnUpdateFields.insert( index );
4559 }
4560
4561 QMap< QString, QgsFieldConstraints::Constraints >::const_iterator constraintIt = mFieldConstraints.constBegin();
4562 for ( ; constraintIt != mFieldConstraints.constEnd(); ++constraintIt )
4563 {
4564 int index = mFields.lookupField( constraintIt.key() );
4565 if ( index < 0 )
4566 continue;
4567
4568 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4569
4570 // always keep provider constraints intact
4571 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintNotNull ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintNotNull ) )
4573 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintUnique ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintUnique ) )
4575 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintExpression ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintExpression ) )
4577 mFields[ index ].setConstraints( constraints );
4578 }
4579
4580 QMap< QString, QPair< QString, QString > >::const_iterator constraintExpIt = mFieldConstraintExpressions.constBegin();
4581 for ( ; constraintExpIt != mFieldConstraintExpressions.constEnd(); ++constraintExpIt )
4582 {
4583 int index = mFields.lookupField( constraintExpIt.key() );
4584 if ( index < 0 )
4585 continue;
4586
4587 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4588
4589 // always keep provider constraints intact
4591 continue;
4592
4593 constraints.setConstraintExpression( constraintExpIt.value().first, constraintExpIt.value().second );
4594 mFields[ index ].setConstraints( constraints );
4595 }
4596
4597 QMap< QPair< QString, QgsFieldConstraints::Constraint >, QgsFieldConstraints::ConstraintStrength >::const_iterator constraintStrengthIt = mFieldConstraintStrength.constBegin();
4598 for ( ; constraintStrengthIt != mFieldConstraintStrength.constEnd(); ++constraintStrengthIt )
4599 {
4600 int index = mFields.lookupField( constraintStrengthIt.key().first );
4601 if ( index < 0 )
4602 continue;
4603
4604 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4605
4606 // always keep provider constraints intact
4608 continue;
4609
4610 constraints.setConstraintStrength( constraintStrengthIt.key().second, constraintStrengthIt.value() );
4611 mFields[ index ].setConstraints( constraints );
4612 }
4613
4614 auto fieldWidgetIterator = mFieldWidgetSetups.constBegin();
4615 for ( ; fieldWidgetIterator != mFieldWidgetSetups.constEnd(); ++ fieldWidgetIterator )
4616 {
4617 int index = mFields.indexOf( fieldWidgetIterator.key() );
4618 if ( index < 0 )
4619 continue;
4620
4621 mFields[index].setEditorWidgetSetup( fieldWidgetIterator.value() );
4622 }
4623
4624 if ( oldFields != mFields )
4625 {
4626 emit updatedFields();
4627 mEditFormConfig.setFields( mFields );
4628 }
4629
4630}
4631
4632QVariant QgsVectorLayer::defaultValue( int index, const QgsFeature &feature, QgsExpressionContext *context ) const
4633{
4635
4636 if ( index < 0 || index >= mFields.count() || !mDataProvider )
4637 return QVariant();
4638
4639 QString expression = mFields.at( index ).defaultValueDefinition().expression();
4640 if ( expression.isEmpty() )
4641 return mDataProvider->defaultValue( index );
4642
4643 QgsExpressionContext *evalContext = context;
4644 std::unique_ptr< QgsExpressionContext > tempContext;
4645 if ( !evalContext )
4646 {
4647 // no context passed, so we create a default one
4649 evalContext = tempContext.get();
4650 }
4651
4652 if ( feature.isValid() )
4653 {
4655 featScope->setFeature( feature );
4656 featScope->setFields( feature.fields() );
4657 evalContext->appendScope( featScope );
4658 }
4659
4660 QVariant val;
4661 QgsExpression exp( expression );
4662 exp.prepare( evalContext );
4663 if ( exp.hasEvalError() )
4664 {
4665 QgsLogger::warning( "Error evaluating default value: " + exp.evalErrorString() );
4666 }
4667 else
4668 {
4669 val = exp.evaluate( evalContext );
4670 }
4671
4672 if ( feature.isValid() )
4673 {
4674 delete evalContext->popScope();
4675 }
4676
4677 return val;
4678}
4679
4681{
4683
4684 if ( index < 0 || index >= mFields.count() )
4685 return;
4686
4687 if ( definition.isValid() )
4688 {
4689 mDefaultExpressionMap.insert( mFields.at( index ).name(), definition );
4690 }
4691 else
4692 {
4693 mDefaultExpressionMap.remove( mFields.at( index ).name() );
4694 }
4695 updateFields();
4696}
4697
4699{
4701
4702 if ( index < 0 || index >= mFields.count() )
4703 return QgsDefaultValue();
4704 else
4705 return mFields.at( index ).defaultValueDefinition();
4706}
4707
4708QSet<QVariant> QgsVectorLayer::uniqueValues( int index, int limit ) const
4709{
4711
4712 QSet<QVariant> uniqueValues;
4713 if ( !mDataProvider )
4714 {
4715 return uniqueValues;
4716 }
4717
4718 Qgis::FieldOrigin origin = mFields.fieldOrigin( index );
4719 switch ( origin )
4720 {
4722 return uniqueValues;
4723
4724 case Qgis::FieldOrigin::Provider: //a provider field
4725 {
4726 uniqueValues = mDataProvider->uniqueValues( index, limit );
4727
4728 if ( mEditBuffer && ! mDataProvider->transaction() )
4729 {
4730 QSet<QString> vals;
4731 const auto constUniqueValues = uniqueValues;
4732 for ( const QVariant &v : constUniqueValues )
4733 {
4734 vals << v.toString();
4735 }
4736
4737 QgsFeatureMap added = mEditBuffer->addedFeatures();
4738 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4739 while ( addedIt.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
4740 {
4741 addedIt.next();
4742 QVariant v = addedIt.value().attribute( index );
4743 if ( v.isValid() )
4744 {
4745 QString vs = v.toString();
4746 if ( !vals.contains( vs ) )
4747 {
4748 vals << vs;
4749 uniqueValues << v;
4750 }
4751 }
4752 }
4753
4754 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4755 while ( it.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
4756 {
4757 it.next();
4758 QVariant v = it.value().value( index );
4759 if ( v.isValid() )
4760 {
4761 QString vs = v.toString();
4762 if ( !vals.contains( vs ) )
4763 {
4764 vals << vs;
4765 uniqueValues << v;
4766 }
4767 }
4768 }
4769 }
4770
4771 return uniqueValues;
4772 }
4773
4775 // the layer is editable, but in certain cases it can still be avoided going through all features
4776 if ( mDataProvider->transaction() || (
4777 mEditBuffer->deletedFeatureIds().isEmpty() &&
4778 mEditBuffer->addedFeatures().isEmpty() &&
4779 !mEditBuffer->deletedAttributeIds().contains( index ) &&
4780 mEditBuffer->changedAttributeValues().isEmpty() ) )
4781 {
4782 uniqueValues = mDataProvider->uniqueValues( index, limit );
4783 return uniqueValues;
4784 }
4785 [[fallthrough]];
4786 //we need to go through each feature
4789 {
4790 QgsAttributeList attList;
4791 attList << index;
4792
4795 .setSubsetOfAttributes( attList ) );
4796
4797 QgsFeature f;
4798 QVariant currentValue;
4799 QHash<QString, QVariant> val;
4800 while ( fit.nextFeature( f ) )
4801 {
4802 currentValue = f.attribute( index );
4803 val.insert( currentValue.toString(), currentValue );
4804 if ( limit >= 0 && val.size() >= limit )
4805 {
4806 break;
4807 }
4808 }
4809
4810 return qgis::listToSet( val.values() );
4811 }
4812 }
4813
4814 Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
4815 return uniqueValues;
4816}
4817
4818QStringList QgsVectorLayer::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
4819{
4821
4822 QStringList results;
4823 if ( !mDataProvider )
4824 {
4825 return results;
4826 }
4827
4828 Qgis::FieldOrigin origin = mFields.fieldOrigin( index );
4829 switch ( origin )
4830 {
4832 return results;
4833
4834 case Qgis::FieldOrigin::Provider: //a provider field
4835 {
4836 results = mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
4837
4838 if ( mEditBuffer && ! mDataProvider->transaction() )
4839 {
4840 QgsFeatureMap added = mEditBuffer->addedFeatures();
4841 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4842 while ( addedIt.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
4843 {
4844 addedIt.next();
4845 QVariant v = addedIt.value().attribute( index );
4846 if ( v.isValid() )
4847 {
4848 QString vs = v.toString();
4849 if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
4850 {
4851 results << vs;
4852 }
4853 }
4854 }
4855
4856 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4857 while ( it.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
4858 {
4859 it.next();
4860 QVariant v = it.value().value( index );
4861 if ( v.isValid() )
4862 {
4863 QString vs = v.toString();
4864 if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
4865 {
4866 results << vs;
4867 }
4868 }
4869 }
4870 }
4871
4872 return results;
4873 }
4874
4876 // the layer is editable, but in certain cases it can still be avoided going through all features
4877 if ( mDataProvider->transaction() || ( mEditBuffer->deletedFeatureIds().isEmpty() &&
4878 mEditBuffer->addedFeatures().isEmpty() &&
4879 !mEditBuffer->deletedAttributeIds().contains( index ) &&
4880 mEditBuffer->changedAttributeValues().isEmpty() ) )
4881 {
4882 return mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
4883 }
4884 [[fallthrough]];
4885 //we need to go through each feature
4888 {
4889 QgsAttributeList attList;
4890 attList << index;
4891
4892 QgsFeatureRequest request;
4893 request.setSubsetOfAttributes( attList );
4895 QString fieldName = mFields.at( index ).name();
4896 request.setFilterExpression( QStringLiteral( "\"%1\" ILIKE '%%2%'" ).arg( fieldName, substring ) );
4897 QgsFeatureIterator fit = getFeatures( request );
4898
4899 QgsFeature f;
4900 QString currentValue;
4901 while ( fit.nextFeature( f ) )
4902 {
4903 currentValue = f.attribute( index ).toString();
4904 if ( !results.contains( currentValue ) )
4905 results << currentValue;
4906
4907 if ( ( limit >= 0 && results.size() >= limit ) || ( feedback && feedback->isCanceled() ) )
4908 {
4909 break;
4910 }
4911 }
4912
4913 return results;
4914 }
4915 }
4916
4917 Q_ASSERT_X( false, "QgsVectorLayer::uniqueStringsMatching()", "Unknown source of the field!" );
4918 return results;
4919}
4920
4921QVariant QgsVectorLayer::minimumValue( int index ) const
4922{
4924
4925 QVariant minimum;
4926 minimumOrMaximumValue( index, &minimum, nullptr );
4927 return minimum;
4928}
4929
4930QVariant QgsVectorLayer::maximumValue( int index ) const
4931{
4933
4934 QVariant maximum;
4935 minimumOrMaximumValue( index, nullptr, &maximum );
4936 return maximum;
4937}
4938
4939void QgsVectorLayer::minimumAndMaximumValue( int index, QVariant &minimum, QVariant &maximum ) const
4940{
4942
4943 minimumOrMaximumValue( index, &minimum, &maximum );
4944}
4945
4946void QgsVectorLayer::minimumOrMaximumValue( int index, QVariant *minimum, QVariant *maximum ) const
4947{
4949
4950 if ( minimum )
4951 *minimum = QVariant();
4952 if ( maximum )
4953 *maximum = QVariant();
4954
4955 if ( !mDataProvider )
4956 {
4957 return;
4958 }
4959
4960 Qgis::FieldOrigin origin = mFields.fieldOrigin( index );
4961
4962 switch ( origin )
4963 {
4965 {
4966 return;
4967 }
4968
4969 case Qgis::FieldOrigin::Provider: //a provider field
4970 {
4971 if ( minimum )
4972 *minimum = mDataProvider->minimumValue( index );
4973 if ( maximum )
4974 *maximum = mDataProvider->maximumValue( index );
4975 if ( mEditBuffer && ! mDataProvider->transaction() )
4976 {
4977 const QgsFeatureMap added = mEditBuffer->addedFeatures();
4978 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4979 while ( addedIt.hasNext() )
4980 {
4981 addedIt.next();
4982 const QVariant v = addedIt.value().attribute( index );
4983 if ( minimum && v.isValid() && qgsVariantLessThan( v, *minimum ) )
4984 *minimum = v;
4985 if ( maximum && v.isValid() && qgsVariantGreaterThan( v, *maximum ) )
4986 *maximum = v;
4987 }
4988
4989 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4990 while ( it.hasNext() )
4991 {
4992 it.next();
4993 const QVariant v = it.value().value( index );
4994 if ( minimum && v.isValid() && qgsVariantLessThan( v, *minimum ) )
4995 *minimum = v;
4996 if ( maximum && v.isValid() && qgsVariantGreaterThan( v, *maximum ) )
4997 *maximum = v;
4998 }
4999 }
5000 return;
5001 }
5002
5004 {
5005 // the layer is editable, but in certain cases it can still be avoided going through all features
5006 if ( mDataProvider->transaction() || ( mEditBuffer->deletedFeatureIds().isEmpty() &&
5007 mEditBuffer->addedFeatures().isEmpty() &&
5008 !mEditBuffer->deletedAttributeIds().contains( index ) &&
5009 mEditBuffer->changedAttributeValues().isEmpty() ) )
5010 {
5011 if ( minimum )
5012 *minimum = mDataProvider->minimumValue( index );
5013 if ( maximum )
5014 *maximum = mDataProvider->maximumValue( index );
5015 return;
5016 }
5017 }
5018 [[fallthrough]];
5019 // no choice but to go through all features
5022 {
5023 // we need to go through each feature
5024 QgsAttributeList attList;
5025 attList << index;
5026
5029 .setSubsetOfAttributes( attList ) );
5030
5031 QgsFeature f;
5032 bool firstValue = true;
5033 while ( fit.nextFeature( f ) )
5034 {
5035 const QVariant currentValue = f.attribute( index );
5036 if ( QgsVariantUtils::isNull( currentValue ) )
5037 continue;
5038
5039 if ( firstValue )
5040 {
5041 if ( minimum )
5042 *minimum = currentValue;
5043 if ( maximum )
5044 *maximum = currentValue;
5045 firstValue = false;
5046 }
5047 else
5048 {
5049 if ( minimum && currentValue.isValid() && qgsVariantLessThan( currentValue, *minimum ) )
5050 *minimum = currentValue;
5051 if ( maximum && currentValue.isValid() && qgsVariantGreaterThan( currentValue, *maximum ) )
5052 *maximum = currentValue;
5053 }
5054 }
5055 return;
5056 }
5057 }
5058
5059 Q_ASSERT_X( false, "QgsVectorLayer::minimumOrMaximumValue()", "Unknown source of the field!" );
5060}
5061
5062void QgsVectorLayer::createEditBuffer()
5063{
5065
5066 if ( mEditBuffer )
5067 clearEditBuffer();
5068
5069 if ( mDataProvider->transaction() )
5070 {
5071 mEditBuffer = new QgsVectorLayerEditPassthrough( this );
5072
5073 connect( mDataProvider->transaction(), &QgsTransaction::dirtied, this, &QgsVectorLayer::onDirtyTransaction, Qt::UniqueConnection );
5074 }
5075 else
5076 {
5077 mEditBuffer = new QgsVectorLayerEditBuffer( this );
5078 }
5079 // forward signals
5080 connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::invalidateSymbolCountedFlag );
5081 connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::layerModified ); // TODO[MD]: necessary?
5082 //connect( mEditBuffer, SIGNAL( layerModified() ), this, SLOT( triggerRepaint() ) ); // TODO[MD]: works well?
5084 connect( mEditBuffer, &QgsVectorLayerEditBuffer::featureDeleted, this, &QgsVectorLayer::onFeatureDeleted );
5095
5096}
5097
5098void QgsVectorLayer::clearEditBuffer()
5099{
5101
5102 delete mEditBuffer;
5103 mEditBuffer = nullptr;
5104}
5105
5106QVariant QgsVectorLayer::aggregate( Qgis::Aggregate aggregate, const QString &fieldOrExpression,
5108 bool *ok, QgsFeatureIds *fids, QgsFeedback *feedback, QString *error ) const
5109{
5110 // non fatal for now -- the aggregate expression functions are not thread safe and call this
5112
5113 if ( ok )
5114 *ok = false;
5115 if ( error )
5116 error->clear();
5117
5118 if ( !mDataProvider )
5119 {
5120 if ( error )
5121 *error = tr( "Layer is invalid" );
5122 return QVariant();
5123 }
5124
5125 // test if we are calculating based on a field
5126 const int attrIndex = QgsExpression::expressionToLayerFieldIndex( fieldOrExpression, this );
5127 if ( attrIndex >= 0 )
5128 {
5129 // aggregate is based on a field - if it's a provider field, we could possibly hand over the calculation
5130 // to the provider itself
5131 Qgis::FieldOrigin origin = mFields.fieldOrigin( attrIndex );
5132 if ( origin == Qgis::FieldOrigin::Provider )
5133 {
5134 bool providerOk = false;
5135 QVariant val = mDataProvider->aggregate( aggregate, attrIndex, parameters, context, providerOk, fids );
5136 if ( providerOk )
5137 {
5138 // provider handled calculation
5139 if ( ok )
5140 *ok = true;
5141 return val;
5142 }
5143 }
5144 }
5145
5146 // fallback to using aggregate calculator to determine aggregate
5147 QgsAggregateCalculator c( this );
5148 if ( fids )
5149 c.setFidsFilter( *fids );
5150 c.setParameters( parameters );
5151 bool aggregateOk = false;
5152 const QVariant result = c.calculate( aggregate, fieldOrExpression, context, &aggregateOk, feedback );
5153 if ( ok )
5154 *ok = aggregateOk;
5155 if ( !aggregateOk && error )
5156 *error = c.lastError();
5157
5158 return result;
5159}
5160
5161void QgsVectorLayer::setFeatureBlendMode( QPainter::CompositionMode featureBlendMode )
5162{
5164
5165 if ( mFeatureBlendMode == featureBlendMode )
5166 return;
5167
5168 mFeatureBlendMode = featureBlendMode;
5171}
5172
5173QPainter::CompositionMode QgsVectorLayer::featureBlendMode() const
5174{
5175 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
5177
5178 return mFeatureBlendMode;
5179}
5180
5181void QgsVectorLayer::readSldLabeling( const QDomNode &node )
5182{
5184
5185 setLabeling( nullptr ); // start with no labeling
5186 setLabelsEnabled( false );
5187
5188 QDomElement element = node.toElement();
5189 if ( element.isNull() )
5190 return;
5191
5192 QDomElement userStyleElem = element.firstChildElement( QStringLiteral( "UserStyle" ) );
5193 if ( userStyleElem.isNull() )
5194 {
5195 QgsDebugMsgLevel( QStringLiteral( "Info: UserStyle element not found." ), 4 );
5196 return;
5197 }
5198
5199 QDomElement featTypeStyleElem = userStyleElem.firstChildElement( QStringLiteral( "FeatureTypeStyle" ) );
5200 if ( featTypeStyleElem.isNull() )
5201 {
5202 QgsDebugMsgLevel( QStringLiteral( "Info: FeatureTypeStyle element not found." ), 4 );
5203 return;
5204 }
5205
5206 // create empty FeatureTypeStyle element to merge TextSymbolizer's Rule's from all FeatureTypeStyle's
5207 QDomElement mergedFeatTypeStyle = featTypeStyleElem.cloneNode( false ).toElement();
5208
5209 // use the RuleRenderer when more rules are present or the rule
5210 // has filters or min/max scale denominators set,
5211 // otherwise use the Simple labeling
5212 bool needRuleBasedLabeling = false;
5213 int ruleCount = 0;
5214
5215 while ( !featTypeStyleElem.isNull() )
5216 {
5217 QDomElement ruleElem = featTypeStyleElem.firstChildElement( QStringLiteral( "Rule" ) );
5218 while ( !ruleElem.isNull() )
5219 {
5220 // test rule children element to check if we need to create RuleRenderer
5221 // and if the rule has a symbolizer
5222 bool hasTextSymbolizer = false;
5223 bool hasRuleBased = false;
5224 QDomElement ruleChildElem = ruleElem.firstChildElement();
5225 while ( !ruleChildElem.isNull() )
5226 {
5227 // rule has filter or min/max scale denominator, use the RuleRenderer
5228 if ( ruleChildElem.localName() == QLatin1String( "Filter" ) ||
5229 ruleChildElem.localName() == QLatin1String( "MinScaleDenominator" ) ||
5230 ruleChildElem.localName() == QLatin1String( "MaxScaleDenominator" ) )
5231 {
5232 hasRuleBased = true;
5233 }
5234 // rule has a renderer symbolizer, not a text symbolizer
5235 else if ( ruleChildElem.localName() == QLatin1String( "TextSymbolizer" ) )
5236 {
5237 QgsDebugMsgLevel( QStringLiteral( "Info: TextSymbolizer element found" ), 4 );
5238 hasTextSymbolizer = true;
5239 }
5240
5241 ruleChildElem = ruleChildElem.nextSiblingElement();
5242 }
5243
5244 if ( hasTextSymbolizer )
5245 {
5246 ruleCount++;
5247
5248 // append a clone of all Rules to the merged FeatureTypeStyle element
5249 mergedFeatTypeStyle.appendChild( ruleElem.cloneNode().toElement() );
5250
5251 if ( hasRuleBased )
5252 {
5253 QgsDebugMsgLevel( QStringLiteral( "Info: Filter or Min/MaxScaleDenominator element found: need a RuleBasedLabeling" ), 4 );
5254 needRuleBasedLabeling = true;
5255 }
5256 }
5257
5258 // more rules present, use the RuleRenderer
5259 if ( ruleCount > 1 )
5260 {
5261 QgsDebugMsgLevel( QStringLiteral( "Info: More Rule elements found: need a RuleBasedLabeling" ), 4 );
5262 needRuleBasedLabeling = true;
5263 }
5264
5265 // not use the rule based labeling if no rules with textSymbolizer
5266 if ( ruleCount == 0 )
5267 {
5268 needRuleBasedLabeling = false;
5269 }
5270
5271 ruleElem = ruleElem.nextSiblingElement( QStringLiteral( "Rule" ) );
5272 }
5273 featTypeStyleElem = featTypeStyleElem.nextSiblingElement( QStringLiteral( "FeatureTypeStyle" ) );
5274 }
5275
5276 if ( ruleCount == 0 )
5277 {
5278 QgsDebugMsgLevel( QStringLiteral( "Info: No TextSymbolizer element." ), 4 );
5279 return;
5280 }
5281
5282 QDomElement ruleElem = mergedFeatTypeStyle.firstChildElement( QStringLiteral( "Rule" ) );
5283
5284 if ( needRuleBasedLabeling )
5285 {
5286 QgsDebugMsgLevel( QStringLiteral( "Info: rule based labeling" ), 4 );
5287 QgsRuleBasedLabeling::Rule *rootRule = new QgsRuleBasedLabeling::Rule( nullptr );
5288 while ( !ruleElem.isNull() )
5289 {
5290
5291 QString label, description, filterExp;
5292 int scaleMinDenom = 0, scaleMaxDenom = 0;
5293 QgsPalLayerSettings settings;
5294
5295 // retrieve the Rule element child nodes
5296 QDomElement childElem = ruleElem.firstChildElement();
5297 while ( !childElem.isNull() )
5298 {
5299 if ( childElem.localName() == QLatin1String( "Name" ) )
5300 {
5301 // <se:Name> tag contains the rule identifier,
5302 // so prefer title tag for the label property value
5303 if ( label.isEmpty() )
5304 label = childElem.firstChild().nodeValue();
5305 }
5306 else if ( childElem.localName() == QLatin1String( "Description" ) )
5307 {
5308 // <se:Description> can contains a title and an abstract
5309 QDomElement titleElem = childElem.firstChildElement( QStringLiteral( "Title" ) );
5310 if ( !titleElem.isNull() )
5311 {
5312 label = titleElem.firstChild().nodeValue();
5313 }
5314
5315 QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( "Abstract" ) );
5316 if ( !abstractElem.isNull() )
5317 {
5318 description = abstractElem.firstChild().nodeValue();
5319 }
5320 }
5321 else if ( childElem.localName() == QLatin1String( "Abstract" ) )
5322 {
5323 // <sld:Abstract> (v1.0)
5324 description = childElem.firstChild().nodeValue();
5325 }
5326 else if ( childElem.localName() == QLatin1String( "Title" ) )
5327 {
5328 // <sld:Title> (v1.0)
5329 label = childElem.firstChild().nodeValue();
5330 }
5331 else if ( childElem.localName() == QLatin1String( "Filter" ) )
5332 {
5334 if ( filter )
5335 {
5336 if ( filter->hasParserError() )
5337 {
5338 QgsDebugMsgLevel( QStringLiteral( "SLD Filter parsing error: %1" ).arg( filter->parserErrorString() ), 3 );
5339 }
5340 else
5341 {
5342 filterExp = filter->expression();
5343 }
5344 delete filter;
5345 }
5346 }
5347 else if ( childElem.localName() == QLatin1String( "MinScaleDenominator" ) )
5348 {
5349 bool ok;
5350 int v = childElem.firstChild().nodeValue().toInt( &ok );
5351 if ( ok )
5352 scaleMinDenom = v;
5353 }
5354 else if ( childElem.localName() == QLatin1String( "MaxScaleDenominator" ) )
5355 {
5356 bool ok;
5357 int v = childElem.firstChild().nodeValue().toInt( &ok );
5358 if ( ok )
5359 scaleMaxDenom = v;
5360 }
5361 else if ( childElem.localName() == QLatin1String( "TextSymbolizer" ) )
5362 {
5363 readSldTextSymbolizer( childElem, settings );
5364 }
5365
5366 childElem = childElem.nextSiblingElement();
5367 }
5368
5369 QgsRuleBasedLabeling::Rule *ruleLabeling = new QgsRuleBasedLabeling::Rule( new QgsPalLayerSettings( settings ), scaleMinDenom, scaleMaxDenom, filterExp, label );
5370 rootRule->appendChild( ruleLabeling );
5371
5372 ruleElem = ruleElem.nextSiblingElement();
5373 }
5374
5375 setLabeling( new QgsRuleBasedLabeling( rootRule ) );
5376 setLabelsEnabled( true );
5377 }
5378 else
5379 {
5380 QgsDebugMsgLevel( QStringLiteral( "Info: simple labeling" ), 4 );
5381 // retrieve the TextSymbolizer element child node
5382 QDomElement textSymbolizerElem = ruleElem.firstChildElement( QStringLiteral( "TextSymbolizer" ) );
5384 if ( readSldTextSymbolizer( textSymbolizerElem, s ) )
5385 {
5387 setLabelsEnabled( true );
5388 }
5389 }
5390}
5391
5392bool QgsVectorLayer::readSldTextSymbolizer( const QDomNode &node, QgsPalLayerSettings &settings ) const
5393{
5395
5396 if ( node.localName() != QLatin1String( "TextSymbolizer" ) )
5397 {
5398 QgsDebugMsgLevel( QStringLiteral( "Not a TextSymbolizer element: %1" ).arg( node.localName() ), 3 );
5399 return false;
5400 }
5401 QDomElement textSymbolizerElem = node.toElement();
5402 // Label
5403 QDomElement labelElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Label" ) );
5404 if ( !labelElem.isNull() )
5405 {
5406 QDomElement propertyNameElem = labelElem.firstChildElement( QStringLiteral( "PropertyName" ) );
5407 if ( !propertyNameElem.isNull() )
5408 {
5409 // set labeling defaults
5410
5411 // label attribute
5412 QString labelAttribute = propertyNameElem.text();
5413 settings.fieldName = labelAttribute;
5414 settings.isExpression = false;
5415
5416 int fieldIndex = mFields.lookupField( labelAttribute );
5417 if ( fieldIndex == -1 )
5418 {
5419 // label attribute is not in columns, check if it is an expression
5420 QgsExpression exp( labelAttribute );
5421 if ( !exp.hasEvalError() )
5422 {
5423 settings.isExpression = true;
5424 }
5425 else
5426 {
5427 QgsDebugMsgLevel( QStringLiteral( "SLD label attribute error: %1" ).arg( exp.evalErrorString() ), 3 );
5428 }
5429 }
5430 }
5431 else
5432 {
5433 QgsDebugMsgLevel( QStringLiteral( "Info: PropertyName element not found." ), 4 );
5434 return false;
5435 }
5436 }
5437 else
5438 {
5439 QgsDebugMsgLevel( QStringLiteral( "Info: Label element not found." ), 4 );
5440 return false;
5441 }
5442
5444 if ( textSymbolizerElem.hasAttribute( QStringLiteral( "uom" ) ) )
5445 {
5446 sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( textSymbolizerElem.attribute( QStringLiteral( "uom" ) ) );
5447 }
5448
5449 QString fontFamily = QStringLiteral( "Sans-Serif" );
5450 int fontPointSize = 10;
5452 int fontWeight = -1;
5453 bool fontItalic = false;
5454 bool fontUnderline = false;
5455
5456 // Font
5457 QDomElement fontElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Font" ) );
5458 if ( !fontElem.isNull() )
5459 {
5460 QgsStringMap fontSvgParams = QgsSymbolLayerUtils::getSvgParameterList( fontElem );
5461 for ( QgsStringMap::iterator it = fontSvgParams.begin(); it != fontSvgParams.end(); ++it )
5462 {
5463 QgsDebugMsgLevel( QStringLiteral( "found fontSvgParams %1: %2" ).arg( it.key(), it.value() ), 4 );
5464
5465 if ( it.key() == QLatin1String( "font-family" ) )
5466 {
5467 fontFamily = it.value();
5468 }
5469 else if ( it.key() == QLatin1String( "font-style" ) )
5470 {
5471 fontItalic = ( it.value() == QLatin1String( "italic" ) ) || ( it.value() == QLatin1String( "Italic" ) );
5472 }
5473 else if ( it.key() == QLatin1String( "font-size" ) )
5474 {
5475 bool ok;
5476 int fontSize = it.value().toInt( &ok );
5477 if ( ok )
5478 {
5479 fontPointSize = fontSize;
5480 fontUnitSize = sldUnitSize;
5481 }
5482 }
5483 else if ( it.key() == QLatin1String( "font-weight" ) )
5484 {
5485 if ( ( it.value() == QLatin1String( "bold" ) ) || ( it.value() == QLatin1String( "Bold" ) ) )
5486 fontWeight = QFont::Bold;
5487 }
5488 else if ( it.key() == QLatin1String( "font-underline" ) )
5489 {
5490 fontUnderline = ( it.value() == QLatin1String( "underline" ) ) || ( it.value() == QLatin1String( "Underline" ) );
5491 }
5492 }
5493 }
5494
5495 QgsTextFormat format;
5496 QFont font( fontFamily, fontPointSize, fontWeight, fontItalic );
5497 font.setUnderline( fontUnderline );
5498 format.setFont( font );
5499 format.setSize( fontPointSize );
5500 format.setSizeUnit( fontUnitSize );
5501
5502 // Fill
5503 QDomElement fillElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Fill" ) );
5504 QColor textColor;
5505 Qt::BrushStyle textBrush = Qt::SolidPattern;
5506 QgsSymbolLayerUtils::fillFromSld( fillElem, textBrush, textColor );
5507 if ( textColor.isValid() )
5508 {
5509 QgsDebugMsgLevel( QStringLiteral( "Info: textColor %1." ).arg( QVariant( textColor ).toString() ), 4 );
5510 format.setColor( textColor );
5511 }
5512
5513 QgsTextBufferSettings bufferSettings;
5514
5515 // Halo
5516 QDomElement haloElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Halo" ) );
5517 if ( !haloElem.isNull() )
5518 {
5519 bufferSettings.setEnabled( true );
5520 bufferSettings.setSize( 1 );
5521
5522 QDomElement radiusElem = haloElem.firstChildElement( QStringLiteral( "Radius" ) );
5523 if ( !radiusElem.isNull() )
5524 {
5525 bool ok;
5526 double bufferSize = radiusElem.text().toDouble( &ok );
5527 if ( ok )
5528 {
5529 bufferSettings.setSize( bufferSize );
5530 bufferSettings.setSizeUnit( sldUnitSize );
5531 }
5532 }
5533
5534 QDomElement haloFillElem = haloElem.firstChildElement( QStringLiteral( "Fill" ) );
5535 QColor bufferColor;
5536 Qt::BrushStyle bufferBrush = Qt::SolidPattern;
5537 QgsSymbolLayerUtils::fillFromSld( haloFillElem, bufferBrush, bufferColor );
5538 if ( bufferColor.isValid() )
5539 {
5540 QgsDebugMsgLevel( QStringLiteral( "Info: bufferColor %1." ).arg( QVariant( bufferColor ).toString() ), 4 );
5541 bufferSettings.setColor( bufferColor );
5542 }
5543 }
5544
5545 // LabelPlacement
5546 QDomElement labelPlacementElem = textSymbolizerElem.firstChildElement( QStringLiteral( "LabelPlacement" ) );
5547 if ( !labelPlacementElem.isNull() )
5548 {
5549 // PointPlacement
5550 QDomElement pointPlacementElem = labelPlacementElem.firstChildElement( QStringLiteral( "PointPlacement" ) );
5551 if ( !pointPlacementElem.isNull() )
5552 {
5555 {
5557 }
5558
5559 QDomElement displacementElem = pointPlacementElem.firstChildElement( QStringLiteral( "Displacement" ) );
5560 if ( !displacementElem.isNull() )
5561 {
5562 QDomElement displacementXElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementX" ) );
5563 if ( !displacementXElem.isNull() )
5564 {
5565 bool ok;
5566 double xOffset = displacementXElem.text().toDouble( &ok );
5567 if ( ok )
5568 {
5569 settings.xOffset = xOffset;
5570 settings.offsetUnits = sldUnitSize;
5571 }
5572 }
5573 QDomElement displacementYElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementY" ) );
5574 if ( !displacementYElem.isNull() )
5575 {
5576 bool ok;
5577 double yOffset = displacementYElem.text().toDouble( &ok );
5578 if ( ok )
5579 {
5580 settings.yOffset = yOffset;
5581 settings.offsetUnits = sldUnitSize;
5582 }
5583 }
5584 }
5585 QDomElement anchorPointElem = pointPlacementElem.firstChildElement( QStringLiteral( "AnchorPoint" ) );
5586 if ( !anchorPointElem.isNull() )
5587 {
5588 QDomElement anchorPointXElem = anchorPointElem.firstChildElement( QStringLiteral( "AnchorPointX" ) );
5589 if ( !anchorPointXElem.isNull() )
5590 {
5591 bool ok;
5592 double xOffset = anchorPointXElem.text().toDouble( &ok );
5593 if ( ok )
5594 {
5595 settings.xOffset = xOffset;
5596 settings.offsetUnits = sldUnitSize;
5597 }
5598 }
5599 QDomElement anchorPointYElem = anchorPointElem.firstChildElement( QStringLiteral( "AnchorPointY" ) );
5600 if ( !anchorPointYElem.isNull() )
5601 {
5602 bool ok;
5603 double yOffset = anchorPointYElem.text().toDouble( &ok );
5604 if ( ok )
5605 {
5606 settings.yOffset = yOffset;
5607 settings.offsetUnits = sldUnitSize;
5608 }
5609 }
5610 }
5611
5612 QDomElement rotationElem = pointPlacementElem.firstChildElement( QStringLiteral( "Rotation" ) );
5613 if ( !rotationElem.isNull() )
5614 {
5615 bool ok;
5616 double rotation = rotationElem.text().toDouble( &ok );
5617 if ( ok )
5618 {
5619 settings.angleOffset = 360 - rotation;
5620 }
5621 }
5622 }
5623 else
5624 {
5625 // PointPlacement
5626 QDomElement linePlacementElem = labelPlacementElem.firstChildElement( QStringLiteral( "LinePlacement" ) );
5627 if ( !linePlacementElem.isNull() )
5628 {
5630 }
5631 }
5632 }
5633
5634 // read vendor options
5635 QgsStringMap vendorOptions;
5636 QDomElement vendorOptionElem = textSymbolizerElem.firstChildElement( QStringLiteral( "VendorOption" ) );
5637 while ( !vendorOptionElem.isNull() && vendorOptionElem.localName() == QLatin1String( "VendorOption" ) )
5638 {
5639 QString optionName = vendorOptionElem.attribute( QStringLiteral( "name" ) );
5640 QString optionValue;
5641 if ( vendorOptionElem.firstChild().nodeType() == QDomNode::TextNode )
5642 {
5643 optionValue = vendorOptionElem.firstChild().nodeValue();
5644 }
5645 else
5646 {
5647 if ( vendorOptionElem.firstChild().nodeType() == QDomNode::ElementNode &&
5648 vendorOptionElem.firstChild().localName() == QLatin1String( "Literal" ) )
5649 {