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