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