QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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 ) == QgsFields::OriginExpression )
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
424{
426
427 return mDataProvider ? mDataProvider->vectorLayerTypeFlags() : Qgis::VectorLayerTypeFlags();
428}
429
431{
433
434 if ( mDataProvider )
435 {
436 return mDataProvider->dataComment();
437 }
438 return QString();
439}
440
442{
444
445 return crs();
446}
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 );
599 QgsFeatureIds oldSelection = selectedFeatureIds();
600 QgsFeatureRequest request = QgsFeatureRequest().setFilterFids( oldSelection );
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
687{
689
691}
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
771{
773
774 return mTemporalProperties;
775}
776
778{
780
781 return mElevationProperties;
782}
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 )
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 ) );
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
1246{
1248
1249 return extent();
1250}
1251
1253{
1255
1256 return extent3D();
1257}
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
1785{
1787
1788 return addTopologicalPoints( QgsPoint( p ) );
1789}
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
1870{
1872
1873 return mDataProvider ? mDataProvider->hasSpatialIndex() : Qgis::SpatialIndexPresence::Unknown;
1874}
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 }
2247
2248 if ( profile )
2249 profile->switchTask( tr( "Read layer fields" ) );
2250 updateFields();
2251
2252 if ( mProviderKey == QLatin1String( "postgres" ) )
2253 {
2254 // update datasource from data provider computed one
2255 mDataSource = mDataProvider->dataSourceUri( false );
2256
2257 QgsDebugMsgLevel( QStringLiteral( "Beautifying layer name %1" ).arg( name() ), 3 );
2258
2259 // adjust the display name for postgres layers
2260 const thread_local QRegularExpression reg( R"lit("[^"]+"\."([^"] + )"( \‍([^)]+\))?)lit" );
2261 const QRegularExpressionMatch match = reg.match( name() );
2262 if ( match.hasMatch() )
2263 {
2264 QStringList stuff = match.capturedTexts();
2265 QString lName = stuff[1];
2266
2267 const QMap<QString, QgsMapLayer *> &layers = QgsProject::instance()->mapLayers();
2268
2269 QMap<QString, QgsMapLayer *>::const_iterator it;
2270 for ( it = layers.constBegin(); it != layers.constEnd() && ( *it )->name() != lName; ++it )
2271 ;
2272
2273 if ( it != layers.constEnd() && stuff.size() > 2 )
2274 {
2275 lName += '.' + stuff[2].mid( 2, stuff[2].length() - 3 );
2276 }
2277
2278 if ( !lName.isEmpty() )
2279 setName( lName );
2280 }
2281 QgsDebugMsgLevel( QStringLiteral( "Beautified layer name %1" ).arg( name() ), 3 );
2282 }
2283 else if ( mProviderKey == QLatin1String( "osm" ) )
2284 {
2285 // make sure that the "observer" has been removed from URI to avoid crashes
2286 mDataSource = mDataProvider->dataSourceUri();
2287 }
2288 else if ( provider == QLatin1String( "ogr" ) )
2289 {
2290 // make sure that the /vsigzip or /vsizip is added to uri, if applicable
2291 mDataSource = mDataProvider->dataSourceUri();
2292 if ( mDataSource.right( 10 ) == QLatin1String( "|layerid=0" ) )
2293 mDataSource.chop( 10 );
2294 }
2295 else if ( provider == QLatin1String( "memory" ) )
2296 {
2297 // required so that source differs between memory layers
2298 mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
2299 }
2300 else if ( provider == QLatin1String( "hana" ) )
2301 {
2302 // update datasource from data provider computed one
2303 mDataSource = mDataProvider->dataSourceUri( false );
2304 }
2305
2306 connect( mDataProvider, &QgsVectorDataProvider::dataChanged, this, &QgsVectorLayer::emitDataChanged );
2308
2309 return true;
2310} // QgsVectorLayer:: setDataProvider
2311
2312
2313
2314
2315/* virtual */
2316bool QgsVectorLayer::writeXml( QDomNode &layer_node,
2317 QDomDocument &document,
2318 const QgsReadWriteContext &context ) const
2319{
2321
2322 // first get the layer element so that we can append the type attribute
2323
2324 QDomElement mapLayerNode = layer_node.toElement();
2325
2326 if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) )
2327 {
2328 QgsDebugMsgLevel( QStringLiteral( "can't find <maplayer>" ), 2 );
2329 return false;
2330 }
2331
2332 mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( Qgis::LayerType::Vector ) );
2333
2334 // set the geometry type
2335 mapLayerNode.setAttribute( QStringLiteral( "geometry" ), QgsWkbTypes::geometryDisplayString( geometryType() ) );
2336 mapLayerNode.setAttribute( QStringLiteral( "wkbType" ), qgsEnumValueToKey( wkbType() ) );
2337
2338 // add provider node
2339 if ( mDataProvider )
2340 {
2341 QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
2342 provider.setAttribute( QStringLiteral( "encoding" ), mDataProvider->encoding() );
2343 QDomText providerText = document.createTextNode( providerType() );
2344 provider.appendChild( providerText );
2345 layer_node.appendChild( provider );
2346 }
2347
2348 //save joins
2349 mJoinBuffer->writeXml( layer_node, document );
2350
2351 // dependencies
2352 QDomElement dependenciesElement = document.createElement( QStringLiteral( "layerDependencies" ) );
2353 const auto constDependencies = dependencies();
2354 for ( const QgsMapLayerDependency &dep : constDependencies )
2355 {
2357 continue;
2358 QDomElement depElem = document.createElement( QStringLiteral( "layer" ) );
2359 depElem.setAttribute( QStringLiteral( "id" ), dep.layerId() );
2360 dependenciesElement.appendChild( depElem );
2361 }
2362 layer_node.appendChild( dependenciesElement );
2363
2364 // change dependencies
2365 QDomElement dataDependenciesElement = document.createElement( QStringLiteral( "dataDependencies" ) );
2366 for ( const QgsMapLayerDependency &dep : constDependencies )
2367 {
2368 if ( dep.type() != QgsMapLayerDependency::DataDependency )
2369 continue;
2370 QDomElement depElem = document.createElement( QStringLiteral( "layer" ) );
2371 depElem.setAttribute( QStringLiteral( "id" ), dep.layerId() );
2372 dataDependenciesElement.appendChild( depElem );
2373 }
2374 layer_node.appendChild( dataDependenciesElement );
2375
2376 // save expression fields
2377 mExpressionFieldBuffer->writeXml( layer_node, document );
2378
2379 writeStyleManager( layer_node, document );
2380
2381 // auxiliary layer
2382 QDomElement asElem = document.createElement( QStringLiteral( "auxiliaryLayer" ) );
2383 if ( mAuxiliaryLayer )
2384 {
2385 const QString pkField = mAuxiliaryLayer->joinInfo().targetFieldName();
2386 asElem.setAttribute( QStringLiteral( "key" ), pkField );
2387 }
2388 layer_node.appendChild( asElem );
2389
2390 // save QGIS Server properties (WMS Dimension, metadata URLS...)
2391 mServerProperties->writeXml( layer_node, document );
2392
2393 // renderer specific settings
2394 QString errorMsg;
2395 return writeSymbology( layer_node, document, errorMsg, context );
2396}
2397
2398QString QgsVectorLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
2399{
2401
2402 if ( providerType() == QLatin1String( "memory" ) )
2403 {
2404 // Refetch the source from the provider, because adding fields actually changes the source for this provider.
2405 return dataProvider()->dataSourceUri();
2406 }
2407
2409}
2410
2411QString QgsVectorLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
2412{
2414
2415 return QgsProviderRegistry::instance()->relativeToAbsoluteUri( provider, source, context );
2416}
2417
2418
2419
2421{
2423
2425 mJoinBuffer->resolveReferences( project );
2426}
2427
2428
2429bool QgsVectorLayer::readSymbology( const QDomNode &layerNode, QString &errorMessage,
2431{
2433
2434 if ( categories.testFlag( Fields ) )
2435 {
2436 if ( !mExpressionFieldBuffer )
2437 mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
2438 mExpressionFieldBuffer->readXml( layerNode );
2439
2440 updateFields();
2441 }
2442
2443 if ( categories.testFlag( Relations ) )
2444 {
2445 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Relations" ) );
2446
2447 const QgsPathResolver resolver { QgsProject::instance()->pathResolver() };
2448
2449 // Restore referenced layers: relations where "this" is the child layer (the referencing part, that holds the FK)
2450 QDomNodeList referencedLayersNodeList = layerNode.toElement().elementsByTagName( QStringLiteral( "referencedLayers" ) );
2451 if ( referencedLayersNodeList.size() > 0 )
2452 {
2453 const QDomNodeList relationNodes { referencedLayersNodeList.at( 0 ).childNodes() };
2454 for ( int i = 0; i < relationNodes.length(); ++i )
2455 {
2456 const QDomElement relationElement = relationNodes.at( i ).toElement();
2457
2458 mWeakRelations.push_back( QgsWeakRelation::readXml( this, QgsWeakRelation::Referencing, relationElement, resolver ) );
2459 }
2460 }
2461
2462 // Restore referencing layers: relations where "this" is the parent layer (the referenced part where the FK points to)
2463 QDomNodeList referencingLayersNodeList = layerNode.toElement().elementsByTagName( QStringLiteral( "referencingLayers" ) );
2464 if ( referencingLayersNodeList.size() > 0 )
2465 {
2466 const QDomNodeList relationNodes { referencingLayersNodeList.at( 0 ).childNodes() };
2467 for ( int i = 0; i < relationNodes.length(); ++i )
2468 {
2469 const QDomElement relationElement = relationNodes.at( i ).toElement();
2470 mWeakRelations.push_back( QgsWeakRelation::readXml( this, QgsWeakRelation::Referenced, relationElement, resolver ) );
2471 }
2472 }
2473 }
2474
2475 QDomElement layerElement = layerNode.toElement();
2476
2477 readCommonStyle( layerElement, context, categories );
2478
2479 readStyle( layerNode, errorMessage, context, categories );
2480
2481 if ( categories.testFlag( MapTips ) )
2482 {
2483 QDomElement mapTipElem = layerNode.namedItem( QStringLiteral( "mapTip" ) ).toElement();
2484 setMapTipTemplate( mapTipElem.text() );
2485 setMapTipsEnabled( mapTipElem.attribute( QStringLiteral( "enabled" ), QStringLiteral( "1" ) ).toInt() == 1 );
2486 }
2487
2488 if ( categories.testFlag( LayerConfiguration ) )
2489 mDisplayExpression = layerNode.namedItem( QStringLiteral( "previewExpression" ) ).toElement().text();
2490
2491 // Try to migrate pre QGIS 3.0 display field property
2492 QString displayField = layerNode.namedItem( QStringLiteral( "displayfield" ) ).toElement().text();
2493 if ( mFields.lookupField( displayField ) < 0 )
2494 {
2495 // if it's not a field, it's a maptip
2496 if ( mMapTipTemplate.isEmpty() && categories.testFlag( MapTips ) )
2497 mMapTipTemplate = displayField;
2498 }
2499 else
2500 {
2501 if ( mDisplayExpression.isEmpty() && categories.testFlag( LayerConfiguration ) )
2502 mDisplayExpression = QgsExpression::quotedColumnRef( displayField );
2503 }
2504
2505 // process the attribute actions
2506 if ( categories.testFlag( Actions ) )
2507 mActions->readXml( layerNode );
2508
2509 if ( categories.testFlag( Fields ) )
2510 {
2511 // IMPORTANT - we don't clear mAttributeAliasMap here, as it may contain aliases which are coming direct
2512 // from the data provider. Instead we leave any existing aliases and only overwrite them if the style
2513 // has a specific value for that field's alias
2514 QDomNode aliasesNode = layerNode.namedItem( QStringLiteral( "aliases" ) );
2515 if ( !aliasesNode.isNull() )
2516 {
2517 QDomElement aliasElem;
2518
2519 QDomNodeList aliasNodeList = aliasesNode.toElement().elementsByTagName( QStringLiteral( "alias" ) );
2520 for ( int i = 0; i < aliasNodeList.size(); ++i )
2521 {
2522 aliasElem = aliasNodeList.at( i ).toElement();
2523
2524 QString field;
2525 if ( aliasElem.hasAttribute( QStringLiteral( "field" ) ) )
2526 {
2527 field = aliasElem.attribute( QStringLiteral( "field" ) );
2528 }
2529 else
2530 {
2531 int index = aliasElem.attribute( QStringLiteral( "index" ) ).toInt();
2532
2533 if ( index >= 0 && index < fields().count() )
2534 field = fields().at( index ).name();
2535 }
2536
2537 QString alias;
2538
2539 if ( !aliasElem.attribute( QStringLiteral( "name" ) ).isEmpty() )
2540 {
2541 //if it has alias
2542 alias = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ), aliasElem.attribute( QStringLiteral( "name" ) ) );
2543 QgsDebugMsgLevel( "context" + QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ) + " source " + aliasElem.attribute( QStringLiteral( "name" ) ), 3 );
2544 }
2545 else
2546 {
2547 //if it has no alias, it should be the fields translation
2548 alias = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ), field );
2549 QgsDebugMsgLevel( "context" + QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ) + " source " + field, 3 );
2550 //if it gets the exact field value, there has been no translation (or not even translation loaded) - so no alias should be generated;
2551 if ( alias == aliasElem.attribute( QStringLiteral( "field" ) ) )
2552 alias.clear();
2553 }
2554
2555 QgsDebugMsgLevel( "field " + field + " origalias " + aliasElem.attribute( QStringLiteral( "name" ) ) + " trans " + alias, 3 );
2556 mAttributeAliasMap.insert( field, alias );
2557 }
2558 }
2559
2560 // IMPORTANT - we don't clear mAttributeSplitPolicy here, as it may contain policies which are coming direct
2561 // from the data provider. Instead we leave any existing policies and only overwrite them if the style
2562 // has a specific value for that field's policy
2563 const QDomNode splitPoliciesNode = layerNode.namedItem( QStringLiteral( "splitPolicies" ) );
2564 if ( !splitPoliciesNode.isNull() )
2565 {
2566 const QDomNodeList splitPolicyNodeList = splitPoliciesNode.toElement().elementsByTagName( QStringLiteral( "policy" ) );
2567 for ( int i = 0; i < splitPolicyNodeList.size(); ++i )
2568 {
2569 const QDomElement splitPolicyElem = splitPolicyNodeList.at( i ).toElement();
2570 const QString field = splitPolicyElem.attribute( QStringLiteral( "field" ) );
2571 const Qgis::FieldDomainSplitPolicy policy = qgsEnumKeyToValue( splitPolicyElem.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDomainSplitPolicy::Duplicate );
2572 mAttributeSplitPolicy.insert( field, policy );
2573 }
2574 }
2575
2576 // default expressions
2577 mDefaultExpressionMap.clear();
2578 QDomNode defaultsNode = layerNode.namedItem( QStringLiteral( "defaults" ) );
2579 if ( !defaultsNode.isNull() )
2580 {
2581 QDomNodeList defaultNodeList = defaultsNode.toElement().elementsByTagName( QStringLiteral( "default" ) );
2582 for ( int i = 0; i < defaultNodeList.size(); ++i )
2583 {
2584 QDomElement defaultElem = defaultNodeList.at( i ).toElement();
2585
2586 QString field = defaultElem.attribute( QStringLiteral( "field" ), QString() );
2587 QString expression = defaultElem.attribute( QStringLiteral( "expression" ), QString() );
2588 bool applyOnUpdate = defaultElem.attribute( QStringLiteral( "applyOnUpdate" ), QStringLiteral( "0" ) ) == QLatin1String( "1" );
2589 if ( field.isEmpty() || expression.isEmpty() )
2590 continue;
2591
2592 mDefaultExpressionMap.insert( field, QgsDefaultValue( expression, applyOnUpdate ) );
2593 }
2594 }
2595
2596 // constraints
2597 mFieldConstraints.clear();
2598 mFieldConstraintStrength.clear();
2599 QDomNode constraintsNode = layerNode.namedItem( QStringLiteral( "constraints" ) );
2600 if ( !constraintsNode.isNull() )
2601 {
2602 QDomNodeList constraintNodeList = constraintsNode.toElement().elementsByTagName( QStringLiteral( "constraint" ) );
2603 for ( int i = 0; i < constraintNodeList.size(); ++i )
2604 {
2605 QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2606
2607 QString field = constraintElem.attribute( QStringLiteral( "field" ), QString() );
2608 int constraints = constraintElem.attribute( QStringLiteral( "constraints" ), QStringLiteral( "0" ) ).toInt();
2609 if ( field.isEmpty() || constraints == 0 )
2610 continue;
2611
2612 mFieldConstraints.insert( field, static_cast< QgsFieldConstraints::Constraints >( constraints ) );
2613
2614 int uniqueStrength = constraintElem.attribute( QStringLiteral( "unique_strength" ), QStringLiteral( "1" ) ).toInt();
2615 int notNullStrength = constraintElem.attribute( QStringLiteral( "notnull_strength" ), QStringLiteral( "1" ) ).toInt();
2616 int expStrength = constraintElem.attribute( QStringLiteral( "exp_strength" ), QStringLiteral( "1" ) ).toInt();
2617
2618 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintUnique ), static_cast< QgsFieldConstraints::ConstraintStrength >( uniqueStrength ) );
2619 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintNotNull ), static_cast< QgsFieldConstraints::ConstraintStrength >( notNullStrength ) );
2620 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintExpression ), static_cast< QgsFieldConstraints::ConstraintStrength >( expStrength ) );
2621 }
2622 }
2623 mFieldConstraintExpressions.clear();
2624 QDomNode constraintExpressionsNode = layerNode.namedItem( QStringLiteral( "constraintExpressions" ) );
2625 if ( !constraintExpressionsNode.isNull() )
2626 {
2627 QDomNodeList constraintNodeList = constraintExpressionsNode.toElement().elementsByTagName( QStringLiteral( "constraint" ) );
2628 for ( int i = 0; i < constraintNodeList.size(); ++i )
2629 {
2630 QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2631
2632 QString field = constraintElem.attribute( QStringLiteral( "field" ), QString() );
2633 QString exp = constraintElem.attribute( QStringLiteral( "exp" ), QString() );
2634 QString desc = constraintElem.attribute( QStringLiteral( "desc" ), QString() );
2635 if ( field.isEmpty() || exp.isEmpty() )
2636 continue;
2637
2638 mFieldConstraintExpressions.insert( field, qMakePair( exp, desc ) );
2639 }
2640 }
2641
2642 updateFields();
2643 }
2644
2645 // load field configuration
2646 if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
2647 {
2648 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Forms" ) );
2649
2650 QDomElement widgetsElem = layerNode.namedItem( QStringLiteral( "fieldConfiguration" ) ).toElement();
2651 QDomNodeList fieldConfigurationElementList = widgetsElem.elementsByTagName( QStringLiteral( "field" ) );
2652 for ( int i = 0; i < fieldConfigurationElementList.size(); ++i )
2653 {
2654 const QDomElement fieldConfigElement = fieldConfigurationElementList.at( i ).toElement();
2655 const QDomElement fieldWidgetElement = fieldConfigElement.elementsByTagName( QStringLiteral( "editWidget" ) ).at( 0 ).toElement();
2656
2657 QString fieldName = fieldConfigElement.attribute( QStringLiteral( "name" ) );
2658
2659 if ( categories.testFlag( Fields ) )
2660 mFieldConfigurationFlags[fieldName] = qgsFlagKeysToValue( fieldConfigElement.attribute( QStringLiteral( "configurationFlags" ) ), Qgis::FieldConfigurationFlag::NoFlag );
2661
2662 // Load editor widget configuration
2663 if ( categories.testFlag( Forms ) )
2664 {
2665 const QString widgetType = fieldWidgetElement.attribute( QStringLiteral( "type" ) );
2666 const QDomElement cfgElem = fieldConfigElement.elementsByTagName( QStringLiteral( "config" ) ).at( 0 ).toElement();
2667 const QDomElement optionsElem = cfgElem.childNodes().at( 0 ).toElement();
2668 QVariantMap optionsMap = QgsXmlUtils::readVariant( optionsElem ).toMap();
2669 if ( widgetType == QLatin1String( "ValueRelation" ) )
2670 {
2671 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() );
2672 }
2673 QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( widgetType, optionsMap );
2674 mFieldWidgetSetups[fieldName] = setup;
2675 }
2676 }
2677 }
2678
2679 // Legacy reading for QGIS 3.14 and older projects
2680 // Attributes excluded from WMS and WFS
2681 if ( categories.testFlag( Fields ) )
2682 {
2683 const QList<QPair<QString, Qgis::FieldConfigurationFlag>> legacyConfig
2684 {
2685 qMakePair( QStringLiteral( "excludeAttributesWMS" ), Qgis::FieldConfigurationFlag::HideFromWms ),
2686 qMakePair( QStringLiteral( "excludeAttributesWFS" ), Qgis::FieldConfigurationFlag::HideFromWfs )
2687 };
2688 for ( const auto &config : legacyConfig )
2689 {
2690 QDomNode excludeNode = layerNode.namedItem( config.first );
2691 if ( !excludeNode.isNull() )
2692 {
2693 QDomNodeList attributeNodeList = excludeNode.toElement().elementsByTagName( QStringLiteral( "attribute" ) );
2694 for ( int i = 0; i < attributeNodeList.size(); ++i )
2695 {
2696 QString fieldName = attributeNodeList.at( i ).toElement().text();
2697 if ( !mFieldConfigurationFlags.contains( fieldName ) )
2698 mFieldConfigurationFlags[fieldName] = config.second;
2699 else
2700 mFieldConfigurationFlags[fieldName].setFlag( config.second, true );
2701 }
2702 }
2703 }
2704 }
2705
2706 if ( categories.testFlag( GeometryOptions ) )
2707 mGeometryOptions->readXml( layerNode.namedItem( QStringLiteral( "geometryOptions" ) ) );
2708
2709 if ( categories.testFlag( Forms ) )
2710 mEditFormConfig.readXml( layerNode, context );
2711
2712 if ( categories.testFlag( AttributeTable ) )
2713 {
2714 mAttributeTableConfig.readXml( layerNode );
2715 mConditionalStyles->readXml( layerNode, context );
2716 mStoredExpressionManager->readXml( layerNode );
2717 }
2718
2719 if ( categories.testFlag( CustomProperties ) )
2720 readCustomProperties( layerNode, QStringLiteral( "variable" ) );
2721
2722 QDomElement mapLayerNode = layerNode.toElement();
2723 if ( categories.testFlag( LayerConfiguration )
2724 && mapLayerNode.attribute( QStringLiteral( "readOnly" ), QStringLiteral( "0" ) ).toInt() == 1 )
2725 mReadOnly = true;
2726
2727 updateFields();
2728
2729 if ( categories.testFlag( Legend ) )
2730 {
2731 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Legend" ) );
2732
2733 const QDomElement legendElem = layerNode.firstChildElement( QStringLiteral( "legend" ) );
2734 if ( !legendElem.isNull() )
2735 {
2736 std::unique_ptr< QgsMapLayerLegend > legend( QgsMapLayerLegend::defaultVectorLegend( this ) );
2737 legend->readXml( legendElem, context );
2738 setLegend( legend.release() );
2739 mSetLegendFromStyle = true;
2740 }
2741 }
2742
2743 return true;
2744}
2745
2746bool QgsVectorLayer::readStyle( const QDomNode &node, QString &errorMessage,
2748{
2750
2751 bool result = true;
2752 emit readCustomSymbology( node.toElement(), errorMessage );
2753
2754 // we must try to restore a renderer if our geometry type is unknown
2755 // as this allows the renderer to be correctly restored even for layers
2756 // with broken sources
2757 if ( isSpatial() || mWkbType == Qgis::WkbType::Unknown )
2758 {
2759 // defer style changed signal until we've set the renderer, labeling, everything.
2760 // we don't want multiple signals!
2761 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
2762
2763 // try renderer v2 first
2764 if ( categories.testFlag( Symbology ) )
2765 {
2766 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Symbology" ) );
2767
2768 QDomElement rendererElement = node.firstChildElement( RENDERER_TAG_NAME );
2769 if ( !rendererElement.isNull() )
2770 {
2771 QgsFeatureRenderer *r = QgsFeatureRenderer::load( rendererElement, context );
2772 if ( r )
2773 {
2774 setRenderer( r );
2775 }
2776 else
2777 {
2778 result = false;
2779 }
2780 }
2781 // make sure layer has a renderer - if none exists, fallback to a default renderer
2782 if ( isSpatial() && !renderer() )
2783 {
2785 }
2786
2787 if ( mSelectionProperties )
2788 mSelectionProperties->readXml( node.toElement(), context );
2789 }
2790
2791 // read labeling definition
2792 if ( categories.testFlag( Labeling ) )
2793 {
2794 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Labeling" ) );
2795
2796 QDomElement labelingElement = node.firstChildElement( QStringLiteral( "labeling" ) );
2798 if ( labelingElement.isNull() ||
2799 ( labelingElement.attribute( QStringLiteral( "type" ) ) == QLatin1String( "simple" ) && labelingElement.firstChildElement( QStringLiteral( "settings" ) ).isNull() ) )
2800 {
2801 // make sure we have custom properties for labeling for 2.x projects
2802 // (custom properties should be already loaded when reading the whole layer from XML,
2803 // but when reading style, custom properties are not read)
2804 readCustomProperties( node, QStringLiteral( "labeling" ) );
2805
2806 // support for pre-QGIS 3 labeling configurations written in custom properties
2807 labeling = readLabelingFromCustomProperties();
2808 }
2809 else
2810 {
2811 labeling = QgsAbstractVectorLayerLabeling::create( labelingElement, context );
2812 }
2814
2815 if ( node.toElement().hasAttribute( QStringLiteral( "labelsEnabled" ) ) )
2816 mLabelsEnabled = node.toElement().attribute( QStringLiteral( "labelsEnabled" ) ).toInt();
2817 else
2818 mLabelsEnabled = true;
2819 }
2820
2821 if ( categories.testFlag( Symbology ) )
2822 {
2823 // get and set the blend mode if it exists
2824 QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
2825 if ( !blendModeNode.isNull() )
2826 {
2827 QDomElement e = blendModeNode.toElement();
2828 setBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
2829 }
2830
2831 // get and set the feature blend mode if it exists
2832 QDomNode featureBlendModeNode = node.namedItem( QStringLiteral( "featureBlendMode" ) );
2833 if ( !featureBlendModeNode.isNull() )
2834 {
2835 QDomElement e = featureBlendModeNode.toElement();
2836 setFeatureBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
2837 }
2838 }
2839
2840 // get and set the layer transparency and scale visibility if they exists
2841 if ( categories.testFlag( Rendering ) )
2842 {
2843 QDomNode layerTransparencyNode = node.namedItem( QStringLiteral( "layerTransparency" ) );
2844 if ( !layerTransparencyNode.isNull() )
2845 {
2846 QDomElement e = layerTransparencyNode.toElement();
2847 setOpacity( 1.0 - e.text().toInt() / 100.0 );
2848 }
2849 QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
2850 if ( !layerOpacityNode.isNull() )
2851 {
2852 QDomElement e = layerOpacityNode.toElement();
2853 setOpacity( e.text().toDouble() );
2854 }
2855
2856 const bool hasScaleBasedVisibiliy { node.attributes().namedItem( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).nodeValue() == '1' };
2857 setScaleBasedVisibility( hasScaleBasedVisibiliy );
2858 bool ok;
2859 const double maxScale { node.attributes().namedItem( QStringLiteral( "maxScale" ) ).nodeValue().toDouble( &ok ) };
2860 if ( ok )
2861 {
2862 setMaximumScale( maxScale );
2863 }
2864 const double minScale { node.attributes().namedItem( QStringLiteral( "minScale" ) ).nodeValue().toDouble( &ok ) };
2865 if ( ok )
2866 {
2867 setMinimumScale( minScale );
2868 }
2869
2870 QDomElement e = node.toElement();
2871
2872 // get the simplification drawing settings
2873 mSimplifyMethod.setSimplifyHints( static_cast< QgsVectorSimplifyMethod::SimplifyHints >( e.attribute( QStringLiteral( "simplifyDrawingHints" ), QStringLiteral( "1" ) ).toInt() ) );
2874 mSimplifyMethod.setSimplifyAlgorithm( static_cast< QgsVectorSimplifyMethod::SimplifyAlgorithm >( e.attribute( QStringLiteral( "simplifyAlgorithm" ), QStringLiteral( "0" ) ).toInt() ) );
2875 mSimplifyMethod.setThreshold( e.attribute( QStringLiteral( "simplifyDrawingTol" ), QStringLiteral( "1" ) ).toFloat() );
2876 mSimplifyMethod.setForceLocalOptimization( e.attribute( QStringLiteral( "simplifyLocal" ), QStringLiteral( "1" ) ).toInt() );
2877 mSimplifyMethod.setMaximumScale( e.attribute( QStringLiteral( "simplifyMaxScale" ), QStringLiteral( "1" ) ).toFloat() );
2878
2879 if ( mRenderer )
2880 mRenderer->setReferenceScale( e.attribute( QStringLiteral( "symbologyReferenceScale" ), QStringLiteral( "-1" ) ).toDouble() );
2881 }
2882
2883 //diagram renderer and diagram layer settings
2884 if ( categories.testFlag( Diagrams ) )
2885 {
2886 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Diagrams" ) );
2887
2888 delete mDiagramRenderer;
2889 mDiagramRenderer = nullptr;
2890 QDomElement singleCatDiagramElem = node.firstChildElement( QStringLiteral( "SingleCategoryDiagramRenderer" ) );
2891 if ( !singleCatDiagramElem.isNull() )
2892 {
2893 mDiagramRenderer = new QgsSingleCategoryDiagramRenderer();
2894 mDiagramRenderer->readXml( singleCatDiagramElem, context );
2895 }
2896 QDomElement linearDiagramElem = node.firstChildElement( QStringLiteral( "LinearlyInterpolatedDiagramRenderer" ) );
2897 if ( !linearDiagramElem.isNull() )
2898 {
2899 if ( linearDiagramElem.hasAttribute( QStringLiteral( "classificationAttribute" ) ) )
2900 {
2901 // fix project from before QGIS 3.0
2902 int idx = linearDiagramElem.attribute( QStringLiteral( "classificationAttribute" ) ).toInt();
2903 if ( idx >= 0 && idx < mFields.count() )
2904 linearDiagramElem.setAttribute( QStringLiteral( "classificationField" ), mFields.at( idx ).name() );
2905 }
2906
2907 mDiagramRenderer = new QgsLinearlyInterpolatedDiagramRenderer();
2908 mDiagramRenderer->readXml( linearDiagramElem, context );
2909 }
2910
2911 if ( mDiagramRenderer )
2912 {
2913 QDomElement diagramSettingsElem = node.firstChildElement( QStringLiteral( "DiagramLayerSettings" ) );
2914 if ( !diagramSettingsElem.isNull() )
2915 {
2916 bool oldXPos = diagramSettingsElem.hasAttribute( QStringLiteral( "xPosColumn" ) );
2917 bool oldYPos = diagramSettingsElem.hasAttribute( QStringLiteral( "yPosColumn" ) );
2918 bool oldShow = diagramSettingsElem.hasAttribute( QStringLiteral( "showColumn" ) );
2919 if ( oldXPos || oldYPos || oldShow )
2920 {
2921 // fix project from before QGIS 3.0
2923 if ( oldXPos )
2924 {
2925 int xPosColumn = diagramSettingsElem.attribute( QStringLiteral( "xPosColumn" ) ).toInt();
2926 if ( xPosColumn >= 0 && xPosColumn < mFields.count() )
2928 }
2929 if ( oldYPos )
2930 {
2931 int yPosColumn = diagramSettingsElem.attribute( QStringLiteral( "yPosColumn" ) ).toInt();
2932 if ( yPosColumn >= 0 && yPosColumn < mFields.count() )
2934 }
2935 if ( oldShow )
2936 {
2937 int showColumn = diagramSettingsElem.attribute( QStringLiteral( "showColumn" ) ).toInt();
2938 if ( showColumn >= 0 && showColumn < mFields.count() )
2939 ddp.setProperty( QgsDiagramLayerSettings::Property::Show, QgsProperty::fromField( mFields.at( showColumn ).name(), true ) );
2940 }
2941 QDomElement propertiesElem = diagramSettingsElem.ownerDocument().createElement( QStringLiteral( "properties" ) );
2943 {
2944 { static_cast< int >( QgsDiagramLayerSettings::Property::PositionX ), QgsPropertyDefinition( "positionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double ) },
2945 { static_cast< int >( QgsDiagramLayerSettings::Property::PositionY ), QgsPropertyDefinition( "positionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double ) },
2946 { static_cast< int >( QgsDiagramLayerSettings::Property::Show ), QgsPropertyDefinition( "show", QObject::tr( "Show diagram" ), QgsPropertyDefinition::Boolean ) },
2947 };
2948 ddp.writeXml( propertiesElem, defs );
2949 diagramSettingsElem.appendChild( propertiesElem );
2950 }
2951
2952 delete mDiagramLayerSettings;
2953 mDiagramLayerSettings = new QgsDiagramLayerSettings();
2954 mDiagramLayerSettings->readXml( diagramSettingsElem );
2955 }
2956 }
2957 }
2958 // end diagram
2959
2960 styleChangedSignalBlocker.release();
2962 }
2963 return result;
2964}
2965
2966
2967bool QgsVectorLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
2968 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
2969{
2971
2972 QDomElement layerElement = node.toElement();
2973 writeCommonStyle( layerElement, doc, context, categories );
2974
2975 ( void )writeStyle( node, doc, errorMessage, context, categories );
2976
2977 if ( categories.testFlag( GeometryOptions ) )
2978 mGeometryOptions->writeXml( node );
2979
2980 if ( categories.testFlag( Legend ) && legend() )
2981 {
2982 QDomElement legendElement = legend()->writeXml( doc, context );
2983 if ( !legendElement.isNull() )
2984 node.appendChild( legendElement );
2985 }
2986
2987 // Relation information for both referenced and referencing sides
2988 if ( categories.testFlag( Relations ) )
2989 {
2990 // Store referenced layers: relations where "this" is the child layer (the referencing part, that holds the FK)
2991 QDomElement referencedLayersElement = doc.createElement( QStringLiteral( "referencedLayers" ) );
2992 node.appendChild( referencedLayersElement );
2993
2994 const QList<QgsRelation> referencingRelations { QgsProject::instance()->relationManager()->referencingRelations( this ) };
2995 for ( const QgsRelation &rel : referencingRelations )
2996 {
2997 switch ( rel.type() )
2998 {
3000 QgsWeakRelation::writeXml( this, QgsWeakRelation::Referencing, rel, referencedLayersElement, doc );
3001 break;
3003 break;
3004 }
3005 }
3006
3007 // Store referencing layers: relations where "this" is the parent layer (the referenced part, that holds the FK)
3008 QDomElement referencingLayersElement = doc.createElement( QStringLiteral( "referencingLayers" ) );
3009 node.appendChild( referencedLayersElement );
3010
3011 const QList<QgsRelation> referencedRelations { QgsProject::instance()->relationManager()->referencedRelations( this ) };
3012 for ( const QgsRelation &rel : referencedRelations )
3013 {
3014 switch ( rel.type() )
3015 {
3017 QgsWeakRelation::writeXml( this, QgsWeakRelation::Referenced, rel, referencingLayersElement, doc );
3018 break;
3020 break;
3021 }
3022 }
3023 }
3024
3025 // write field configurations
3026 if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
3027 {
3028 QDomElement fieldConfigurationElement;
3029 // field configuration flag
3030 fieldConfigurationElement = doc.createElement( QStringLiteral( "fieldConfiguration" ) );
3031 node.appendChild( fieldConfigurationElement );
3032
3033 for ( const QgsField &field : std::as_const( mFields ) )
3034 {
3035 QDomElement fieldElement = doc.createElement( QStringLiteral( "field" ) );
3036 fieldElement.setAttribute( QStringLiteral( "name" ), field.name() );
3037 fieldConfigurationElement.appendChild( fieldElement );
3038
3039 if ( categories.testFlag( Fields ) )
3040 {
3041 fieldElement.setAttribute( QStringLiteral( "configurationFlags" ), qgsFlagValueToKeys( field.configurationFlags() ) );
3042 }
3043
3044 if ( categories.testFlag( Forms ) )
3045 {
3046 QgsEditorWidgetSetup widgetSetup = field.editorWidgetSetup();
3047
3048 // TODO : wrap this part in an if to only save if it was user-modified
3049 QDomElement editWidgetElement = doc.createElement( QStringLiteral( "editWidget" ) );
3050 fieldElement.appendChild( editWidgetElement );
3051 editWidgetElement.setAttribute( QStringLiteral( "type" ), field.editorWidgetSetup().type() );
3052 QDomElement editWidgetConfigElement = doc.createElement( QStringLiteral( "config" ) );
3053
3054 editWidgetConfigElement.appendChild( QgsXmlUtils::writeVariant( widgetSetup.config(), doc ) );
3055 editWidgetElement.appendChild( editWidgetConfigElement );
3056 // END TODO : wrap this part in an if to only save if it was user-modified
3057 }
3058 }
3059 }
3060
3061 if ( categories.testFlag( Fields ) )
3062 {
3063 //attribute aliases
3064 QDomElement aliasElem = doc.createElement( QStringLiteral( "aliases" ) );
3065 for ( const QgsField &field : std::as_const( mFields ) )
3066 {
3067 QDomElement aliasEntryElem = doc.createElement( QStringLiteral( "alias" ) );
3068 aliasEntryElem.setAttribute( QStringLiteral( "field" ), field.name() );
3069 aliasEntryElem.setAttribute( QStringLiteral( "index" ), mFields.indexFromName( field.name() ) );
3070 aliasEntryElem.setAttribute( QStringLiteral( "name" ), field.alias() );
3071 aliasElem.appendChild( aliasEntryElem );
3072 }
3073 node.appendChild( aliasElem );
3074
3075 //split policies
3076 {
3077 QDomElement splitPoliciesElement = doc.createElement( QStringLiteral( "splitPolicies" ) );
3078 for ( const QgsField &field : std::as_const( mFields ) )
3079 {
3080 QDomElement splitPolicyElem = doc.createElement( QStringLiteral( "policy" ) );
3081 splitPolicyElem.setAttribute( QStringLiteral( "field" ), field.name() );
3082 splitPolicyElem.setAttribute( QStringLiteral( "policy" ), qgsEnumValueToKey( field.splitPolicy() ) );
3083 splitPoliciesElement.appendChild( splitPolicyElem );
3084 }
3085 node.appendChild( splitPoliciesElement );
3086 }
3087
3088 //default expressions
3089 QDomElement defaultsElem = doc.createElement( QStringLiteral( "defaults" ) );
3090 for ( const QgsField &field : std::as_const( mFields ) )
3091 {
3092 QDomElement defaultElem = doc.createElement( QStringLiteral( "default" ) );
3093 defaultElem.setAttribute( QStringLiteral( "field" ), field.name() );
3094 defaultElem.setAttribute( QStringLiteral( "expression" ), field.defaultValueDefinition().expression() );
3095 defaultElem.setAttribute( QStringLiteral( "applyOnUpdate" ), field.defaultValueDefinition().applyOnUpdate() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
3096 defaultsElem.appendChild( defaultElem );
3097 }
3098 node.appendChild( defaultsElem );
3099
3100 // constraints
3101 QDomElement constraintsElem = doc.createElement( QStringLiteral( "constraints" ) );
3102 for ( const QgsField &field : std::as_const( mFields ) )
3103 {
3104 QDomElement constraintElem = doc.createElement( QStringLiteral( "constraint" ) );
3105 constraintElem.setAttribute( QStringLiteral( "field" ), field.name() );
3106 constraintElem.setAttribute( QStringLiteral( "constraints" ), field.constraints().constraints() );
3107 constraintElem.setAttribute( QStringLiteral( "unique_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintUnique ) );
3108 constraintElem.setAttribute( QStringLiteral( "notnull_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintNotNull ) );
3109 constraintElem.setAttribute( QStringLiteral( "exp_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintExpression ) );
3110 constraintsElem.appendChild( constraintElem );
3111 }
3112 node.appendChild( constraintsElem );
3113
3114 // constraint expressions
3115 QDomElement constraintExpressionsElem = doc.createElement( QStringLiteral( "constraintExpressions" ) );
3116 for ( const QgsField &field : std::as_const( mFields ) )
3117 {
3118 QDomElement constraintExpressionElem = doc.createElement( QStringLiteral( "constraint" ) );
3119 constraintExpressionElem.setAttribute( QStringLiteral( "field" ), field.name() );
3120 constraintExpressionElem.setAttribute( QStringLiteral( "exp" ), field.constraints().constraintExpression() );
3121 constraintExpressionElem.setAttribute( QStringLiteral( "desc" ), field.constraints().constraintDescription() );
3122 constraintExpressionsElem.appendChild( constraintExpressionElem );
3123 }
3124 node.appendChild( constraintExpressionsElem );
3125
3126 // save expression fields
3127 if ( !mExpressionFieldBuffer )
3128 {
3129 // can happen when saving style on a invalid layer
3131 dummy.writeXml( node, doc );
3132 }
3133 else
3134 {
3135 mExpressionFieldBuffer->writeXml( node, doc );
3136 }
3137 }
3138
3139 // add attribute actions
3140 if ( categories.testFlag( Actions ) )
3141 mActions->writeXml( node );
3142
3143 if ( categories.testFlag( AttributeTable ) )
3144 {
3145 mAttributeTableConfig.writeXml( node );
3146 mConditionalStyles->writeXml( node, doc, context );
3147 mStoredExpressionManager->writeXml( node );
3148 }
3149
3150 if ( categories.testFlag( Forms ) )
3151 mEditFormConfig.writeXml( node, context );
3152
3153 // save readonly state
3154 if ( categories.testFlag( LayerConfiguration ) )
3155 node.toElement().setAttribute( QStringLiteral( "readOnly" ), mReadOnly );
3156
3157 // save preview expression
3158 if ( categories.testFlag( LayerConfiguration ) )
3159 {
3160 QDomElement prevExpElem = doc.createElement( QStringLiteral( "previewExpression" ) );
3161 QDomText prevExpText = doc.createTextNode( mDisplayExpression );
3162 prevExpElem.appendChild( prevExpText );
3163 node.appendChild( prevExpElem );
3164 }
3165
3166 // save map tip
3167 if ( categories.testFlag( MapTips ) )
3168 {
3169 QDomElement mapTipElem = doc.createElement( QStringLiteral( "mapTip" ) );
3170 mapTipElem.setAttribute( QStringLiteral( "enabled" ), mapTipsEnabled() );
3171 QDomText mapTipText = doc.createTextNode( mMapTipTemplate );
3172 mapTipElem.appendChild( mapTipText );
3173 node.toElement().appendChild( mapTipElem );
3174 }
3175
3176 return true;
3177}
3178
3179bool QgsVectorLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
3180 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
3181{
3183
3184 QDomElement mapLayerNode = node.toElement();
3185
3186 emit writeCustomSymbology( mapLayerNode, doc, errorMessage );
3187
3188 // we must try to write the renderer if our geometry type is unknown
3189 // as this allows the renderer to be correctly restored even for layers
3190 // with broken sources
3191 if ( isSpatial() || mWkbType == Qgis::WkbType::Unknown )
3192 {
3193 if ( categories.testFlag( Symbology ) )
3194 {
3195 if ( mRenderer )
3196 {
3197 QDomElement rendererElement = mRenderer->save( doc, context );
3198 node.appendChild( rendererElement );
3199 }
3200 if ( mSelectionProperties )
3201 {
3202 mSelectionProperties->writeXml( mapLayerNode, doc, context );
3203 }
3204 }
3205
3206 if ( categories.testFlag( Labeling ) )
3207 {
3208 if ( mLabeling )
3209 {
3210 QDomElement labelingElement = mLabeling->save( doc, context );
3211 node.appendChild( labelingElement );
3212 }
3213 mapLayerNode.setAttribute( QStringLiteral( "labelsEnabled" ), mLabelsEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
3214 }
3215
3216 // save the simplification drawing settings
3217 if ( categories.testFlag( Rendering ) )
3218 {
3219 mapLayerNode.setAttribute( QStringLiteral( "simplifyDrawingHints" ), QString::number( mSimplifyMethod.simplifyHints() ) );
3220 mapLayerNode.setAttribute( QStringLiteral( "simplifyAlgorithm" ), QString::number( mSimplifyMethod.simplifyAlgorithm() ) );
3221 mapLayerNode.setAttribute( QStringLiteral( "simplifyDrawingTol" ), QString::number( mSimplifyMethod.threshold() ) );
3222 mapLayerNode.setAttribute( QStringLiteral( "simplifyLocal" ), mSimplifyMethod.forceLocalOptimization() ? 1 : 0 );
3223 mapLayerNode.setAttribute( QStringLiteral( "simplifyMaxScale" ), QString::number( mSimplifyMethod.maximumScale() ) );
3224 }
3225
3226 //save customproperties
3227 if ( categories.testFlag( CustomProperties ) )
3228 {
3229 writeCustomProperties( node, doc );
3230 }
3231
3232 if ( categories.testFlag( Symbology ) )
3233 {
3234 // add the blend mode field
3235 QDomElement blendModeElem = doc.createElement( QStringLiteral( "blendMode" ) );
3236 QDomText blendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( blendMode() ) ) ) );
3237 blendModeElem.appendChild( blendModeText );
3238 node.appendChild( blendModeElem );
3239
3240 // add the feature blend mode field
3241 QDomElement featureBlendModeElem = doc.createElement( QStringLiteral( "featureBlendMode" ) );
3242 QDomText featureBlendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( featureBlendMode() ) ) ) );
3243 featureBlendModeElem.appendChild( featureBlendModeText );
3244 node.appendChild( featureBlendModeElem );
3245 }
3246
3247 // add the layer opacity and scale visibility
3248 if ( categories.testFlag( Rendering ) )
3249 {
3250 QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
3251 QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
3252 layerOpacityElem.appendChild( layerOpacityText );
3253 node.appendChild( layerOpacityElem );
3254 mapLayerNode.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
3255 mapLayerNode.setAttribute( QStringLiteral( "maxScale" ), maximumScale() );
3256 mapLayerNode.setAttribute( QStringLiteral( "minScale" ), minimumScale() );
3257
3258 mapLayerNode.setAttribute( QStringLiteral( "symbologyReferenceScale" ), mRenderer ? mRenderer->referenceScale() : -1 );
3259 }
3260
3261 if ( categories.testFlag( Diagrams ) && mDiagramRenderer )
3262 {
3263 mDiagramRenderer->writeXml( mapLayerNode, doc, context );
3264 if ( mDiagramLayerSettings )
3265 mDiagramLayerSettings->writeXml( mapLayerNode, doc );
3266 }
3267 }
3268 return true;
3269}
3270
3271bool QgsVectorLayer::readSld( const QDomNode &node, QString &errorMessage )
3272{
3274
3275 // get the Name element
3276 QDomElement nameElem = node.firstChildElement( QStringLiteral( "Name" ) );
3277 if ( nameElem.isNull() )
3278 {
3279 errorMessage = QStringLiteral( "Warning: Name element not found within NamedLayer while it's required." );
3280 }
3281
3282 if ( isSpatial() )
3283 {
3284 QgsFeatureRenderer *r = QgsFeatureRenderer::loadSld( node, geometryType(), errorMessage );
3285 if ( !r )
3286 return false;
3287
3288 // defer style changed signal until we've set the renderer, labeling, everything.
3289 // we don't want multiple signals!
3290 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
3291
3292 setRenderer( r );
3293
3294 // labeling
3295 readSldLabeling( node );
3296
3297 styleChangedSignalBlocker.release();
3299 }
3300 return true;
3301}
3302
3303bool QgsVectorLayer::writeSld( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QVariantMap &props ) const
3304{
3306
3307 Q_UNUSED( errorMessage )
3308
3309 QVariantMap localProps = QVariantMap( props );
3311 {
3313 }
3314
3315 if ( isSpatial() )
3316 {
3317 // store the Name element
3318 QDomElement nameNode = doc.createElement( QStringLiteral( "se:Name" ) );
3319 nameNode.appendChild( doc.createTextNode( name() ) );
3320 node.appendChild( nameNode );
3321
3322 QDomElement userStyleElem = doc.createElement( QStringLiteral( "UserStyle" ) );
3323 node.appendChild( userStyleElem );
3324
3325 QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
3326 nameElem.appendChild( doc.createTextNode( name() ) );
3327
3328 userStyleElem.appendChild( nameElem );
3329
3330 QDomElement featureTypeStyleElem = doc.createElement( QStringLiteral( "se:FeatureTypeStyle" ) );
3331 userStyleElem.appendChild( featureTypeStyleElem );
3332
3333 mRenderer->toSld( doc, featureTypeStyleElem, localProps );
3334 if ( labelsEnabled() )
3335 {
3336 mLabeling->toSld( featureTypeStyleElem, localProps );
3337 }
3338 }
3339 return true;
3340}
3341
3342
3343bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, QgsGeometry &geom, bool skipDefaultValue )
3344{
3346
3347 if ( !mEditBuffer || !mDataProvider )
3348 {
3349 return false;
3350 }
3351
3352 if ( mGeometryOptions->isActive() )
3353 mGeometryOptions->apply( geom );
3354
3355 updateExtents();
3356
3357 bool result = mEditBuffer->changeGeometry( fid, geom );
3358
3359 if ( result )
3360 {
3361 updateExtents();
3362 if ( !skipDefaultValue && !mDefaultValueOnUpdateFields.isEmpty() )
3363 updateDefaultValues( fid );
3364 }
3365 return result;
3366}
3367
3368
3369bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue, bool skipDefaultValues )
3370{
3372
3373 bool result = false;
3374
3375 switch ( fields().fieldOrigin( field ) )
3376 {
3378 result = mJoinBuffer->changeAttributeValue( fid, field, newValue, oldValue );
3379 if ( result )
3380 emit attributeValueChanged( fid, field, newValue );
3381 break;
3382
3386 {
3387 if ( mEditBuffer && mDataProvider )
3388 result = mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
3389 break;
3390 }
3391
3393 break;
3394 }
3395
3396 if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
3397 updateDefaultValues( fid );
3398
3399 return result;
3400}
3401
3402bool QgsVectorLayer::changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues, bool skipDefaultValues )
3403{
3405
3406 bool result = true;
3407
3408 QgsAttributeMap newValuesJoin;
3409 QgsAttributeMap oldValuesJoin;
3410
3411 QgsAttributeMap newValuesNotJoin;
3412 QgsAttributeMap oldValuesNotJoin;
3413
3414 for ( auto it = newValues.constBegin(); it != newValues.constEnd(); ++it )
3415 {
3416 const int field = it.key();
3417 const QVariant newValue = it.value();
3418 QVariant oldValue;
3419
3420 if ( oldValues.contains( field ) )
3421 oldValue = oldValues[field];
3422
3423 switch ( fields().fieldOrigin( field ) )
3424 {
3426 newValuesJoin[field] = newValue;
3427 oldValuesJoin[field] = oldValue;
3428 break;
3429
3433 {
3434 newValuesNotJoin[field] = newValue;
3435 oldValuesNotJoin[field] = oldValue;
3436 break;
3437 }
3438
3440 break;
3441 }
3442 }
3443
3444 if ( ! newValuesJoin.isEmpty() && mJoinBuffer )
3445 {
3446 result = mJoinBuffer->changeAttributeValues( fid, newValuesJoin, oldValuesJoin );
3447 }
3448
3449 if ( ! newValuesNotJoin.isEmpty() )
3450 {
3451 if ( mEditBuffer && mDataProvider )
3452 result &= mEditBuffer->changeAttributeValues( fid, newValuesNotJoin, oldValues );
3453 else
3454 result = false;
3455 }
3456
3457 if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
3458 {
3459 updateDefaultValues( fid );
3460 }
3461
3462 return result;
3463}
3464
3466{
3468
3469 if ( !mEditBuffer || !mDataProvider )
3470 return false;
3471
3472 return mEditBuffer->addAttribute( field );
3473}
3474
3476{
3478
3479 if ( attIndex < 0 || attIndex >= fields().count() )
3480 return;
3481
3482 QString name = fields().at( attIndex ).name();
3483 mFields[ attIndex ].setAlias( QString() );
3484 if ( mAttributeAliasMap.contains( name ) )
3485 {
3486 mAttributeAliasMap.remove( name );
3487 updateFields();
3488 mEditFormConfig.setFields( mFields );
3489 emit layerModified();
3490 }
3491}
3492
3493bool QgsVectorLayer::renameAttribute( int index, const QString &newName )
3494{
3496
3497 if ( index < 0 || index >= fields().count() )
3498 return false;
3499
3500 switch ( mFields.fieldOrigin( index ) )
3501 {
3503 {
3504 if ( mExpressionFieldBuffer )
3505 {
3506 int oi = mFields.fieldOriginIndex( index );
3507 mExpressionFieldBuffer->renameExpression( oi, newName );
3508 updateFields();
3509 return true;
3510 }
3511 else
3512 {
3513 return false;
3514 }
3515 }
3516
3519
3520 if ( !mEditBuffer || !mDataProvider )
3521 return false;
3522
3523 return mEditBuffer->renameAttribute( index, newName );
3524
3527 return false;
3528
3529 }
3530
3531 return false; // avoid warning
3532}
3533
3534void QgsVectorLayer::setFieldAlias( int attIndex, const QString &aliasString )
3535{
3537
3538 if ( attIndex < 0 || attIndex >= fields().count() )
3539 return;
3540
3541 QString name = fields().at( attIndex ).name();
3542
3543 mAttributeAliasMap.insert( name, aliasString );
3544 mFields[ attIndex ].setAlias( aliasString );
3545 mEditFormConfig.setFields( mFields );
3546 emit layerModified(); // TODO[MD]: should have a different signal?
3547}
3548
3549QString QgsVectorLayer::attributeAlias( int index ) const
3550{
3552
3553 if ( index < 0 || index >= fields().count() )
3554 return QString();
3555
3556 return fields().at( index ).alias();
3557}
3558
3560{
3562
3563 if ( index >= 0 && index < mFields.count() )
3564 return mFields.at( index ).displayName();
3565 else
3566 return QString();
3567}
3568
3570{
3572
3573 return mAttributeAliasMap;
3574}
3575
3577{
3579
3580 if ( index < 0 || index >= fields().count() )
3581 return;
3582
3583 const QString name = fields().at( index ).name();
3584
3585 mAttributeSplitPolicy.insert( name, policy );
3586 mFields[ index ].setSplitPolicy( policy );
3587 mEditFormConfig.setFields( mFields );
3588 emit layerModified(); // TODO[MD]: should have a different signal?
3589}
3590
3592{
3594
3595 QSet<QString> excludeList;
3596 QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
3597 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
3598 {
3599 if ( flagsIt->testFlag( Qgis::FieldConfigurationFlag::HideFromWms ) )
3600 {
3601 excludeList << flagsIt.key();
3602 }
3603 }
3604 return excludeList;
3605}
3606
3607void QgsVectorLayer::setExcludeAttributesWms( const QSet<QString> &att )
3608{
3610
3611 QMap< QString, Qgis::FieldConfigurationFlags >::iterator flagsIt = mFieldConfigurationFlags.begin();
3612 for ( ; flagsIt != mFieldConfigurationFlags.end(); ++flagsIt )
3613 {
3614 flagsIt->setFlag( Qgis::FieldConfigurationFlag::HideFromWms, att.contains( flagsIt.key() ) );
3615 }
3616 updateFields();
3617}
3618
3620{
3622
3623 QSet<QString> excludeList;
3624 QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
3625 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
3626 {
3627 if ( flagsIt->testFlag( Qgis::FieldConfigurationFlag::HideFromWfs ) )
3628 {
3629 excludeList << flagsIt.key();
3630 }
3631 }
3632 return excludeList;
3633}
3634
3635void QgsVectorLayer::setExcludeAttributesWfs( const QSet<QString> &att )
3636{
3638
3639 QMap< QString, Qgis::FieldConfigurationFlags >::iterator flagsIt = mFieldConfigurationFlags.begin();
3640 for ( ; flagsIt != mFieldConfigurationFlags.end(); ++flagsIt )
3641 {
3642 flagsIt->setFlag( Qgis::FieldConfigurationFlag::HideFromWfs, att.contains( flagsIt.key() ) );
3643 }
3644 updateFields();
3645}
3646
3648{
3650
3651 if ( index < 0 || index >= fields().count() )
3652 return false;
3653
3654 if ( mFields.fieldOrigin( index ) == QgsFields::OriginExpression )
3655 {
3656 removeExpressionField( index );
3657 return true;
3658 }
3659
3660 if ( !mEditBuffer || !mDataProvider )
3661 return false;
3662
3663 return mEditBuffer->deleteAttribute( index );
3664}
3665
3666bool QgsVectorLayer::deleteAttributes( const QList<int> &attrs )
3667{
3669
3670 bool deleted = false;
3671
3672 // Remove multiple occurrences of same attribute
3673 QList<int> attrList = qgis::setToList( qgis::listToSet( attrs ) );
3674
3675 std::sort( attrList.begin(), attrList.end(), std::greater<int>() );
3676
3677 for ( int attr : std::as_const( attrList ) )
3678 {
3679 if ( deleteAttribute( attr ) )
3680 {
3681 deleted = true;
3682 }
3683 }
3684
3685 return deleted;
3686}
3687
3688bool QgsVectorLayer::deleteFeatureCascade( QgsFeatureId fid, QgsVectorLayer::DeleteContext *context )
3689{
3691
3692 if ( !mEditBuffer )
3693 return false;
3694
3695 if ( context && context->cascade )
3696 {
3697 const QList<QgsRelation> relations = context->project->relationManager()->referencedRelations( this );
3698 const bool hasRelationsOrJoins = !relations.empty() || mJoinBuffer->containsJoins();
3699 if ( hasRelationsOrJoins )
3700 {
3701 if ( context->mHandledFeatures.contains( this ) )
3702 {
3703 QgsFeatureIds &handledFeatureIds = context->mHandledFeatures[ this ];
3704 if ( handledFeatureIds.contains( fid ) )
3705 {
3706 // avoid endless recursion
3707 return false;
3708 }
3709 else
3710 {
3711 // add feature id
3712 handledFeatureIds << fid;
3713 }
3714 }
3715 else
3716 {
3717 // add layer and feature id
3718 context->mHandledFeatures.insert( this, QgsFeatureIds() << fid );
3719 }
3720
3721 for ( const QgsRelation &relation : relations )
3722 {
3723 //check if composition (and not association)
3724 switch ( relation.strength() )
3725 {
3727 {
3728 //get features connected over this relation
3729 QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( getFeature( fid ) );
3730 QgsFeatureIds childFeatureIds;
3731 QgsFeature childFeature;
3732 while ( relatedFeaturesIt.nextFeature( childFeature ) )
3733 {
3734 childFeatureIds.insert( childFeature.id() );
3735 }
3736 if ( childFeatureIds.count() > 0 )
3737 {
3738 relation.referencingLayer()->startEditing();
3739 relation.referencingLayer()->deleteFeatures( childFeatureIds, context );
3740 }
3741 break;
3742 }
3743
3745 break;
3746 }
3747 }
3748 }
3749 }
3750
3751 if ( mJoinBuffer->containsJoins() )
3752 mJoinBuffer->deleteFeature( fid, context );
3753
3754 bool res = mEditBuffer->deleteFeature( fid );
3755
3756 return res;
3757}
3758
3760{
3762
3763 if ( !mEditBuffer )
3764 return false;
3765
3766 bool res = deleteFeatureCascade( fid, context );
3767
3768 if ( res )
3769 {
3770 updateExtents();
3771 }
3772
3773 return res;
3774}
3775
3777{
3779
3780 bool res = true;
3781
3782 if ( ( context && context->cascade ) || mJoinBuffer->containsJoins() )
3783 {
3784 // should ideally be "deleteFeaturesCascade" for performance!
3785 for ( QgsFeatureId fid : fids )
3786 res = deleteFeatureCascade( fid, context ) && res;
3787 }
3788 else
3789 {
3790 res = mEditBuffer && mEditBuffer->deleteFeatures( fids );
3791 }
3792
3793 if ( res )
3794 {
3795 mSelectedFeatureIds.subtract( fids ); // remove it from selection
3796 updateExtents();
3797 }
3798
3799 return res;
3800}
3801
3803{
3804 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
3806
3807 return mFields;
3808}
3809
3811{
3813
3814 QgsAttributeList pkAttributesList;
3815 if ( !mDataProvider )
3816 return pkAttributesList;
3817
3818 QgsAttributeList providerIndexes = mDataProvider->pkAttributeIndexes();
3819 for ( int i = 0; i < mFields.count(); ++i )
3820 {
3821 if ( mFields.fieldOrigin( i ) == QgsFields::OriginProvider &&
3822 providerIndexes.contains( mFields.fieldOriginIndex( i ) ) )
3823 pkAttributesList << i;
3824 }
3825
3826 return pkAttributesList;
3827}
3828
3830{
3832
3833 if ( !mDataProvider )
3834 return static_cast< long long >( Qgis::FeatureCountState::UnknownCount );
3835 return mDataProvider->featureCount() +
3836 ( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->addedFeatures().size() - mEditBuffer->deletedFeatureIds().size() : 0 );
3837}
3838
3840{
3842
3843 const QgsFeatureIds deletedFeatures( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->deletedFeatureIds() : QgsFeatureIds() );
3844 const QgsFeatureMap addedFeatures( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->addedFeatures() : QgsFeatureMap() );
3845
3846 if ( mEditBuffer && !deletedFeatures.empty() )
3847 {
3848 if ( addedFeatures.size() > deletedFeatures.size() )
3850 else
3852 }
3853
3854 if ( ( !mEditBuffer || addedFeatures.empty() ) && mDataProvider && mDataProvider->empty() )
3856 else
3858}
3859
3860bool QgsVectorLayer::commitChanges( bool stopEditing )
3861{
3863
3864 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
3865 return project()->commitChanges( mCommitErrors, stopEditing, this );
3866
3867 mCommitErrors.clear();
3868
3869 if ( !mDataProvider )
3870 {
3871 mCommitErrors << tr( "ERROR: no provider" );
3872 return false;
3873 }
3874
3875 if ( !mEditBuffer )
3876 {
3877 mCommitErrors << tr( "ERROR: layer not editable" );
3878 return false;
3879 }
3880
3881 emit beforeCommitChanges( stopEditing );
3882
3883 if ( !mAllowCommit )
3884 return false;
3885
3886 mCommitChangesActive = true;
3887
3888 bool success = false;
3889 if ( mEditBuffer->editBufferGroup() )
3890 success = mEditBuffer->editBufferGroup()->commitChanges( mCommitErrors, stopEditing );
3891 else
3892 success = mEditBuffer->commitChanges( mCommitErrors );
3893
3894 mCommitChangesActive = false;
3895
3896 if ( !mDeletedFids.empty() )
3897 {
3898 emit featuresDeleted( mDeletedFids );
3899 mDeletedFids.clear();
3900 }
3901
3902 if ( success )
3903 {
3904 if ( stopEditing )
3905 {
3906 clearEditBuffer();
3907 }
3908 undoStack()->clear();
3909 emit afterCommitChanges();
3910 if ( stopEditing )
3911 emit editingStopped();
3912 }
3913 else
3914 {
3915 QgsMessageLog::logMessage( tr( "Commit errors:\n %1" ).arg( mCommitErrors.join( QLatin1String( "\n " ) ) ) );
3916 }
3917
3918 updateFields();
3919
3920 mDataProvider->updateExtents();
3921 mDataProvider->leaveUpdateMode();
3922
3923 // This second call is required because OGR provider with JSON
3924 // driver might have changed fields order after the call to
3925 // leaveUpdateMode
3926 if ( mFields.names() != mDataProvider->fields().names() )
3927 {
3928 updateFields();
3929 }
3930
3932
3933 return success;
3934}
3935
3937{
3939
3940 return mCommitErrors;
3941}
3942
3943bool QgsVectorLayer::rollBack( bool deleteBuffer )
3944{
3946
3947 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
3948 return project()->rollBack( mCommitErrors, deleteBuffer, this );
3949
3950 if ( !mEditBuffer )
3951 {
3952 return false;
3953 }
3954
3955 if ( !mDataProvider )
3956 {
3957 mCommitErrors << tr( "ERROR: no provider" );
3958 return false;
3959 }
3960
3961 bool rollbackExtent = !mDataProvider->transaction() && ( !mEditBuffer->deletedFeatureIds().isEmpty() ||
3962 !mEditBuffer->addedFeatures().isEmpty() ||
3963 !mEditBuffer->changedGeometries().isEmpty() );
3964
3965 emit beforeRollBack();
3966
3967 mEditBuffer->rollBack();
3968
3969 emit afterRollBack();
3970
3971 if ( isModified() )
3972 {
3973 // new undo stack roll back method
3974 // old method of calling every undo could cause many canvas refreshes
3975 undoStack()->setIndex( 0 );
3976 }
3977
3978 updateFields();
3979
3980 if ( deleteBuffer )
3981 {
3982 delete mEditBuffer;
3983 mEditBuffer = nullptr;
3984 undoStack()->clear();
3985 }
3986 emit editingStopped();
3987
3988 if ( rollbackExtent )
3989 updateExtents();
3990
3991 mDataProvider->leaveUpdateMode();
3992
3994 return true;
3995}
3996
3998{
4000
4001 return mSelectedFeatureIds.size();
4002}
4003
4005{
4006 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
4008
4009 return mSelectedFeatureIds;
4010}
4011
4013{
4015
4016 QgsFeatureList features;
4017 features.reserve( mSelectedFeatureIds.count() );
4018 QgsFeature f;
4019
4021
4022 while ( it.nextFeature( f ) )
4023 {
4024 features.push_back( f );
4025 }
4026
4027 return features;
4028}
4029
4031{
4033
4034 if ( mSelectedFeatureIds.isEmpty() )
4035 return QgsFeatureIterator();
4036
4039
4040 if ( mSelectedFeatureIds.count() == 1 )
4041 request.setFilterFid( *mSelectedFeatureIds.constBegin() );
4042 else
4043 request.setFilterFids( mSelectedFeatureIds );
4044
4045 return getFeatures( request );
4046}
4047
4049{
4051
4052 if ( !mEditBuffer || !mDataProvider )
4053 return false;
4054
4055 if ( mGeometryOptions->isActive() )
4056 {
4057 for ( auto feature = features.begin(); feature != features.end(); ++feature )
4058 {
4059 QgsGeometry geom = feature->geometry();
4060 mGeometryOptions->apply( geom );
4061 feature->setGeometry( geom );
4062 }
4063 }
4064
4065 bool res = mEditBuffer->addFeatures( features );
4066 updateExtents();
4067
4068 if ( res && mJoinBuffer->containsJoins() )
4069 res = mJoinBuffer->addFeatures( features );
4070
4071 return res;
4072}
4073
4075{
4077
4078 // if layer is not spatial, it has not CRS!
4079 setCrs( ( isSpatial() && mDataProvider ) ? mDataProvider->crs() : QgsCoordinateReferenceSystem() );
4080}
4081
4083{
4085
4087 if ( exp.isField() )
4088 {
4089 return static_cast<const QgsExpressionNodeColumnRef *>( exp.rootNode() )->name();
4090 }
4091
4092 return QString();
4093}
4094
4095void QgsVectorLayer::setDisplayExpression( const QString &displayExpression )
4096{
4098
4099 if ( mDisplayExpression == displayExpression )
4100 return;
4101
4102 mDisplayExpression = displayExpression;
4104}
4105
4107{
4109
4110 if ( !mDisplayExpression.isEmpty() || mFields.isEmpty() )
4111 {
4112 return mDisplayExpression;
4113 }
4114 else
4115 {
4116 const QString candidateName = QgsVectorLayerUtils::guessFriendlyIdentifierField( mFields );
4117 if ( !candidateName.isEmpty() )
4118 {
4119 return QgsExpression::quotedColumnRef( candidateName );
4120 }
4121 else
4122 {
4123 return QString();
4124 }
4125 }
4126}
4127
4129{
4131
4132 // display expressions are used as a fallback when no explicit map tip template is set
4133 return mapTipsEnabled() && ( !mapTipTemplate().isEmpty() || !displayExpression().isEmpty() );
4134}
4135
4137{
4139
4140 return ( mEditBuffer && mDataProvider );
4141}
4142
4144{
4145 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
4147
4150}
4151
4152bool QgsVectorLayer::isReadOnly() const
4153{
4155
4156 return mDataSourceReadOnly || mReadOnly;
4157}
4158
4159bool QgsVectorLayer::setReadOnly( bool readonly )
4160{
4162
4163 // exit if the layer is in editing mode
4164 if ( readonly && mEditBuffer )
4165 return false;
4166
4167 // exit if the data source is in read-only mode
4168 if ( !readonly && mDataSourceReadOnly )
4169 return false;
4170
4171 mReadOnly = readonly;
4172 emit readOnlyChanged();
4173 return true;
4174}
4175
4177{
4179
4180 if ( ! mDataProvider )
4181 return false;
4182
4183 if ( mDataSourceReadOnly )
4184 return false;
4185
4186 return mDataProvider->capabilities() & QgsVectorDataProvider::EditingCapabilities && ! mReadOnly;
4187}
4188
4190{
4192
4193 emit beforeModifiedCheck();
4194 return mEditBuffer && mEditBuffer->isModified();
4195}
4196
4197bool QgsVectorLayer::isAuxiliaryField( int index, int &srcIndex ) const
4198{
4200
4201 bool auxiliaryField = false;
4202 srcIndex = -1;
4203
4204 if ( !auxiliaryLayer() )
4205 return auxiliaryField;
4206
4207 if ( index >= 0 && fields().fieldOrigin( index ) == QgsFields::OriginJoin )
4208 {
4209 const QgsVectorLayerJoinInfo *info = mJoinBuffer->joinForFieldIndex( index, fields(), srcIndex );
4210
4211 if ( info && info->joinLayerId() == auxiliaryLayer()->id() )
4212 auxiliaryField = true;
4213 }
4214
4215 return auxiliaryField;
4216}
4217
4219{
4221
4222 // we must allow setting a renderer if our geometry type is unknown
4223 // as this allows the renderer to be correctly set even for layers
4224 // with broken sources
4225 // (note that we allow REMOVING the renderer for non-spatial layers,
4226 // e.g. to permit removing the renderer when the layer changes from
4227 // a spatial layer to a non-spatial one)
4228 if ( r && !isSpatial() && mWkbType != Qgis::WkbType::Unknown )
4229 return;
4230
4231 if ( r != mRenderer )
4232 {
4233 delete mRenderer;
4234 mRenderer = r;
4235 mSymbolFeatureCounted = false;
4236 mSymbolFeatureCountMap.clear();
4237 mSymbolFeatureIdMap.clear();
4238
4239 if ( mRenderer )
4240 {
4241 const double refreshRate = QgsSymbolLayerUtils::rendererFrameRate( mRenderer );
4242 if ( refreshRate <= 0 )
4243 {
4244 mRefreshRendererTimer->stop();
4245 mRefreshRendererTimer->setInterval( 0 );
4246 }
4247 else
4248 {
4249 mRefreshRendererTimer->setInterval( 1000 / refreshRate );
4250 mRefreshRendererTimer->start();
4251 }
4252 }
4253
4254 emit rendererChanged();
4256 }
4257}
4258
4260{
4262
4263 if ( generator )
4264 {
4265 mRendererGenerators << generator;
4266 }
4267}
4268
4270{
4272
4273 for ( int i = mRendererGenerators.count() - 1; i >= 0; --i )
4274 {
4275 if ( mRendererGenerators.at( i )->id() == id )
4276 {
4277 delete mRendererGenerators.at( i );
4278 mRendererGenerators.removeAt( i );
4279 }
4280 }
4281}
4282
4283QList<const QgsFeatureRendererGenerator *> QgsVectorLayer::featureRendererGenerators() const
4284{
4285 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
4287
4288 QList< const QgsFeatureRendererGenerator * > res;
4289 for ( const QgsFeatureRendererGenerator *generator : mRendererGenerators )
4290 res << generator;
4291 return res;
4292}
4293
4294void QgsVectorLayer::beginEditCommand( const QString &text )
4295{
4297
4298 if ( !mDataProvider )
4299 {
4300 return;
4301 }
4302 if ( mDataProvider->transaction() )
4303 {
4304 QString ignoredError;
4305 mDataProvider->transaction()->createSavepoint( ignoredError );
4306 }
4307 undoStack()->beginMacro( text );
4308 mEditCommandActive = true;
4309 emit editCommandStarted( text );
4310}
4311
4313{
4315
4316 if ( !mDataProvider )
4317 {
4318 return;
4319 }
4320 undoStack()->endMacro();
4321 mEditCommandActive = false;
4322 if ( !mDeletedFids.isEmpty() )
4323 {
4324 if ( selectedFeatureCount() > 0 )
4325 {
4326 mSelectedFeatureIds.subtract( mDeletedFids );
4327 }
4328 emit featuresDeleted( mDeletedFids );
4329 mDeletedFids.clear();
4330 }
4331 emit editCommandEnded();
4332}
4333
4335{
4337
4338 if ( !mDataProvider )
4339 {
4340 return;
4341 }
4342 undoStack()->endMacro();
4343 undoStack()->undo();
4344
4345 // it's not directly possible to pop the last command off the stack (the destroyed one)
4346 // and delete, so we add a dummy obsolete command to force this to occur.
4347 // Pushing the new command deletes the destroyed one, and since the new
4348 // command is obsolete it's automatically deleted by the undo stack.
4349 std::unique_ptr< QUndoCommand > command = std::make_unique< QUndoCommand >();
4350 command->setObsolete( true );
4351 undoStack()->push( command.release() );
4352
4353 mEditCommandActive = false;
4354 mDeletedFids.clear();
4355 emit editCommandDestroyed();
4356}
4357
4359{
4361
4362 return mJoinBuffer->addJoin( joinInfo );
4363}
4364
4365bool QgsVectorLayer::removeJoin( const QString &joinLayerId )
4366{
4368
4369 return mJoinBuffer->removeJoin( joinLayerId );
4370}
4371
4372const QList< QgsVectorLayerJoinInfo > QgsVectorLayer::vectorJoins() const
4373{
4375
4376 return mJoinBuffer->vectorJoins();
4377}
4378
4379int QgsVectorLayer::addExpressionField( const QString &exp, const QgsField &fld )
4380{
4382
4383 emit beforeAddingExpressionField( fld.name() );
4384 mExpressionFieldBuffer->addExpression( exp, fld );
4385 updateFields();
4386 int idx = mFields.indexFromName( fld.name() );
4387 emit attributeAdded( idx );
4388 return idx;
4389}
4390
4392{
4394
4395 emit beforeRemovingExpressionField( index );
4396 int oi = mFields.fieldOriginIndex( index );
4397 mExpressionFieldBuffer->removeExpression( oi );
4398 updateFields();
4399 emit attributeDeleted( index );
4400}
4401
4402QString QgsVectorLayer::expressionField( int index ) const
4403{
4405
4406 if ( mFields.fieldOrigin( index ) != QgsFields::OriginExpression )
4407 return QString();
4408
4409 int oi = mFields.fieldOriginIndex( index );
4410 if ( oi < 0 || oi >= mExpressionFieldBuffer->expressions().size() )
4411 return QString();
4412
4413 return mExpressionFieldBuffer->expressions().at( oi ).cachedExpression.expression();
4414}
4415
4416void QgsVectorLayer::updateExpressionField( int index, const QString &exp )
4417{
4419
4420 int oi = mFields.fieldOriginIndex( index );
4421 mExpressionFieldBuffer->updateExpression( oi, exp );
4422}
4423
4425{
4426 // non fatal for now -- the QgsVirtualLayerTask class is not thread safe and calls this
4428
4429 if ( !mDataProvider )
4430 return;
4431
4432 QgsFields oldFields = mFields;
4433
4434 mFields = mDataProvider->fields();
4435
4436 // added / removed fields
4437 if ( mEditBuffer )
4438 mEditBuffer->updateFields( mFields );
4439
4440 // joined fields
4441 if ( mJoinBuffer->containsJoins() )
4442 mJoinBuffer->updateFields( mFields );
4443
4444 if ( mExpressionFieldBuffer )
4445 mExpressionFieldBuffer->updateFields( mFields );
4446
4447 // set aliases and default values
4448 for ( auto aliasIt = mAttributeAliasMap.constBegin(); aliasIt != mAttributeAliasMap.constEnd(); ++aliasIt )
4449 {
4450 int index = mFields.lookupField( aliasIt.key() );
4451 if ( index < 0 )
4452 continue;
4453
4454 mFields[ index ].setAlias( aliasIt.value() );
4455 }
4456
4457 for ( auto splitPolicyIt = mAttributeSplitPolicy.constBegin(); splitPolicyIt != mAttributeSplitPolicy.constEnd(); ++splitPolicyIt )
4458 {
4459 int index = mFields.lookupField( splitPolicyIt.key() );
4460 if ( index < 0 )
4461 continue;
4462
4463 mFields[ index ].setSplitPolicy( splitPolicyIt.value() );
4464 }
4465
4466 // Update configuration flags
4467 QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
4468 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
4469 {
4470 int index = mFields.lookupField( flagsIt.key() );
4471 if ( index < 0 )
4472 continue;
4473
4474 mFields[index].setConfigurationFlags( flagsIt.value() );
4475 }
4476
4477 // Update default values
4478 mDefaultValueOnUpdateFields.clear();
4479 QMap< QString, QgsDefaultValue >::const_iterator defaultIt = mDefaultExpressionMap.constBegin();
4480 for ( ; defaultIt != mDefaultExpressionMap.constEnd(); ++defaultIt )
4481 {
4482 int index = mFields.lookupField( defaultIt.key() );
4483 if ( index < 0 )
4484 continue;
4485
4486 mFields[ index ].setDefaultValueDefinition( defaultIt.value() );
4487 if ( defaultIt.value().applyOnUpdate() )
4488 mDefaultValueOnUpdateFields.insert( index );
4489 }
4490
4491 QMap< QString, QgsFieldConstraints::Constraints >::const_iterator constraintIt = mFieldConstraints.constBegin();
4492 for ( ; constraintIt != mFieldConstraints.constEnd(); ++constraintIt )
4493 {
4494 int index = mFields.lookupField( constraintIt.key() );
4495 if ( index < 0 )
4496 continue;
4497
4498 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4499
4500 // always keep provider constraints intact
4501 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintNotNull ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintNotNull ) )
4503 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintUnique ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintUnique ) )
4505 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintExpression ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintExpression ) )
4507 mFields[ index ].setConstraints( constraints );
4508 }
4509
4510 QMap< QString, QPair< QString, QString > >::const_iterator constraintExpIt = mFieldConstraintExpressions.constBegin();
4511 for ( ; constraintExpIt != mFieldConstraintExpressions.constEnd(); ++constraintExpIt )
4512 {
4513 int index = mFields.lookupField( constraintExpIt.key() );
4514 if ( index < 0 )
4515 continue;
4516
4517 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4518
4519 // always keep provider constraints intact
4521 continue;
4522
4523 constraints.setConstraintExpression( constraintExpIt.value().first, constraintExpIt.value().second );
4524 mFields[ index ].setConstraints( constraints );
4525 }
4526
4527 QMap< QPair< QString, QgsFieldConstraints::Constraint >, QgsFieldConstraints::ConstraintStrength >::const_iterator constraintStrengthIt = mFieldConstraintStrength.constBegin();
4528 for ( ; constraintStrengthIt != mFieldConstraintStrength.constEnd(); ++constraintStrengthIt )
4529 {
4530 int index = mFields.lookupField( constraintStrengthIt.key().first );
4531 if ( index < 0 )
4532 continue;
4533
4534 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4535
4536 // always keep provider constraints intact
4538 continue;
4539
4540 constraints.setConstraintStrength( constraintStrengthIt.key().second, constraintStrengthIt.value() );
4541 mFields[ index ].setConstraints( constraints );
4542 }
4543
4544 auto fieldWidgetIterator = mFieldWidgetSetups.constBegin();
4545 for ( ; fieldWidgetIterator != mFieldWidgetSetups.constEnd(); ++ fieldWidgetIterator )
4546 {
4547 int index = mFields.indexOf( fieldWidgetIterator.key() );
4548 if ( index < 0 )
4549 continue;
4550
4551 mFields[index].setEditorWidgetSetup( fieldWidgetIterator.value() );
4552 }
4553
4554 if ( oldFields != mFields )
4555 {
4556 emit updatedFields();
4557 mEditFormConfig.setFields( mFields );
4558 }
4559
4560}
4561
4562QVariant QgsVectorLayer::defaultValue( int index, const QgsFeature &feature, QgsExpressionContext *context ) const
4563{
4565
4566 if ( index < 0 || index >= mFields.count() || !mDataProvider )
4567 return QVariant();
4568
4569 QString expression = mFields.at( index ).defaultValueDefinition().expression();
4570 if ( expression.isEmpty() )
4571 return mDataProvider->defaultValue( index );
4572
4573 QgsExpressionContext *evalContext = context;
4574 std::unique_ptr< QgsExpressionContext > tempContext;
4575 if ( !evalContext )
4576 {
4577 // no context passed, so we create a default one
4579 evalContext = tempContext.get();
4580 }
4581
4582 if ( feature.isValid() )
4583 {
4585 featScope->setFeature( feature );
4586 featScope->setFields( feature.fields() );
4587 evalContext->appendScope( featScope );
4588 }
4589
4590 QVariant val;
4591 QgsExpression exp( expression );
4592 exp.prepare( evalContext );
4593 if ( exp.hasEvalError() )
4594 {
4595 QgsLogger::warning( "Error evaluating default value: " + exp.evalErrorString() );
4596 }
4597 else
4598 {
4599 val = exp.evaluate( evalContext );
4600 }
4601
4602 if ( feature.isValid() )
4603 {
4604 delete evalContext->popScope();
4605 }
4606
4607 return val;
4608}
4609
4611{
4613
4614 if ( index < 0 || index >= mFields.count() )
4615 return;
4616
4617 if ( definition.isValid() )
4618 {
4619 mDefaultExpressionMap.insert( mFields.at( index ).name(), definition );
4620 }
4621 else
4622 {
4623 mDefaultExpressionMap.remove( mFields.at( index ).name() );
4624 }
4625 updateFields();
4626}
4627
4629{
4631
4632 if ( index < 0 || index >= mFields.count() )
4633 return QgsDefaultValue();
4634 else
4635 return mFields.at( index ).defaultValueDefinition();
4636}
4637
4638QSet<QVariant> QgsVectorLayer::uniqueValues( int index, int limit ) const
4639{
4641
4642 QSet<QVariant> uniqueValues;
4643 if ( !mDataProvider )
4644 {
4645 return uniqueValues;
4646 }
4647
4648 QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
4649 switch ( origin )
4650 {
4652 return uniqueValues;
4653
4654 case QgsFields::OriginProvider: //a provider field
4655 {
4656 uniqueValues = mDataProvider->uniqueValues( index, limit );
4657
4658 if ( mEditBuffer && ! mDataProvider->transaction() )
4659 {
4660 QSet<QString> vals;
4661 const auto constUniqueValues = uniqueValues;
4662 for ( const QVariant &v : constUniqueValues )
4663 {
4664 vals << v.toString();
4665 }
4666
4667 QgsFeatureMap added = mEditBuffer->addedFeatures();
4668 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4669 while ( addedIt.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
4670 {
4671 addedIt.next();
4672 QVariant v = addedIt.value().attribute( index );
4673 if ( v.isValid() )
4674 {
4675 QString vs = v.toString();
4676 if ( !vals.contains( vs ) )
4677 {
4678 vals << vs;
4679 uniqueValues << v;
4680 }
4681 }
4682 }
4683
4684 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4685 while ( it.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
4686 {
4687 it.next();
4688 QVariant v = it.value().value( index );
4689 if ( v.isValid() )
4690 {
4691 QString vs = v.toString();
4692 if ( !vals.contains( vs ) )
4693 {
4694 vals << vs;
4695 uniqueValues << v;
4696 }
4697 }
4698 }
4699 }
4700
4701 return uniqueValues;
4702 }
4703
4705 // the layer is editable, but in certain cases it can still be avoided going through all features
4706 if ( mDataProvider->transaction() || (
4707 mEditBuffer->deletedFeatureIds().isEmpty() &&
4708 mEditBuffer->addedFeatures().isEmpty() &&
4709 !mEditBuffer->deletedAttributeIds().contains( index ) &&
4710 mEditBuffer->changedAttributeValues().isEmpty() ) )
4711 {
4712 uniqueValues = mDataProvider->uniqueValues( index, limit );
4713 return uniqueValues;
4714 }
4715 [[fallthrough]];
4716 //we need to go through each feature
4719 {
4720 QgsAttributeList attList;
4721 attList << index;
4722
4725 .setSubsetOfAttributes( attList ) );
4726
4727 QgsFeature f;
4728 QVariant currentValue;
4729 QHash<QString, QVariant> val;
4730 while ( fit.nextFeature( f ) )
4731 {
4732 currentValue = f.attribute( index );
4733 val.insert( currentValue.toString(), currentValue );
4734 if ( limit >= 0 && val.size() >= limit )
4735 {
4736 break;
4737 }
4738 }
4739
4740 return qgis::listToSet( val.values() );
4741 }
4742 }
4743
4744 Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
4745 return uniqueValues;
4746}
4747
4748QStringList QgsVectorLayer::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
4749{
4751
4752 QStringList results;
4753 if ( !mDataProvider )
4754 {
4755 return results;
4756 }
4757
4758 QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
4759 switch ( origin )
4760 {
4762 return results;
4763
4764 case QgsFields::OriginProvider: //a provider field
4765 {
4766 results = mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
4767
4768 if ( mEditBuffer && ! mDataProvider->transaction() )
4769 {
4770 QgsFeatureMap added = mEditBuffer->addedFeatures();
4771 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4772 while ( addedIt.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
4773 {
4774 addedIt.next();
4775 QVariant v = addedIt.value().attribute( index );
4776 if ( v.isValid() )
4777 {
4778 QString vs = v.toString();
4779 if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
4780 {
4781 results << vs;
4782 }
4783 }
4784 }
4785
4786 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4787 while ( it.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
4788 {
4789 it.next();
4790 QVariant v = it.value().value( index );
4791 if ( v.isValid() )
4792 {
4793 QString vs = v.toString();
4794 if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
4795 {
4796 results << vs;
4797 }
4798 }
4799 }
4800 }
4801
4802 return results;
4803 }
4804
4806 // the layer is editable, but in certain cases it can still be avoided going through all features
4807 if ( mDataProvider->transaction() || ( mEditBuffer->deletedFeatureIds().isEmpty() &&
4808 mEditBuffer->addedFeatures().isEmpty() &&
4809 !mEditBuffer->deletedAttributeIds().contains( index ) &&
4810 mEditBuffer->changedAttributeValues().isEmpty() ) )
4811 {
4812 return mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
4813 }
4814 [[fallthrough]];
4815 //we need to go through each feature
4818 {
4819 QgsAttributeList attList;
4820 attList << index;
4821
4822 QgsFeatureRequest request;
4823 request.setSubsetOfAttributes( attList );
4825 QString fieldName = mFields.at( index ).name();
4826 request.setFilterExpression( QStringLiteral( "\"%1\" ILIKE '%%2%'" ).arg( fieldName, substring ) );
4827 QgsFeatureIterator fit = getFeatures( request );
4828
4829 QgsFeature f;
4830 QString currentValue;
4831 while ( fit.nextFeature( f ) )
4832 {
4833 currentValue = f.attribute( index ).toString();
4834 if ( !results.contains( currentValue ) )
4835 results << currentValue;
4836
4837 if ( ( limit >= 0 && results.size() >= limit ) || ( feedback && feedback->isCanceled() ) )
4838 {
4839 break;
4840 }
4841 }
4842
4843 return results;
4844 }
4845 }
4846
4847 Q_ASSERT_X( false, "QgsVectorLayer::uniqueStringsMatching()", "Unknown source of the field!" );
4848 return results;
4849}
4850
4851QVariant QgsVectorLayer::minimumValue( int index ) const
4852{
4854
4855 QVariant minimum;
4856 minimumOrMaximumValue( index, &minimum, nullptr );
4857 return minimum;
4858}
4859
4860QVariant QgsVectorLayer::maximumValue( int index ) const
4861{
4863
4864 QVariant maximum;
4865 minimumOrMaximumValue( index, nullptr, &maximum );
4866 return maximum;
4867}
4868
4869void QgsVectorLayer::minimumAndMaximumValue( int index, QVariant &minimum, QVariant &maximum ) const
4870{
4872
4873 minimumOrMaximumValue( index, &minimum, &maximum );
4874}
4875
4876void QgsVectorLayer::minimumOrMaximumValue( int index, QVariant *minimum, QVariant *maximum ) const
4877{
4879
4880 if ( minimum )
4881 *minimum = QVariant();
4882 if ( maximum )
4883 *maximum = QVariant();
4884
4885 if ( !mDataProvider )
4886 {
4887 return;
4888 }
4889
4890 QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
4891
4892 switch ( origin )
4893 {
4895 {
4896 return;
4897 }
4898
4899 case QgsFields::OriginProvider: //a provider field
4900 {
4901 if ( minimum )
4902 *minimum = mDataProvider->minimumValue( index );
4903 if ( maximum )
4904 *maximum = mDataProvider->maximumValue( index );
4905 if ( mEditBuffer && ! mDataProvider->transaction() )
4906 {
4907 const QgsFeatureMap added = mEditBuffer->addedFeatures();
4908 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4909 while ( addedIt.hasNext() )
4910 {
4911 addedIt.next();
4912 const QVariant v = addedIt.value().attribute( index );
4913 if ( minimum && v.isValid() && qgsVariantLessThan( v, *minimum ) )
4914 *minimum = v;
4915 if ( maximum && v.isValid() && qgsVariantGreaterThan( v, *maximum ) )
4916 *maximum = v;
4917 }
4918
4919 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4920 while ( it.hasNext() )
4921 {
4922 it.next();
4923 const QVariant v = it.value().value( index );
4924 if ( minimum && v.isValid() && qgsVariantLessThan( v, *minimum ) )
4925 *minimum = v;
4926 if ( maximum && v.isValid() && qgsVariantGreaterThan( v, *maximum ) )
4927 *maximum = v;
4928 }
4929 }
4930 return;
4931 }
4932
4934 {
4935 // the layer is editable, but in certain cases it can still be avoided going through all features
4936 if ( mDataProvider->transaction() || ( mEditBuffer->deletedFeatureIds().isEmpty() &&
4937 mEditBuffer->addedFeatures().isEmpty() &&
4938 !mEditBuffer->deletedAttributeIds().contains( index ) &&
4939 mEditBuffer->changedAttributeValues().isEmpty() ) )
4940 {
4941 if ( minimum )
4942 *minimum = mDataProvider->minimumValue( index );
4943 if ( maximum )
4944 *maximum = mDataProvider->maximumValue( index );
4945 return;
4946 }
4947 }
4948 [[fallthrough]];
4949 // no choice but to go through all features
4952 {
4953 // we need to go through each feature
4954 QgsAttributeList attList;
4955 attList << index;
4956
4959 .setSubsetOfAttributes( attList ) );
4960
4961 QgsFeature f;
4962 bool firstValue = true;
4963 while ( fit.nextFeature( f ) )
4964 {
4965 const QVariant currentValue = f.attribute( index );
4966 if ( QgsVariantUtils::isNull( currentValue ) )
4967 continue;
4968
4969 if ( firstValue )
4970 {
4971 if ( minimum )
4972 *minimum = currentValue;
4973 if ( maximum )
4974 *maximum = currentValue;
4975 firstValue = false;
4976 }
4977 else
4978 {
4979 if ( minimum && currentValue.isValid() && qgsVariantLessThan( currentValue, *minimum ) )
4980 *minimum = currentValue;
4981 if ( maximum && currentValue.isValid() && qgsVariantGreaterThan( currentValue, *maximum ) )
4982 *maximum = currentValue;
4983 }
4984 }
4985 return;
4986 }
4987 }
4988
4989 Q_ASSERT_X( false, "QgsVectorLayer::minimumOrMaximumValue()", "Unknown source of the field!" );
4990}
4991
4992void QgsVectorLayer::createEditBuffer()
4993{
4995
4996 if ( mEditBuffer )
4997 clearEditBuffer();
4998
4999 if ( mDataProvider->transaction() )
5000 {
5001 mEditBuffer = new QgsVectorLayerEditPassthrough( this );
5002
5003 connect( mDataProvider->transaction(), &QgsTransaction::dirtied, this, &QgsVectorLayer::onDirtyTransaction, Qt::UniqueConnection );
5004 }
5005 else
5006 {
5007 mEditBuffer = new QgsVectorLayerEditBuffer( this );
5008 }
5009 // forward signals
5010 connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::invalidateSymbolCountedFlag );
5011 connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::layerModified ); // TODO[MD]: necessary?
5012 //connect( mEditBuffer, SIGNAL( layerModified() ), this, SLOT( triggerRepaint() ) ); // TODO[MD]: works well?
5014 connect( mEditBuffer, &QgsVectorLayerEditBuffer::featureDeleted, this, &QgsVectorLayer::onFeatureDeleted );
5025
5026}
5027
5028void QgsVectorLayer::clearEditBuffer()
5029{
5031
5032 delete mEditBuffer;
5033 mEditBuffer = nullptr;
5034}
5035
5036QVariant QgsVectorLayer::aggregate( Qgis::Aggregate aggregate, const QString &fieldOrExpression,
5038 bool *ok, QgsFeatureIds *fids, QgsFeedback *feedback, QString *error ) const
5039{
5040 // non fatal for now -- the aggregate expression functions are not thread safe and call this
5042
5043 if ( ok )
5044 *ok = false;
5045 if ( error )
5046 error->clear();
5047
5048 if ( !mDataProvider )
5049 {
5050 if ( error )
5051 *error = tr( "Layer is invalid" );
5052 return QVariant();
5053 }
5054
5055 // test if we are calculating based on a field
5056 const int attrIndex = QgsExpression::expressionToLayerFieldIndex( fieldOrExpression, this );
5057 if ( attrIndex >= 0 )
5058 {
5059 // aggregate is based on a field - if it's a provider field, we could possibly hand over the calculation
5060 // to the provider itself
5061 QgsFields::FieldOrigin origin = mFields.fieldOrigin( attrIndex );
5062 if ( origin == QgsFields::OriginProvider )
5063 {
5064 bool providerOk = false;
5065 QVariant val = mDataProvider->aggregate( aggregate, attrIndex, parameters, context, providerOk, fids );
5066 if ( providerOk )
5067 {
5068 // provider handled calculation
5069 if ( ok )
5070 *ok = true;
5071 return val;
5072 }
5073 }
5074 }
5075
5076 // fallback to using aggregate calculator to determine aggregate
5077 QgsAggregateCalculator c( this );
5078 if ( fids )
5079 c.setFidsFilter( *fids );
5080 c.setParameters( parameters );
5081 bool aggregateOk = false;
5082 const QVariant result = c.calculate( aggregate, fieldOrExpression, context, &aggregateOk, feedback );
5083 if ( ok )
5084 *ok = aggregateOk;
5085 if ( !aggregateOk && error )
5086 *error = c.lastError();
5087
5088 return result;
5089}
5090
5091void QgsVectorLayer::setFeatureBlendMode( QPainter::CompositionMode featureBlendMode )
5092{
5094
5095 if ( mFeatureBlendMode == featureBlendMode )
5096 return;
5097
5098 mFeatureBlendMode = featureBlendMode;
5101}
5102
5103QPainter::CompositionMode QgsVectorLayer::featureBlendMode() const
5104{
5105 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
5107
5108 return mFeatureBlendMode;
5109}
5110
5111void QgsVectorLayer::readSldLabeling( const QDomNode &node )
5112{
5114
5115 setLabeling( nullptr ); // start with no labeling
5116 setLabelsEnabled( false );
5117
5118 QDomElement element = node.toElement();
5119 if ( element.isNull() )
5120 return;
5121
5122 QDomElement userStyleElem = element.firstChildElement( QStringLiteral( "UserStyle" ) );
5123 if ( userStyleElem.isNull() )
5124 {
5125 QgsDebugMsgLevel( QStringLiteral( "Info: UserStyle element not found." ), 4 );
5126 return;
5127 }
5128
5129 QDomElement featTypeStyleElem = userStyleElem.firstChildElement( QStringLiteral( "FeatureTypeStyle" ) );
5130 if ( featTypeStyleElem.isNull() )
5131 {
5132 QgsDebugMsgLevel( QStringLiteral( "Info: FeatureTypeStyle element not found." ), 4 );
5133 return;
5134 }
5135
5136 // create empty FeatureTypeStyle element to merge TextSymbolizer's Rule's from all FeatureTypeStyle's
5137 QDomElement mergedFeatTypeStyle = featTypeStyleElem.cloneNode( false ).toElement();
5138
5139 // use the RuleRenderer when more rules are present or the rule
5140 // has filters or min/max scale denominators set,
5141 // otherwise use the Simple labeling
5142 bool needRuleBasedLabeling = false;
5143 int ruleCount = 0;
5144
5145 while ( !featTypeStyleElem.isNull() )
5146 {
5147 QDomElement ruleElem = featTypeStyleElem.firstChildElement( QStringLiteral( "Rule" ) );
5148 while ( !ruleElem.isNull() )
5149 {
5150 // test rule children element to check if we need to create RuleRenderer
5151 // and if the rule has a symbolizer
5152 bool hasTextSymbolizer = false;
5153 bool hasRuleBased = false;
5154 QDomElement ruleChildElem = ruleElem.firstChildElement();
5155 while ( !ruleChildElem.isNull() )
5156 {
5157 // rule has filter or min/max scale denominator, use the RuleRenderer
5158 if ( ruleChildElem.localName() == QLatin1String( "Filter" ) ||
5159 ruleChildElem.localName() == QLatin1String( "MinScaleDenominator" ) ||
5160 ruleChildElem.localName() == QLatin1String( "MaxScaleDenominator" ) )
5161 {
5162 hasRuleBased = true;
5163 }
5164 // rule has a renderer symbolizer, not a text symbolizer
5165 else if ( ruleChildElem.localName() == QLatin1String( "TextSymbolizer" ) )
5166 {
5167 QgsDebugMsgLevel( QStringLiteral( "Info: TextSymbolizer element found" ), 4 );
5168 hasTextSymbolizer = true;
5169 }
5170
5171 ruleChildElem = ruleChildElem.nextSiblingElement();
5172 }
5173
5174 if ( hasTextSymbolizer )
5175 {
5176 ruleCount++;
5177
5178 // append a clone of all Rules to the merged FeatureTypeStyle element
5179 mergedFeatTypeStyle.appendChild( ruleElem.cloneNode().toElement() );
5180
5181 if ( hasRuleBased )
5182 {
5183 QgsDebugMsgLevel( QStringLiteral( "Info: Filter or Min/MaxScaleDenominator element found: need a RuleBasedLabeling" ), 4 );
5184 needRuleBasedLabeling = true;
5185 }
5186 }
5187
5188 // more rules present, use the RuleRenderer
5189 if ( ruleCount > 1 )
5190 {
5191 QgsDebugMsgLevel( QStringLiteral( "Info: More Rule elements found: need a RuleBasedLabeling" ), 4 );
5192 needRuleBasedLabeling = true;
5193 }
5194
5195 // not use the rule based labeling if no rules with textSymbolizer
5196 if ( ruleCount == 0 )
5197 {
5198 needRuleBasedLabeling = false;
5199 }
5200
5201 ruleElem = ruleElem.nextSiblingElement( QStringLiteral( "Rule" ) );
5202 }
5203 featTypeStyleElem = featTypeStyleElem.nextSiblingElement( QStringLiteral( "FeatureTypeStyle" ) );
5204 }
5205
5206 if ( ruleCount == 0 )
5207 {
5208 QgsDebugMsgLevel( QStringLiteral( "Info: No TextSymbolizer element." ), 4 );
5209 return;
5210 }
5211
5212 QDomElement ruleElem = mergedFeatTypeStyle.firstChildElement( QStringLiteral( "Rule" ) );
5213
5214 if ( needRuleBasedLabeling )
5215 {
5216 QgsDebugMsgLevel( QStringLiteral( "Info: rule based labeling" ), 4 );
5217 QgsRuleBasedLabeling::Rule *rootRule = new QgsRuleBasedLabeling::Rule( nullptr );
5218 while ( !ruleElem.isNull() )
5219 {
5220
5221 QString label, description, filterExp;
5222 int scaleMinDenom = 0, scaleMaxDenom = 0;
5223 QgsPalLayerSettings settings;
5224
5225 // retrieve the Rule element child nodes
5226 QDomElement childElem = ruleElem.firstChildElement();
5227 while ( !childElem.isNull() )
5228 {
5229 if ( childElem.localName() == QLatin1String( "Name" ) )
5230 {
5231 // <se:Name> tag contains the rule identifier,
5232 // so prefer title tag for the label property value
5233 if ( label.isEmpty() )
5234 label = childElem.firstChild().nodeValue();
5235 }
5236 else if ( childElem.localName() == QLatin1String( "Description" ) )
5237 {
5238 // <se:Description> can contains a title and an abstract
5239 QDomElement titleElem = childElem.firstChildElement( QStringLiteral( "Title" ) );
5240 if ( !titleElem.isNull() )
5241 {
5242 label = titleElem.firstChild().nodeValue();
5243 }
5244
5245 QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( "Abstract" ) );
5246 if ( !abstractElem.isNull() )
5247 {
5248 description = abstractElem.firstChild().nodeValue();
5249 }
5250 }
5251 else if ( childElem.localName() == QLatin1String( "Abstract" ) )
5252 {
5253 // <sld:Abstract> (v1.0)
5254 description = childElem.firstChild().nodeValue();
5255 }
5256 else if ( childElem.localName() == QLatin1String( "Title" ) )
5257 {
5258 // <sld:Title> (v1.0)
5259 label = childElem.firstChild().nodeValue();
5260 }
5261 else if ( childElem.localName() == QLatin1String( "Filter" ) )
5262 {
5264 if ( filter )
5265 {
5266 if ( filter->hasParserError() )
5267 {
5268 QgsDebugMsgLevel( QStringLiteral( "SLD Filter parsing error: %1" ).arg( filter->parserErrorString() ), 3 );
5269 }
5270 else
5271 {
5272 filterExp = filter->expression();
5273 }
5274 delete filter;
5275 }
5276 }
5277 else if ( childElem.localName() == QLatin1String( "MinScaleDenominator" ) )
5278 {
5279 bool ok;
5280 int v = childElem.firstChild().nodeValue().toInt( &ok );
5281 if ( ok )
5282 scaleMinDenom = v;
5283 }
5284 else if ( childElem.localName() == QLatin1String( "MaxScaleDenominator" ) )
5285 {
5286 bool ok;
5287 int v = childElem.firstChild().nodeValue().toInt( &ok );
5288 if ( ok )
5289 scaleMaxDenom = v;
5290 }
5291 else if ( childElem.localName() == QLatin1String( "TextSymbolizer" ) )
5292 {
5293 readSldTextSymbolizer( childElem, settings );
5294 }
5295
5296 childElem = childElem.nextSiblingElement();
5297 }
5298
5299 QgsRuleBasedLabeling::Rule *ruleLabeling = new QgsRuleBasedLabeling::Rule( new QgsPalLayerSettings( settings ), scaleMinDenom, scaleMaxDenom, filterExp, label );
5300 rootRule->appendChild( ruleLabeling );
5301
5302 ruleElem = ruleElem.nextSiblingElement();
5303 }
5304
5305 setLabeling( new QgsRuleBasedLabeling( rootRule ) );
5306 setLabelsEnabled( true );
5307 }
5308 else
5309 {
5310 QgsDebugMsgLevel( QStringLiteral( "Info: simple labeling" ), 4 );
5311 // retrieve the TextSymbolizer element child node
5312 QDomElement textSymbolizerElem = ruleElem.firstChildElement( QStringLiteral( "TextSymbolizer" ) );
5314 if ( readSldTextSymbolizer( textSymbolizerElem, s ) )
5315 {
5317 setLabelsEnabled( true );
5318 }
5319 }
5320}
5321
5322bool QgsVectorLayer::readSldTextSymbolizer( const QDomNode &node, QgsPalLayerSettings &settings ) const
5323{
5325
5326 if ( node.localName() != QLatin1String( "TextSymbolizer" ) )
5327 {
5328 QgsDebugMsgLevel( QStringLiteral( "Not a TextSymbolizer element: %1" ).arg( node.localName() ), 3 );
5329 return false;
5330 }
5331 QDomElement textSymbolizerElem = node.toElement();
5332 // Label
5333 QDomElement labelElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Label" ) );
5334 if ( !labelElem.isNull() )
5335 {
5336 QDomElement propertyNameElem = labelElem.firstChildElement( QStringLiteral( "PropertyName" ) );
5337 if ( !propertyNameElem.isNull() )
5338 {
5339 // set labeling defaults
5340
5341 // label attribute
5342 QString labelAttribute = propertyNameElem.text();
5343 settings.fieldName = labelAttribute;
5344 settings.isExpression = false;
5345
5346 int fieldIndex = mFields.lookupField( labelAttribute );
5347 if ( fieldIndex == -1 )
5348 {
5349 // label attribute is not in columns, check if it is an expression
5350 QgsExpression exp( labelAttribute );
5351 if ( !exp.hasEvalError() )
5352 {
5353 settings.isExpression = true;
5354 }
5355 else
5356 {
5357 QgsDebugMsgLevel( QStringLiteral( "SLD label attribute error: %1" ).arg( exp.evalErrorString() ), 3 );
5358 }
5359 }
5360 }
5361 else
5362 {
5363 QgsDebugMsgLevel( QStringLiteral( "Info: PropertyName element not found." ), 4 );
5364 return false;
5365 }
5366 }
5367 else
5368 {
5369 QgsDebugMsgLevel( QStringLiteral( "Info: Label element not found." ), 4 );
5370 return false;
5371 }
5372
5374 if ( textSymbolizerElem.hasAttribute( QStringLiteral( "uom" ) ) )
5375 {
5376 sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( textSymbolizerElem.attribute( QStringLiteral( "uom" ) ) );
5377 }
5378
5379 QString fontFamily = QStringLiteral( "Sans-Serif" );
5380 int fontPointSize = 10;
5382 int fontWeight = -1;
5383 bool fontItalic = false;
5384 bool fontUnderline = false;
5385
5386 // Font
5387 QDomElement fontElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Font" ) );
5388 if ( !fontElem.isNull() )
5389 {
5390 QgsStringMap fontSvgParams = QgsSymbolLayerUtils::getSvgParameterList( fontElem );
5391 for ( QgsStringMap::iterator it = fontSvgParams.begin(); it != fontSvgParams.end(); ++it )
5392 {
5393 QgsDebugMsgLevel( QStringLiteral( "found fontSvgParams %1: %2" ).arg( it.key(), it.value() ), 4 );
5394
5395 if ( it.key() == QLatin1String( "font-family" ) )
5396 {
5397 fontFamily = it.value();
5398 }
5399 else if ( it.key() == QLatin1String( "font-style" ) )
5400 {
5401 fontItalic = ( it.value() == QLatin1String( "italic" ) ) || ( it.value() == QLatin1String( "Italic" ) );
5402 }
5403 else if ( it.key() == QLatin1String( "font-size" ) )
5404 {
5405 bool ok;
5406 int fontSize = it.value().toInt( &ok );
5407 if ( ok )
5408 {
5409 fontPointSize = fontSize;
5410 fontUnitSize = sldUnitSize;
5411 }
5412 }
5413 else if ( it.key() == QLatin1String( "font-weight" ) )
5414 {
5415 if ( ( it.value() == QLatin1String( "bold" ) ) || ( it.value() == QLatin1String( "Bold" ) ) )
5416 fontWeight = QFont::Bold;
5417 }
5418 else if ( it.key() == QLatin1String( "font-underline" ) )
5419 {
5420 fontUnderline = ( it.value() == QLatin1String( "underline" ) ) || ( it.value() == QLatin1String( "Underline" ) );
5421 }
5422 }
5423 }
5424
5425 QgsTextFormat format;
5426 QFont font( fontFamily, fontPointSize, fontWeight, fontItalic );
5427 font.setUnderline( fontUnderline );
5428 format.setFont( font );
5429 format.setSize( fontPointSize );
5430 format.setSizeUnit( fontUnitSize );
5431
5432 // Fill
5433 QDomElement fillElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Fill" ) );
5434 QColor textColor;
5435 Qt::BrushStyle textBrush = Qt::SolidPattern;
5436 QgsSymbolLayerUtils::fillFromSld( fillElem, textBrush, textColor );
5437 if ( textColor.isValid() )
5438 {
5439 QgsDebugMsgLevel( QStringLiteral( "Info: textColor %1." ).arg( QVariant( textColor ).toString() ), 4 );
5440 format.setColor( textColor );
5441 }
5442
5443 QgsTextBufferSettings bufferSettings;
5444
5445 // Halo
5446 QDomElement haloElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Halo" ) );
5447 if ( !haloElem.isNull() )
5448 {
5449 bufferSettings.setEnabled( true );
5450 bufferSettings.setSize( 1 );
5451
5452 QDomElement radiusElem = haloElem.firstChildElement( QStringLiteral( "Radius" ) );
5453 if ( !radiusElem.isNull() )
5454 {
5455 bool ok;
5456 double bufferSize = radiusElem.text().toDouble( &ok );
5457 if ( ok )
5458 {
5459 bufferSettings.setSize( bufferSize );
5460 bufferSettings.setSizeUnit( sldUnitSize );
5461 }
5462 }
5463
5464 QDomElement haloFillElem = haloElem.firstChildElement( QStringLiteral( "Fill" ) );
5465 QColor bufferColor;
5466 Qt::BrushStyle bufferBrush = Qt::SolidPattern;
5467 QgsSymbolLayerUtils::fillFromSld( haloFillElem, bufferBrush, bufferColor );
5468 if ( bufferColor.isValid() )
5469 {
5470 QgsDebugMsgLevel( QStringLiteral( "Info: bufferColor %1." ).arg( QVariant( bufferColor ).toString() ), 4 );
5471 bufferSettings.setColor( bufferColor );
5472 }
5473 }
5474
5475 // LabelPlacement
5476 QDomElement labelPlacementElem = textSymbolizerElem.firstChildElement( QStringLiteral( "LabelPlacement" ) );
5477 if ( !labelPlacementElem.isNull() )
5478 {
5479 // PointPlacement
5480 QDomElement pointPlacementElem = labelPlacementElem.firstChildElement( QStringLiteral( "PointPlacement" ) );
5481 if ( !pointPlacementElem.isNull() )
5482 {
5485 {
5487 }
5488
5489 QDomElement displacementElem = pointPlacementElem.firstChildElement( QStringLiteral( "Displacement" ) );
5490 if ( !displacementElem.isNull() )
5491 {
5492 QDomElement displacementXElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementX" ) );
5493 if ( !displacementXElem.isNull() )
5494 {
5495 bool ok;
5496 double xOffset = displacementXElem.text().toDouble( &ok );
5497 if ( ok )
5498 {
5499 settings.xOffset = xOffset;
5500 settings.offsetUnits = sldUnitSize;
5501 }
5502 }
5503 QDomElement displacementYElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementY" ) );
5504 if ( !displacementYElem.isNull() )
5505 {
5506 bool ok;
5507 double yOffset = displacementYElem.text().toDouble( &ok );
5508 if ( ok )
5509 {
5510 settings.yOffset = yOffset;
5511 settings.offsetUnits = sldUnitSize;
5512 }
5513 }
5514 }
5515 QDomElement anchorPointElem = pointPlacementElem.firstChildElement( QStringLiteral( "AnchorPoint" ) );
5516 if ( !anchorPointElem.isNull() )
5517 {
5518 QDomElement anchorPointXElem = anchorPointElem.firstChildElement( QStringLiteral( "AnchorPointX" ) );
5519 if ( !anchorPointXElem.isNull() )
5520 {
5521 bool ok;
5522 double xOffset = anchorPointXElem.text().toDouble( &ok );
5523 if ( ok )
5524 {
5525 settings.xOffset = xOffset;
5526 settings.offsetUnits = sldUnitSize;
5527 }
5528 }
5529 QDomElement anchorPointYElem = anchorPointElem.firstChildElement( QStringLiteral( "AnchorPointY" ) );
5530 if ( !anchorPointYElem.isNull() )
5531 {
5532 bool ok;
5533 double yOffset = anchorPointYElem.text().toDouble( &ok );
5534 if ( ok )
5535 {
5536 settings.yOffset = yOffset;
5537 settings.offsetUnits = sldUnitSize;
5538 }
5539 }
5540 }
5541
5542 QDomElement rotationElem = pointPlacementElem.firstChildElement( QStringLiteral( "Rotation" ) );
5543 if ( !rotationElem.isNull() )
5544 {
5545 bool ok;
5546 double rotation = rotationElem.text().toDouble( &ok );
5547 if ( ok )
5548 {
5549 settings.angleOffset = 360 - rotation;
5550 }
5551 }
5552 }
5553 else
5554 {
5555 // PointPlacement
5556 QDomElement linePlacementElem = labelPlacementElem.firstChildElement( QStringLiteral( "LinePlacement" ) );
5557 if ( !linePlacementElem.isNull() )
5558 {
5560 }
5561 }
5562 }
5563
5564 // read vendor options
5565 QgsStringMap vendorOptions;
5566 QDomElement vendorOptionElem = textSymbolizerElem.firstChildElement( QStringLiteral( "VendorOption" ) );
5567 while ( !vendorOptionElem.isNull() && vendorOptionElem.localName() == QLatin1String( "VendorOption" ) )
5568 {
5569 QString optionName = vendorOptionElem.attribute( QStringLiteral( "name" ) );
5570 QString optionValue;
5571 if ( vendorOptionElem.firstChild().nodeType() == QDomNode::TextNode )
5572 {
5573 optionValue = vendorOptionElem.firstChild().nodeValue();
5574 }
5575 else
5576 {
5577 if ( vendorOptionElem.firstChild().nodeType() == QDomNode::ElementNode &&
5578 vendorOptionElem.firstChild().localName() == QLatin1String( "Literal" ) )
5579 {
5580 QgsDebugMsgLevel( vendorOptionElem.firstChild().localName(), 2 );
5581 optionValue = vendorOptionElem.firstChild().firstChild().nodeValue();
5582 }
5583 else
5584 {
5585 QgsDebugError( QStringLiteral( "unexpected child of %1 named %2" ).arg( vendorOptionElem.localName(), optionName ) );
5586 }
5587 }
5588
5589 if ( !optionName.isEmpty() && !optionValue.isEmpty() )
5590 {
5591 vendorOptions[ optionName ] = optionValue;
5592 }
5593
5594 vendorOptionElem = vendorOptionElem.nextSiblingElement();
5595 }
5596 if ( !vendorOptions.isEmpty() )
5597 {
5598 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
5599 {
5600 if ( it.key() == QLatin1String( "underlineText" ) && it.value() == QLatin1String( "true" ) )
5601 {
5602 font.setUnderline( true );
5603 format.setFont( font );
5604 }
5605 else if ( it.key() == QLatin1String( "strikethroughText" ) && it.value() == QLatin1String( "true" ) )
5606 {
5607 font.setStrikeOut( true );
5608 format.setFont( font );
5609 }
5610 else if ( it.key() == QLatin1String( "maxDisplacement" ) )
5611 {
5613 }
5614 else if ( it.key() == QLatin1String( "followLine" ) && it.value() == QLatin1String( "true" ) )
5615 {
5617 {
5619 }
5620 else
5621 {
5623 }
5624 }
5625 else if ( it.key() == QLatin1String( "maxAngleDelta" ) )
5626 {
5627 bool ok;
5628 double angle = it.value().toDouble( &ok );
5629 if ( ok )
5630 {
5631 settings.maxCurvedCharAngleIn = angle;
5632 settings.maxCurvedCharAngleOut = angle;
5633 }
5634 }
5635 // miscellaneous options
5636 else if ( it.key() == QLatin1String( "conflictResolution" ) && it.value() == QLatin1String( "false" ) )
5637 {
5639 }
5640 else if ( it.key() == QLatin1String( "forceLeftToRight" ) && it.value() == QLatin1String( "false" ) )
5641 {
5643 }
5644 else if ( it.key() == QLatin1String( "group" ) && it.value() == QLatin1String( "yes" ) )
5645 {
5646 settings.lineSettings().setMergeLines( true );
5647 }
5648 else if ( it.key() == QLatin1String( "labelAllGroup" ) && it.value() == QLatin1String( "true" ) )
5649 {
5650 settings.lineSettings().setMergeLines( true );
5651 }
5652 }
5653 }
5654
5655 format.setBuffer( bufferSettings );
5656 settings.setFormat( format );
5657 return true;
5658}
5659
5661{
5663
5664 return mEditFormConfig;
5665}
5666
5668{
5670
5671 if ( mEditFormConfig == editFormConfig )
5672 return;
5673
5674 mEditFormConfig = editFormConfig;
5675 mEditFormConfig.onRelationsLoaded();
5676 emit editFormConfigChanged();
5677}
5678
5680{
5682
5683 QgsAttributeTableConfig config = mAttributeTableConfig;
5684
5685 if ( config.isEmpty() )
5686 config.update( fields() );
5687
5688 return config;
5689}
5690
5692{
5694
5695 if ( mAttributeTableConfig != attributeTableConfig )
5696 {
5697 mAttributeTableConfig = attributeTableConfig;
5698 emit configChanged();
5699 }
5700}
5701
5703{
5704 // called in a non-thread-safe way in some cases when calculating aggregates in a different thread
5706
5708}
5709
5711{
5713
5715}
5716
5718{
5720
5721 if ( !mDiagramLayerSettings )