QGIS API Documentation 3.99.0-Master (e69e8341d6a)
qgsvectorlayer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvectorlayer.cpp
3 --------------------
4 begin : Oct 29, 2003
5 copyright : (C) 2003 by Gary E.Sherman
6 email : sherman at mrcc.com
7
8 This class implements a generic means to display vector layers. The features
9 and attributes are read from the data store using a "data provider" plugin.
10 QgsVectorLayer can be used with any data store for which an appropriate
11 plugin is available.
12
13***************************************************************************/
14
15/***************************************************************************
16 * *
17 * This program is free software; you can redistribute it and/or modify *
18 * it under the terms of the GNU General Public License as published by *
19 * the Free Software Foundation; either version 2 of the License, or *
20 * (at your option) any later version. *
21 * *
22 ***************************************************************************/
23
24#include "qgis.h" //for globals
25#include "qgssettings.h"
26#include "qgsvectorlayer.h"
27#include "moc_qgsvectorlayer.cpp"
28#include "qgsactionmanager.h"
29#include "qgsapplication.h"
30#include "qgsconditionalstyle.h"
32#include "qgscurve.h"
33#include "qgsdatasourceuri.h"
36#include "qgsfeature.h"
37#include "qgsfeaturerequest.h"
38#include "qgsfields.h"
39#include "qgsmaplayerfactory.h"
41#include "qgsgeometry.h"
43#include "qgslogger.h"
44#include "qgsmaplayerlegend.h"
45#include "qgsmessagelog.h"
46#include "qgsogcutils.h"
47#include "qgspainting.h"
48#include "qgspointxy.h"
49#include "qgsproject.h"
50#include "qgsproviderregistry.h"
51#include "qgsrectangle.h"
52#include "qgsrelationmanager.h"
53#include "qgsweakrelation.h"
54#include "qgsrendercontext.h"
67#include "qgspoint.h"
68#include "qgsrenderer.h"
69#include "qgssymbollayer.h"
70#include "qgsdiagramrenderer.h"
71#include "qgspallabeling.h"
75#include "qgsfeedback.h"
76#include "qgsxmlutils.h"
77#include "qgstaskmanager.h"
78#include "qgstransaction.h"
79#include "qgsauxiliarystorage.h"
80#include "qgsgeometryoptions.h"
82#include "qgsruntimeprofiler.h"
84#include "qgsvectorlayerutils.h"
86#include "qgsprofilerequest.h"
87#include "qgssymbollayerutils.h"
88#include "qgsthreadingutils.h"
89#include "qgssldexportcontext.h"
90
91#include <QDir>
92#include <QFile>
93#include <QImage>
94#include <QPainter>
95#include <QPainterPath>
96#include <QPolygonF>
97#include <QProgressDialog>
98#include <QString>
99#include <QDomNode>
100#include <QVector>
101#include <QStringBuilder>
102#include <QUrl>
103#include <QUndoCommand>
104#include <QUrlQuery>
105#include <QUuid>
106#include <QRegularExpression>
107#include <QTimer>
108
109#include <limits>
110#include <optional>
111
113#include "qgssettingsentryimpl.h"
114#include "qgssettingstree.h"
115
121
122
123#ifdef TESTPROVIDERLIB
124#include <dlfcn.h>
125#endif
126
127typedef bool saveStyle_t(
128 const QString &uri,
129 const QString &qmlStyle,
130 const QString &sldStyle,
131 const QString &styleName,
132 const QString &styleDescription,
133 const QString &uiFileContent,
134 bool useAsDefault,
135 QString &errCause
136);
137
138typedef QString loadStyle_t(
139 const QString &uri,
140 QString &errCause
141);
142
143typedef int listStyles_t(
144 const QString &uri,
145 QStringList &ids,
146 QStringList &names,
147 QStringList &descriptions,
148 QString &errCause
149);
150
151typedef QString getStyleById_t(
152 const QString &uri,
153 QString styleID,
154 QString &errCause
155);
156
157typedef bool deleteStyleById_t(
158 const QString &uri,
159 QString styleID,
160 QString &errCause
161);
162
163
164QgsVectorLayer::QgsVectorLayer( const QString &vectorLayerPath,
165 const QString &baseName,
166 const QString &providerKey,
167 const QgsVectorLayer::LayerOptions &options )
168 : QgsMapLayer( Qgis::LayerType::Vector, baseName, vectorLayerPath )
169 , mSelectionProperties( new QgsVectorLayerSelectionProperties( this ) )
170 , mTemporalProperties( new QgsVectorLayerTemporalProperties( this ) )
171 , mElevationProperties( new QgsVectorLayerElevationProperties( this ) )
172 , mAuxiliaryLayer( nullptr )
173 , mAuxiliaryLayerKey( QString() )
174 , mReadExtentFromXml( options.readExtentFromXml )
175 , mRefreshRendererTimer( new QTimer( this ) )
176{
178 mLoadAllStoredStyle = options.loadAllStoredStyles;
179
180 if ( options.fallbackCrs.isValid() )
181 setCrs( options.fallbackCrs, false );
182 mWkbType = options.fallbackWkbType;
183
184 setProviderType( providerKey );
185
186 mGeometryOptions = std::make_unique<QgsGeometryOptions>();
187 mActions = new QgsActionManager( this );
188 mConditionalStyles = new QgsConditionalLayerStyles( this );
189 mStoredExpressionManager = new QgsStoredExpressionManager();
190 mStoredExpressionManager->setParent( this );
191
192 mJoinBuffer = new QgsVectorLayerJoinBuffer( this );
193 mJoinBuffer->setParent( this );
194 connect( mJoinBuffer, &QgsVectorLayerJoinBuffer::joinedFieldsChanged, this, &QgsVectorLayer::onJoinedFieldsChanged );
195
196 mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
197 // if we're given a provider type, try to create and bind one to this layer
198 if ( !vectorLayerPath.isEmpty() && !mProviderKey.isEmpty() )
199 {
200 QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
201 Qgis::DataProviderReadFlags providerFlags;
202 if ( options.loadDefaultStyle )
203 {
205 }
206 if ( options.forceReadOnly )
207 {
209 mDataSourceReadOnly = true;
210 }
211 setDataSource( vectorLayerPath, baseName, providerKey, providerOptions, providerFlags );
212 }
213
214 for ( const QgsField &field : std::as_const( mFields ) )
215 {
216 if ( !mAttributeAliasMap.contains( field.name() ) )
217 mAttributeAliasMap.insert( field.name(), QString() );
218 }
219
220 if ( isValid() )
221 {
222 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
223 if ( !mTemporalProperties->isActive() )
224 {
225 // didn't populate temporal properties from provider metadata, so at least try to setup some initially nice
226 // selections
227 mTemporalProperties->guessDefaultsFromFields( mFields );
228 }
229
230 mElevationProperties->setDefaultsFromLayer( this );
231 }
232
233 connect( this, &QgsVectorLayer::selectionChanged, this, [this] { triggerRepaint(); } );
234 connect( QgsProject::instance()->relationManager(), &QgsRelationManager::relationsLoaded, this, &QgsVectorLayer::onRelationsLoaded ); // skip-keyword-check
235
239
240 // Default simplify drawing settings
241 QgsSettings settings;
242 mSimplifyMethod.setSimplifyHints( QgsVectorLayer::settingsSimplifyDrawingHints->valueWithDefaultOverride( mSimplifyMethod.simplifyHints() ) );
243 mSimplifyMethod.setSimplifyAlgorithm( QgsVectorLayer::settingsSimplifyAlgorithm->valueWithDefaultOverride( mSimplifyMethod.simplifyAlgorithm() ) );
244 mSimplifyMethod.setThreshold( QgsVectorLayer::settingsSimplifyDrawingTol->valueWithDefaultOverride( mSimplifyMethod.threshold() ) );
245 mSimplifyMethod.setForceLocalOptimization( QgsVectorLayer::settingsSimplifyLocal->valueWithDefaultOverride( mSimplifyMethod.forceLocalOptimization() ) );
246 mSimplifyMethod.setMaximumScale( QgsVectorLayer::settingsSimplifyMaxScale->valueWithDefaultOverride( mSimplifyMethod.maximumScale() ) );
247
248 connect( mRefreshRendererTimer, &QTimer::timeout, this, [this] { triggerRepaint( true ); } );
249}
250
252{
253 emit willBeDeleted();
254
255 setValid( false );
256
257 delete mDataProvider;
258 delete mEditBuffer;
259 delete mJoinBuffer;
260 delete mExpressionFieldBuffer;
261 delete mLabeling;
262 delete mDiagramLayerSettings;
263 delete mDiagramRenderer;
264
265 delete mActions;
266
267 delete mRenderer;
268 delete mConditionalStyles;
269 delete mStoredExpressionManager;
270
271 if ( mFeatureCounter )
272 mFeatureCounter->cancel();
273
274 qDeleteAll( mRendererGenerators );
275}
276
278{
280
282 // We get the data source string from the provider when
283 // possible because some providers may have changed it
284 // directly (memory provider does that).
285 QString dataSource;
286 if ( mDataProvider )
287 {
288 dataSource = mDataProvider->dataSourceUri();
289 options.transformContext = mDataProvider->transformContext();
290 }
291 else
292 {
293 dataSource = source();
294 }
295 options.forceReadOnly = mDataSourceReadOnly;
296 QgsVectorLayer *layer = new QgsVectorLayer( dataSource, name(), mProviderKey, options );
297 if ( mDataProvider && layer->dataProvider() )
298 {
299 layer->dataProvider()->handlePostCloneOperations( mDataProvider );
300 }
301 QgsMapLayer::clone( layer );
302 layer->mXmlExtent2D = mXmlExtent2D;
303 layer->mLazyExtent2D = mLazyExtent2D;
304 layer->mValidExtent2D = mValidExtent2D;
305 layer->mXmlExtent3D = mXmlExtent3D;
306 layer->mLazyExtent3D = mLazyExtent3D;
307 layer->mValidExtent3D = mValidExtent3D;
308
309 QList<QgsVectorLayerJoinInfo> joins = vectorJoins();
310 const auto constJoins = joins;
311 for ( const QgsVectorLayerJoinInfo &join : constJoins )
312 {
313 // do not copy join information for auxiliary layer
314 if ( !auxiliaryLayer()
315 || ( auxiliaryLayer() && auxiliaryLayer()->id() != join.joinLayerId() ) )
316 layer->addJoin( join );
317 }
318
319 if ( mDataProvider )
320 layer->setProviderEncoding( mDataProvider->encoding() );
321 layer->setSubsetString( subsetString() );
325 layer->setReadOnly( isReadOnly() );
330
331 const auto constActions = actions()->actions();
332 for ( const QgsAction &action : constActions )
333 {
334 layer->actions()->addAction( action );
335 }
336
337 if ( auto *lRenderer = renderer() )
338 {
339 layer->setRenderer( lRenderer->clone() );
340 }
341
342 if ( auto *lLabeling = labeling() )
343 {
344 layer->setLabeling( lLabeling->clone() );
345 }
347
349
350 if ( auto *lDiagramRenderer = diagramRenderer() )
351 {
352 layer->setDiagramRenderer( lDiagramRenderer->clone() );
353 }
354
355 if ( auto *lDiagramLayerSettings = diagramLayerSettings() )
356 {
357 layer->setDiagramLayerSettings( *lDiagramLayerSettings );
358 }
359
360 for ( int i = 0; i < fields().count(); i++ )
361 {
362 layer->setFieldAlias( i, attributeAlias( i ) );
364 layer->setEditorWidgetSetup( i, editorWidgetSetup( i ) );
367
368 QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength> constraints = fieldConstraintsAndStrength( i );
369 auto constraintIt = constraints.constBegin();
370 for ( ; constraintIt != constraints.constEnd(); ++ constraintIt )
371 {
372 layer->setFieldConstraint( i, constraintIt.key(), constraintIt.value() );
373 }
374
375 if ( fields().fieldOrigin( i ) == Qgis::FieldOrigin::Expression )
376 {
377 layer->addExpressionField( expressionField( i ), fields().at( i ) );
378 }
379 }
380
382
383 if ( auto *lAuxiliaryLayer = auxiliaryLayer() )
384 layer->setAuxiliaryLayer( lAuxiliaryLayer->clone( layer ) );
385
386 layer->mElevationProperties = mElevationProperties->clone();
387 layer->mElevationProperties->setParent( layer );
388
389 layer->mSelectionProperties = mSelectionProperties->clone();
390 layer->mSelectionProperties->setParent( layer );
391
392 return layer;
393}
394
396{
398
399 if ( mDataProvider )
400 {
401 return mDataProvider->storageType();
402 }
403 return QString();
404}
405
406
408{
410
411 if ( mDataProvider )
412 {
413 return mDataProvider->capabilitiesString();
414 }
415 return QString();
416}
417
419{
421
422 return mDataProvider && mDataProvider->isSqlQuery();
423}
424
431
433{
435
436 if ( mDataProvider )
437 {
438 return mDataProvider->dataComment();
439 }
440 return QString();
441}
442
449
451{
453
454 return name();
455}
456
458{
459 // non fatal for now -- the QgsVirtualLayerTask class is not thread safe and calls this
461
462 if ( mDataProvider )
463 {
464 mDataProvider->reloadData();
465 updateFields();
466 }
467}
468
470{
471 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
473
474 return new QgsVectorLayerRenderer( this, rendererContext );
475}
476
477
478void QgsVectorLayer::drawVertexMarker( double x, double y, QPainter &p, Qgis::VertexMarkerType type, int m )
479{
480 switch ( type )
481 {
483 p.setPen( QColor( 50, 100, 120, 200 ) );
484 p.setBrush( QColor( 200, 200, 210, 120 ) );
485 p.drawEllipse( x - m, y - m, m * 2 + 1, m * 2 + 1 );
486 break;
487
489 p.setPen( QColor( 255, 0, 0 ) );
490 p.drawLine( x - m, y + m, x + m, y - m );
491 p.drawLine( x - m, y - m, x + m, y + m );
492 break;
493
495 break;
496 }
497}
498
500{
502
503 mSelectedFeatureIds.insert( fid );
504 mPreviousSelectedFeatureIds.clear();
505
506 emit selectionChanged( QgsFeatureIds() << fid, QgsFeatureIds(), false );
507}
508
509void QgsVectorLayer::select( const QgsFeatureIds &featureIds )
510{
512
513 mSelectedFeatureIds.unite( featureIds );
514 mPreviousSelectedFeatureIds.clear();
515
516 emit selectionChanged( featureIds, QgsFeatureIds(), false );
517}
518
520{
522
523 mSelectedFeatureIds.remove( fid );
524 mPreviousSelectedFeatureIds.clear();
525
526 emit selectionChanged( QgsFeatureIds(), QgsFeatureIds() << fid, false );
527}
528
530{
532
533 mSelectedFeatureIds.subtract( featureIds );
534 mPreviousSelectedFeatureIds.clear();
535
536 emit selectionChanged( QgsFeatureIds(), featureIds, false );
537}
538
540{
542
543 // normalize the rectangle
544 rect.normalize();
545
546 QgsFeatureIds newSelection;
547
549 .setFilterRect( rect )
551 .setNoAttributes() );
552
553 QgsFeature feat;
554 while ( features.nextFeature( feat ) )
555 {
556 newSelection << feat.id();
557 }
558 features.close();
559
560 selectByIds( newSelection, behavior );
561}
562
563void QgsVectorLayer::selectByExpression( const QString &expression, Qgis::SelectBehavior behavior, QgsExpressionContext *context )
564{
566
567 QgsFeatureIds newSelection;
568
569 std::optional< QgsExpressionContext > defaultContext;
570 if ( !context )
571 {
572 defaultContext.emplace( QgsExpressionContextUtils::globalProjectLayerScopes( this ) );
573 context = &defaultContext.value();
574 }
575 else
576 {
578 }
579
580 QgsExpression exp( expression );
581 exp.prepare( context );
582
584 {
586 .setExpressionContext( *context );
588
589 if ( !exp.needsGeometry() )
591
592 QgsFeatureIterator features = getFeatures( request );
593
594 if ( behavior == Qgis::SelectBehavior::AddToSelection )
595 {
596 newSelection = selectedFeatureIds();
597 }
598 QgsFeature feat;
599 while ( features.nextFeature( feat ) )
600 {
601 newSelection << feat.id();
602 }
603 features.close();
604 }
606 {
607
608 QgsFeatureIds oldSelection = selectedFeatureIds();
609 QgsFeatureRequest request = QgsFeatureRequest().setFilterFids( oldSelection );
610
611 //refine request
612 if ( !exp.needsGeometry() )
615
616 QgsFeatureIterator features = getFeatures( request );
617 QgsFeature feat;
618 while ( features.nextFeature( feat ) )
619 {
620 context->setFeature( feat );
621 bool matches = exp.evaluate( context ).toBool();
622
623 if ( matches && behavior == Qgis::SelectBehavior::IntersectSelection )
624 {
625 newSelection << feat.id();
626 }
627 else if ( !matches && behavior == Qgis::SelectBehavior::RemoveFromSelection )
628 {
629 newSelection << feat.id();
630 }
631 }
632 }
633
634 selectByIds( newSelection );
635}
636
638{
640
641 QgsFeatureIds newSelection;
642
643 switch ( behavior )
644 {
646 newSelection = ids;
647 break;
648
650 newSelection = mSelectedFeatureIds + ids;
651 break;
652
654 newSelection = mSelectedFeatureIds - ids;
655 break;
656
658 newSelection = mSelectedFeatureIds.intersect( ids );
659 break;
660 }
661
662 QgsFeatureIds deselectedFeatures = mSelectedFeatureIds - newSelection;
663 mSelectedFeatureIds = newSelection;
664 mPreviousSelectedFeatureIds.clear();
665
666 emit selectionChanged( newSelection, deselectedFeatures, true );
667}
668
669void QgsVectorLayer::modifySelection( const QgsFeatureIds &selectIds, const QgsFeatureIds &deselectIds )
670{
672
673 QgsFeatureIds intersectingIds = selectIds & deselectIds;
674 if ( !intersectingIds.isEmpty() )
675 {
676 QgsDebugMsgLevel( QStringLiteral( "Trying to select and deselect the same item at the same time. Unsure what to do. Selecting dubious items." ), 3 );
677 }
678
679 mSelectedFeatureIds -= deselectIds;
680 mSelectedFeatureIds += selectIds;
681 mPreviousSelectedFeatureIds.clear();
682
683 emit selectionChanged( selectIds, deselectIds - intersectingIds, false );
684}
685
687{
689
691 ids.subtract( mSelectedFeatureIds );
692 selectByIds( ids );
693}
694
701
703{
705
706 // normalize the rectangle
707 rect.normalize();
708
710 .setFilterRect( rect )
712 .setNoAttributes() );
713
714 QgsFeatureIds selectIds;
715 QgsFeatureIds deselectIds;
716
717 QgsFeature fet;
718 while ( fit.nextFeature( fet ) )
719 {
720 if ( mSelectedFeatureIds.contains( fet.id() ) )
721 {
722 deselectIds << fet.id();
723 }
724 else
725 {
726 selectIds << fet.id();
727 }
728 }
729
730 modifySelection( selectIds, deselectIds );
731}
732
734{
736
737 if ( mSelectedFeatureIds.isEmpty() )
738 return;
739
740 const QgsFeatureIds previous = mSelectedFeatureIds;
742 mPreviousSelectedFeatureIds = previous;
743}
744
746{
748
749 if ( mPreviousSelectedFeatureIds.isEmpty() || !mSelectedFeatureIds.empty() )
750 return;
751
752 selectByIds( mPreviousSelectedFeatureIds );
753}
754
756{
757 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
759
760 return mDataProvider;
761}
762
764{
765 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
767
768 return mDataProvider;
769}
770
772{
773 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
775
776 return mSelectionProperties;
777}
778
785
792
794{
796
797 QgsProfileRequest modifiedRequest( request );
798 modifiedRequest.expressionContext().appendScope( createExpressionContextScope() );
799 return new QgsVectorLayerProfileGenerator( this, modifiedRequest );
800}
801
802void QgsVectorLayer::setProviderEncoding( const QString &encoding )
803{
805
806 if ( isValid() && mDataProvider && mDataProvider->encoding() != encoding )
807 {
808 mDataProvider->setEncoding( encoding );
809 updateFields();
810 }
811}
812
814{
816
817 delete mDiagramRenderer;
818 mDiagramRenderer = r;
819 emit rendererChanged();
820 emit styleChanged();
821}
822
824{
825 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
827
828 return QgsWkbTypes::geometryType( mWkbType );
829}
830
832{
834
835 return mWkbType;
836}
837
839{
841
842 if ( !isValid() || !isSpatial() || mSelectedFeatureIds.isEmpty() || !mDataProvider ) //no selected features
843 {
844 return QgsRectangle( 0, 0, 0, 0 );
845 }
846
847 QgsRectangle r, retval;
848 retval.setNull();
849
850 QgsFeature fet;
852 {
854 .setFilterFids( mSelectedFeatureIds )
855 .setNoAttributes() );
856
857 while ( fit.nextFeature( fet ) )
858 {
859 if ( !fet.hasGeometry() )
860 continue;
861 r = fet.geometry().boundingBox();
862 retval.combineExtentWith( r );
863 }
864 }
865 else
866 {
868 .setNoAttributes() );
869
870 while ( fit.nextFeature( fet ) )
871 {
872 if ( mSelectedFeatureIds.contains( fet.id() ) )
873 {
874 if ( fet.hasGeometry() )
875 {
876 r = fet.geometry().boundingBox();
877 retval.combineExtentWith( r );
878 }
879 }
880 }
881 }
882
883 if ( retval.width() == 0.0 || retval.height() == 0.0 )
884 {
885 // If all of the features are at the one point, buffer the
886 // rectangle a bit. If they are all at zero, do something a bit
887 // more crude.
888
889 if ( retval.xMinimum() == 0.0 && retval.xMaximum() == 0.0 &&
890 retval.yMinimum() == 0.0 && retval.yMaximum() == 0.0 )
891 {
892 retval.set( -1.0, -1.0, 1.0, 1.0 );
893 }
894 }
895
896 return retval;
897}
898
900{
901 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
903
904 return mLabelsEnabled && static_cast< bool >( mLabeling );
905}
906
908{
910
911 mLabelsEnabled = enabled;
912}
913
915{
916 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
918
919 if ( !mDiagramRenderer || !mDiagramLayerSettings )
920 return false;
921
922 QList<QgsDiagramSettings> settingList = mDiagramRenderer->diagramSettings();
923 if ( !settingList.isEmpty() )
924 {
925 return settingList.at( 0 ).enabled;
926 }
927 return false;
928}
929
930long long QgsVectorLayer::featureCount( const QString &legendKey ) const
931{
933
934 if ( !mSymbolFeatureCounted )
935 return -1;
936
937 return mSymbolFeatureCountMap.value( legendKey, -1 );
938}
939
940QgsFeatureIds QgsVectorLayer::symbolFeatureIds( const QString &legendKey ) const
941{
943
944 if ( !mSymbolFeatureCounted )
945 return QgsFeatureIds();
946
947 return mSymbolFeatureIdMap.value( legendKey, QgsFeatureIds() );
948}
950{
952
953 if ( ( mSymbolFeatureCounted || mFeatureCounter ) && !( storeSymbolFids && mSymbolFeatureIdMap.isEmpty() ) )
954 return mFeatureCounter;
955
956 mSymbolFeatureCountMap.clear();
957 mSymbolFeatureIdMap.clear();
958
959 if ( !isValid() )
960 {
961 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer" ), 3 );
962 return mFeatureCounter;
963 }
964 if ( !mDataProvider )
965 {
966 QgsDebugMsgLevel( QStringLiteral( "invoked with null mDataProvider" ), 3 );
967 return mFeatureCounter;
968 }
969 if ( !mRenderer )
970 {
971 QgsDebugMsgLevel( QStringLiteral( "invoked with null mRenderer" ), 3 );
972 return mFeatureCounter;
973 }
974
975 if ( !mFeatureCounter || ( storeSymbolFids && mSymbolFeatureIdMap.isEmpty() ) )
976 {
977 mFeatureCounter = new QgsVectorLayerFeatureCounter( this, QgsExpressionContext(), storeSymbolFids );
978 connect( mFeatureCounter, &QgsTask::taskCompleted, this, &QgsVectorLayer::onFeatureCounterCompleted, Qt::UniqueConnection );
979 connect( mFeatureCounter, &QgsTask::taskTerminated, this, &QgsVectorLayer::onFeatureCounterTerminated, Qt::UniqueConnection );
980 QgsApplication::taskManager()->addTask( mFeatureCounter );
981 }
982
983 return mFeatureCounter;
984}
985
987{
989
990 // do not update extent by default when trust project option is activated
991 if ( force || !mReadExtentFromXml || ( mReadExtentFromXml && mXmlExtent2D.isNull() && mXmlExtent3D.isNull() ) )
992 {
993 mValidExtent2D = false;
994 mValidExtent3D = false;
995 }
996}
997
999{
1001
1003 mValidExtent2D = true;
1004}
1005
1007{
1009
1011 mValidExtent3D = true;
1012}
1013
1014void QgsVectorLayer::updateDefaultValues( QgsFeatureId fid, QgsFeature feature, QgsExpressionContext *context )
1015{
1017
1018 if ( !mDefaultValueOnUpdateFields.isEmpty() )
1019 {
1020 if ( !feature.isValid() )
1021 feature = getFeature( fid );
1022
1023 int size = mFields.size();
1024 for ( int idx : std::as_const( mDefaultValueOnUpdateFields ) )
1025 {
1026 if ( idx < 0 || idx >= size )
1027 continue;
1028 feature.setAttribute( idx, defaultValue( idx, feature, context ) );
1029 updateFeature( feature, true );
1030 }
1031 }
1032}
1033
1035{
1037
1038 QgsRectangle rect;
1039 rect.setNull();
1040
1041 if ( !isSpatial() )
1042 return rect;
1043
1044 // Don't do lazy extent if the layer is currently in edit mode
1045 if ( mLazyExtent2D && isEditable() )
1046 mLazyExtent2D = false;
1047
1048 if ( mDataProvider && mDataProvider->isValid() && ( mDataProvider->flags() & Qgis::DataProviderFlag::FastExtent2D ) )
1049 {
1050 // Provider has a trivial 2D extent calculation => always get extent from provider.
1051 // Things are nice and simple this way, e.g. we can always trust that this extent is
1052 // accurate and up to date.
1053 updateExtent( mDataProvider->extent() );
1054 mValidExtent2D = true;
1055 mLazyExtent2D = false;
1056 }
1057 else
1058 {
1059 if ( !mValidExtent2D && mLazyExtent2D && mReadExtentFromXml && !mXmlExtent2D.isNull() )
1060 {
1061 updateExtent( mXmlExtent2D );
1062 mValidExtent2D = true;
1063 mLazyExtent2D = false;
1064 }
1065
1066 if ( !mValidExtent2D && mLazyExtent2D && mDataProvider && mDataProvider->isValid() )
1067 {
1068 // store the extent
1069 updateExtent( mDataProvider->extent() );
1070 mValidExtent2D = true;
1071 mLazyExtent2D = false;
1072
1073 // show the extent
1074 QgsDebugMsgLevel( QStringLiteral( "2D Extent of layer: %1" ).arg( mExtent2D.toString() ), 3 );
1075 }
1076 }
1077
1078 if ( mValidExtent2D )
1079 return QgsMapLayer::extent();
1080
1081 if ( !isValid() || !mDataProvider )
1082 {
1083 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
1084 return rect;
1085 }
1086
1087 if ( !mEditBuffer ||
1088 ( !mDataProvider->transaction() && ( mEditBuffer->deletedFeatureIds().isEmpty() && mEditBuffer->changedGeometries().isEmpty() ) ) ||
1090 {
1091 mDataProvider->updateExtents();
1092
1093 // get the extent of the layer from the provider
1094 // but only when there are some features already
1095 if ( mDataProvider->featureCount() != 0 )
1096 {
1097 const QgsRectangle r = mDataProvider->extent();
1098 rect.combineExtentWith( r );
1099 }
1100
1101 if ( mEditBuffer && !mDataProvider->transaction() )
1102 {
1103 const auto addedFeatures = mEditBuffer->addedFeatures();
1104 for ( QgsFeatureMap::const_iterator it = addedFeatures.constBegin(); it != addedFeatures.constEnd(); ++it )
1105 {
1106 if ( it->hasGeometry() )
1107 {
1108 const QgsRectangle r = it->geometry().boundingBox();
1109 rect.combineExtentWith( r );
1110 }
1111 }
1112 }
1113 }
1114 else
1115 {
1117 .setNoAttributes() );
1118
1119 QgsFeature fet;
1120 while ( fit.nextFeature( fet ) )
1121 {
1122 if ( fet.hasGeometry() && fet.geometry().type() != Qgis::GeometryType::Unknown )
1123 {
1124 const QgsRectangle bb = fet.geometry().boundingBox();
1125 rect.combineExtentWith( bb );
1126 }
1127 }
1128 }
1129
1130 if ( rect.xMinimum() > rect.xMaximum() && rect.yMinimum() > rect.yMaximum() )
1131 {
1132 // special case when there are no features in provider nor any added
1133 rect = QgsRectangle(); // use rectangle with zero coordinates
1134 }
1135
1136 updateExtent( rect );
1137 mValidExtent2D = true;
1138
1139 // Send this (hopefully) up the chain to the map canvas
1140 emit recalculateExtents();
1141
1142 return rect;
1143}
1144
1146{
1148
1149 // if data is 2D, redirect to 2D extend computation, and save it as 2D extent (in 3D bbox)
1150 if ( mDataProvider && mDataProvider->elevationProperties() && !mDataProvider->elevationProperties()->containsElevationData() )
1151 {
1152 return QgsBox3D( extent() );
1153 }
1154
1156 extent.setNull();
1157
1158 if ( !isSpatial() )
1159 return extent;
1160
1161 if ( mDataProvider && mDataProvider->isValid() && ( mDataProvider->flags() & Qgis::DataProviderFlag::FastExtent3D ) )
1162 {
1163 // Provider has a trivial 3D extent calculation => always get extent from provider.
1164 // Things are nice and simple this way, e.g. we can always trust that this extent is
1165 // accurate and up to date.
1166 updateExtent( mDataProvider->extent3D() );
1167 mValidExtent3D = true;
1168 mLazyExtent3D = false;
1169 }
1170 else
1171 {
1172 if ( !mValidExtent3D && mLazyExtent3D && mReadExtentFromXml && !mXmlExtent3D.isNull() )
1173 {
1174 updateExtent( mXmlExtent3D );
1175 mValidExtent3D = true;
1176 mLazyExtent3D = false;
1177 }
1178
1179 if ( !mValidExtent3D && mLazyExtent3D && mDataProvider && mDataProvider->isValid() )
1180 {
1181 // store the extent
1182 updateExtent( mDataProvider->extent3D() );
1183 mValidExtent3D = true;
1184 mLazyExtent3D = false;
1185
1186 // show the extent
1187 QgsDebugMsgLevel( QStringLiteral( "3D Extent of layer: %1" ).arg( mExtent3D.toString() ), 3 );
1188 }
1189 }
1190
1191 if ( mValidExtent3D )
1192 return QgsMapLayer::extent3D();
1193
1194 if ( !isValid() || !mDataProvider )
1195 {
1196 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
1197 return extent;
1198 }
1199
1200 if ( !mEditBuffer ||
1201 ( !mDataProvider->transaction() && ( mEditBuffer->deletedFeatureIds().isEmpty() && mEditBuffer->changedGeometries().isEmpty() ) ) ||
1203 {
1204 mDataProvider->updateExtents();
1205
1206 // get the extent of the layer from the provider
1207 // but only when there are some features already
1208 if ( mDataProvider->featureCount() != 0 )
1209 {
1210 const QgsBox3D ext = mDataProvider->extent3D();
1211 extent.combineWith( ext );
1212 }
1213
1214 if ( mEditBuffer && !mDataProvider->transaction() )
1215 {
1216 const auto addedFeatures = mEditBuffer->addedFeatures();
1217 for ( QgsFeatureMap::const_iterator it = addedFeatures.constBegin(); it != addedFeatures.constEnd(); ++it )
1218 {
1219 if ( it->hasGeometry() )
1220 {
1221 const QgsBox3D bbox = it->geometry().boundingBox3D();
1222 extent.combineWith( bbox );
1223 }
1224 }
1225 }
1226 }
1227 else
1228 {
1230 .setNoAttributes() );
1231
1232 QgsFeature fet;
1233 while ( fit.nextFeature( fet ) )
1234 {
1235 if ( fet.hasGeometry() && fet.geometry().type() != Qgis::GeometryType::Unknown )
1236 {
1237 const QgsBox3D bb = fet.geometry().boundingBox3D();
1238 extent.combineWith( bb );
1239 }
1240 }
1241 }
1242
1243 if ( extent.xMinimum() > extent.xMaximum() && extent.yMinimum() > extent.yMaximum() && extent.zMinimum() > extent.zMaximum() )
1244 {
1245 // special case when there are no features in provider nor any added
1246 extent = QgsBox3D(); // use rectangle with zero coordinates
1247 }
1248
1249 updateExtent( extent );
1250 mValidExtent3D = true;
1251
1252 // Send this (hopefully) up the chain to the map canvas
1253 emit recalculateExtents();
1254
1255 return extent;
1256}
1257
1264
1271
1273{
1275
1276 if ( !isValid() || !mDataProvider )
1277 {
1278 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
1279 return customProperty( QStringLiteral( "storedSubsetString" ) ).toString();
1280 }
1281 return mDataProvider->subsetString();
1282}
1283
1284bool QgsVectorLayer::setSubsetString( const QString &subset )
1285{
1287
1288 if ( !isValid() || !mDataProvider )
1289 {
1290 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider or while editing" ), 3 );
1291 setCustomProperty( QStringLiteral( "storedSubsetString" ), subset );
1292 return false;
1293 }
1294 else if ( mEditBuffer )
1295 {
1296 QgsDebugMsgLevel( QStringLiteral( "invoked while editing" ), 3 );
1297 return false;
1298 }
1299
1300 if ( subset == mDataProvider->subsetString() )
1301 return true;
1302
1303 bool res = mDataProvider->setSubsetString( subset );
1304
1305 // get the updated data source string from the provider
1306 mDataSource = mDataProvider->dataSourceUri();
1307 updateExtents();
1308 updateFields();
1309
1310 if ( res )
1311 {
1312 emit subsetStringChanged();
1314 }
1315
1316 return res;
1317}
1318
1320{
1321 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
1323
1324 if ( isValid() && mDataProvider && !mEditBuffer && ( isSpatial() && geometryType() != Qgis::GeometryType::Point ) && ( mSimplifyMethod.simplifyHints() & simplifyHint ) && renderContext.useRenderingOptimization() )
1325 {
1326 double maximumSimplificationScale = mSimplifyMethod.maximumScale();
1327
1328 // check maximum scale at which generalisation should be carried out
1329 return !( maximumSimplificationScale > 1 && renderContext.rendererScale() <= maximumSimplificationScale );
1330 }
1331 return false;
1332}
1333
1335{
1337
1338 return mConditionalStyles;
1339}
1340
1342{
1343 // non fatal for now -- the aggregate expression functions are not thread safe and call this
1345
1346 if ( !isValid() || !mDataProvider )
1347 return QgsFeatureIterator();
1348
1349 return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( new QgsVectorLayerFeatureSource( this ), true, request ) );
1350}
1351
1353{
1355
1356 QgsFeature feature;
1358 if ( feature.isValid() )
1359 return feature.geometry();
1360 else
1361 return QgsGeometry();
1362}
1363
1365{
1367
1368 if ( !isValid() || !mEditBuffer || !mDataProvider )
1369 return false;
1370
1371
1372 if ( mGeometryOptions->isActive() )
1373 {
1374 QgsGeometry geom = feature.geometry();
1375 mGeometryOptions->apply( geom );
1376 feature.setGeometry( geom );
1377 }
1378
1379 bool success = mEditBuffer->addFeature( feature );
1380
1381 if ( success && mJoinBuffer->containsJoins() )
1382 {
1383 success = mJoinBuffer->addFeature( feature );
1384 }
1385
1386 return success;
1387}
1388
1389bool QgsVectorLayer::updateFeature( QgsFeature &updatedFeature, bool skipDefaultValues )
1390{
1392
1393 if ( !mEditBuffer || !mDataProvider )
1394 {
1395 return false;
1396 }
1397
1398 QgsFeature currentFeature = getFeature( updatedFeature.id() );
1399 if ( currentFeature.isValid() )
1400 {
1401 bool hasChanged = false;
1402 bool hasError = false;
1403
1404 if ( ( updatedFeature.hasGeometry() || currentFeature.hasGeometry() ) && !updatedFeature.geometry().equals( currentFeature.geometry() ) )
1405 {
1406 QgsGeometry geometry = updatedFeature.geometry();
1407 if ( changeGeometry( updatedFeature.id(), geometry, true ) )
1408 {
1409 hasChanged = true;
1410 updatedFeature.setGeometry( geometry );
1411 }
1412 else
1413 {
1414 QgsDebugMsgLevel( QStringLiteral( "geometry of feature %1 could not be changed." ).arg( updatedFeature.id() ), 3 );
1415 }
1416 }
1417
1418 QgsAttributes fa = updatedFeature.attributes();
1419 QgsAttributes ca = currentFeature.attributes();
1420
1421 for ( int attr = 0; attr < fa.count(); ++attr )
1422 {
1423 if ( !qgsVariantEqual( fa.at( attr ), ca.at( attr ) ) )
1424 {
1425 if ( changeAttributeValue( updatedFeature.id(), attr, fa.at( attr ), ca.at( attr ), true ) )
1426 {
1427 hasChanged = true;
1428 }
1429 else
1430 {
1431 QgsDebugMsgLevel( QStringLiteral( "attribute %1 of feature %2 could not be changed." ).arg( attr ).arg( updatedFeature.id() ), 3 );
1432 hasError = true;
1433 }
1434 }
1435 }
1436 if ( hasChanged && !mDefaultValueOnUpdateFields.isEmpty() && !skipDefaultValues )
1437 updateDefaultValues( updatedFeature.id(), updatedFeature );
1438
1439 return !hasError;
1440 }
1441 else
1442 {
1443 QgsDebugMsgLevel( QStringLiteral( "feature %1 could not be retrieved" ).arg( updatedFeature.id() ), 3 );
1444 return false;
1445 }
1446}
1447
1448
1449bool QgsVectorLayer::insertVertex( double x, double y, QgsFeatureId atFeatureId, int beforeVertex )
1450{
1452
1453 if ( !isValid() || !mEditBuffer || !mDataProvider )
1454 return false;
1455
1456 QgsVectorLayerEditUtils utils( this );
1457 bool result = utils.insertVertex( x, y, atFeatureId, beforeVertex );
1458 if ( result )
1459 updateExtents();
1460 return result;
1461}
1462
1463
1464bool QgsVectorLayer::insertVertex( const QgsPoint &point, QgsFeatureId atFeatureId, int beforeVertex )
1465{
1467
1468 if ( !isValid() || !mEditBuffer || !mDataProvider )
1469 return false;
1470
1471 QgsVectorLayerEditUtils utils( this );
1472 bool result = utils.insertVertex( point, atFeatureId, beforeVertex );
1473 if ( result )
1474 updateExtents();
1475 return result;
1476}
1477
1478
1479bool QgsVectorLayer::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
1480{
1482
1483 if ( !isValid() || !mEditBuffer || !mDataProvider )
1484 return false;
1485
1486 QgsVectorLayerEditUtils utils( this );
1487 bool result = utils.moveVertex( x, y, atFeatureId, atVertex );
1488
1489 if ( result )
1490 updateExtents();
1491 return result;
1492}
1493
1494bool QgsVectorLayer::moveVertex( const QgsPoint &p, QgsFeatureId atFeatureId, int atVertex )
1495{
1497
1498 if ( !isValid() || !mEditBuffer || !mDataProvider )
1499 return false;
1500
1501 QgsVectorLayerEditUtils utils( this );
1502 bool result = utils.moveVertex( p, atFeatureId, atVertex );
1503
1504 if ( result )
1505 updateExtents();
1506 return result;
1507}
1508
1510{
1512
1513 if ( !isValid() || !mEditBuffer || !mDataProvider )
1515
1516 QgsVectorLayerEditUtils utils( this );
1517 Qgis::VectorEditResult result = utils.deleteVertex( featureId, vertex );
1518
1519 if ( result == Qgis::VectorEditResult::Success )
1520 updateExtents();
1521 return result;
1522}
1523
1524
1526{
1528
1529 if ( !isValid() || !mDataProvider || !( mDataProvider->capabilities() & Qgis::VectorProviderCapability::DeleteFeatures ) )
1530 {
1531 return false;
1532 }
1533
1534 if ( !isEditable() )
1535 {
1536 return false;
1537 }
1538
1539 int deleted = 0;
1540 int count = mSelectedFeatureIds.size();
1541 // Make a copy since deleteFeature modifies mSelectedFeatureIds
1542 QgsFeatureIds selectedFeatures( mSelectedFeatureIds );
1543 for ( QgsFeatureId fid : std::as_const( selectedFeatures ) )
1544 {
1545 deleted += deleteFeature( fid, context ); // removes from selection
1546 }
1547
1549 updateExtents();
1550
1551 if ( deletedCount )
1552 {
1553 *deletedCount = deleted;
1554 }
1555
1556 return deleted == count;
1557}
1558
1559static const QgsPointSequence vectorPointXY2pointSequence( const QVector<QgsPointXY> &points )
1560{
1561 QgsPointSequence pts;
1562 pts.reserve( points.size() );
1563 QVector<QgsPointXY>::const_iterator it = points.constBegin();
1564 while ( it != points.constEnd() )
1565 {
1566 pts.append( QgsPoint( *it ) );
1567 ++it;
1568 }
1569 return pts;
1570}
1571Qgis::GeometryOperationResult QgsVectorLayer::addRing( const QVector<QgsPointXY> &ring, QgsFeatureId *featureId )
1572{
1574
1575 return addRing( vectorPointXY2pointSequence( ring ), featureId );
1576}
1577
1579{
1581
1582 if ( !isValid() || !mEditBuffer || !mDataProvider )
1584
1585 QgsVectorLayerEditUtils utils( this );
1587
1588 //first try with selected features
1589 if ( !mSelectedFeatureIds.isEmpty() )
1590 {
1591 result = utils.addRing( ring, mSelectedFeatureIds, featureId );
1592 }
1593
1595 {
1596 //try with all intersecting features
1597 result = utils.addRing( ring, QgsFeatureIds(), featureId );
1598 }
1599
1600 return result;
1601}
1602
1604{
1606
1607 if ( !isValid() || !mEditBuffer || !mDataProvider )
1608 {
1609 delete ring;
1611 }
1612
1613 if ( !ring )
1614 {
1616 }
1617
1618 if ( !ring->isClosed() )
1619 {
1620 delete ring;
1622 }
1623
1624 QgsVectorLayerEditUtils utils( this );
1626
1627 //first try with selected features
1628 if ( !mSelectedFeatureIds.isEmpty() )
1629 {
1630 result = utils.addRing( static_cast< QgsCurve * >( ring->clone() ), mSelectedFeatureIds, featureId );
1631 }
1632
1634 {
1635 //try with all intersecting features
1636 result = utils.addRing( static_cast< QgsCurve * >( ring->clone() ), QgsFeatureIds(), featureId );
1637 }
1638
1639 delete ring;
1640 return result;
1641}
1642
1644{
1646
1647 QgsPointSequence pts;
1648 pts.reserve( points.size() );
1649 for ( QList<QgsPointXY>::const_iterator it = points.constBegin(); it != points.constEnd() ; ++it )
1650 {
1651 pts.append( QgsPoint( *it ) );
1652 }
1653 return addPart( pts );
1654}
1655
1656#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1657Qgis::GeometryOperationResult QgsVectorLayer::addPart( const QVector<QgsPointXY> &points )
1658{
1660
1661 return addPart( vectorPointXY2pointSequence( points ) );
1662}
1663#endif
1664
1666{
1668
1669 if ( !isValid() || !mEditBuffer || !mDataProvider )
1671
1672 //number of selected features must be 1
1673
1674 if ( mSelectedFeatureIds.empty() )
1675 {
1676 QgsDebugMsgLevel( QStringLiteral( "Number of selected features <1" ), 3 );
1678 }
1679 else if ( mSelectedFeatureIds.size() > 1 )
1680 {
1681 QgsDebugMsgLevel( QStringLiteral( "Number of selected features >1" ), 3 );
1683 }
1684
1685 QgsVectorLayerEditUtils utils( this );
1686 Qgis::GeometryOperationResult result = utils.addPart( points, *mSelectedFeatureIds.constBegin() );
1687
1689 updateExtents();
1690 return result;
1691}
1692
1694{
1696
1697 if ( !isValid() || !mEditBuffer || !mDataProvider )
1699
1700 //number of selected features must be 1
1701
1702 if ( mSelectedFeatureIds.empty() )
1703 {
1704 QgsDebugMsgLevel( QStringLiteral( "Number of selected features <1" ), 3 );
1706 }
1707 else if ( mSelectedFeatureIds.size() > 1 )
1708 {
1709 QgsDebugMsgLevel( QStringLiteral( "Number of selected features >1" ), 3 );
1711 }
1712
1713 QgsVectorLayerEditUtils utils( this );
1714 Qgis::GeometryOperationResult result = utils.addPart( ring, *mSelectedFeatureIds.constBegin() );
1715
1717 updateExtents();
1718 return result;
1719}
1720
1721// TODO QGIS 4.0 -- this should return Qgis::GeometryOperationResult, not int
1722int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double dy )
1723{
1725
1726 if ( !isValid() || !mEditBuffer || !mDataProvider )
1727 return static_cast< int >( Qgis::GeometryOperationResult::LayerNotEditable );
1728
1729 QgsVectorLayerEditUtils utils( this );
1730 int result = utils.translateFeature( featureId, dx, dy );
1731
1732 if ( result == static_cast< int >( Qgis::GeometryOperationResult::Success ) )
1733 updateExtents();
1734 return result;
1735}
1736
1737Qgis::GeometryOperationResult QgsVectorLayer::splitParts( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
1738{
1740
1741 return splitParts( vectorPointXY2pointSequence( splitLine ), topologicalEditing );
1742}
1743
1745{
1747
1748 if ( !isValid() || !mEditBuffer || !mDataProvider )
1750
1751 QgsVectorLayerEditUtils utils( this );
1752 return utils.splitParts( splitLine, topologicalEditing );
1753}
1754
1755Qgis::GeometryOperationResult QgsVectorLayer::splitFeatures( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
1756{
1758
1759 return splitFeatures( vectorPointXY2pointSequence( splitLine ), topologicalEditing );
1760}
1761
1763{
1765
1766 QgsLineString splitLineString( splitLine );
1767 QgsPointSequence topologyTestPoints;
1768 bool preserveCircular = false;
1769 return splitFeatures( &splitLineString, topologyTestPoints, preserveCircular, topologicalEditing );
1770}
1771
1772Qgis::GeometryOperationResult QgsVectorLayer::splitFeatures( const QgsCurve *curve, QgsPointSequence &topologyTestPoints, bool preserveCircular, bool topologicalEditing )
1773{
1775
1776 if ( !isValid() || !mEditBuffer || !mDataProvider )
1778
1779 QgsVectorLayerEditUtils utils( this );
1780 return utils.splitFeatures( curve, topologyTestPoints, preserveCircular, topologicalEditing );
1781}
1782
1784{
1786
1787 if ( !isValid() || !mEditBuffer || !mDataProvider )
1788 return -1;
1789
1790 QgsVectorLayerEditUtils utils( this );
1791 return utils.addTopologicalPoints( geom );
1792}
1793
1800
1802{
1804
1805 if ( !isValid() || !mEditBuffer || !mDataProvider )
1806 return -1;
1807
1808 QgsVectorLayerEditUtils utils( this );
1809 return utils.addTopologicalPoints( p );
1810}
1811
1813{
1815
1816 if ( !mValid || !mEditBuffer || !mDataProvider )
1817 return -1;
1818
1819 QgsVectorLayerEditUtils utils( this );
1820 return utils.addTopologicalPoints( ps );
1821}
1822
1824{
1826
1827 if ( mLabeling == labeling )
1828 return;
1829
1830 delete mLabeling;
1831 mLabeling = labeling;
1832}
1833
1835{
1837
1838 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
1839 return project()->startEditing( this );
1840
1841 if ( !isValid() || !mDataProvider )
1842 {
1843 return false;
1844 }
1845
1846 // allow editing if provider supports any of the capabilities
1847 if ( !supportsEditing() )
1848 {
1849 return false;
1850 }
1851
1852 if ( mEditBuffer )
1853 {
1854 // editing already underway
1855 return false;
1856 }
1857
1858 mDataProvider->enterUpdateMode();
1859
1860 emit beforeEditingStarted();
1861
1862 createEditBuffer();
1863
1864 updateFields();
1865
1866 emit editingStarted();
1867
1868 return true;
1869}
1870
1872{
1874
1875 if ( mDataProvider )
1876 mDataProvider->setTransformContext( transformContext );
1877}
1878
1885
1887{
1889
1890 if ( mRenderer )
1891 if ( !mRenderer->accept( visitor ) )
1892 return false;
1893
1894 if ( mLabeling )
1895 if ( !mLabeling->accept( visitor ) )
1896 return false;
1897
1898 return true;
1899}
1900
1901bool QgsVectorLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1902{
1904
1905 QgsDebugMsgLevel( QStringLiteral( "Datasource in QgsVectorLayer::readXml: %1" ).arg( mDataSource.toLocal8Bit().data() ), 3 );
1906
1907 //process provider key
1908 QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
1909
1910 if ( pkeyNode.isNull() )
1911 {
1912 mProviderKey.clear();
1913 }
1914 else
1915 {
1916 QDomElement pkeyElt = pkeyNode.toElement();
1917 mProviderKey = pkeyElt.text();
1918 }
1919
1920 // determine type of vector layer
1921 if ( !mProviderKey.isNull() )
1922 {
1923 // if the provider string isn't empty, then we successfully
1924 // got the stored provider
1925 }
1926 else if ( mDataSource.contains( QLatin1String( "dbname=" ) ) )
1927 {
1928 mProviderKey = QStringLiteral( "postgres" );
1929 }
1930 else
1931 {
1932 mProviderKey = QStringLiteral( "ogr" );
1933 }
1934
1935 const QDomElement elem = layer_node.toElement();
1937
1938 mDataSourceReadOnly = mReadFlags & QgsMapLayer::FlagForceReadOnly;
1940
1941 if ( ( mReadFlags & QgsMapLayer::FlagDontResolveLayers ) || !setDataProvider( mProviderKey, options, flags ) )
1942 {
1944 {
1945 QgsDebugError( QStringLiteral( "Could not set data provider for layer %1" ).arg( publicSource() ) );
1946 }
1947
1948 // for invalid layer sources, we fallback to stored wkbType if available
1949 if ( elem.hasAttribute( QStringLiteral( "wkbType" ) ) )
1950 mWkbType = qgsEnumKeyToValue( elem.attribute( QStringLiteral( "wkbType" ) ), mWkbType );
1951 }
1952
1953 QDomElement pkeyElem = pkeyNode.toElement();
1954 if ( !pkeyElem.isNull() )
1955 {
1956 QString encodingString = pkeyElem.attribute( QStringLiteral( "encoding" ) );
1957 if ( mDataProvider && !encodingString.isEmpty() )
1958 {
1959 mDataProvider->setEncoding( encodingString );
1960 }
1961 }
1962
1963 // load vector joins - does not resolve references to layers yet
1964 mJoinBuffer->readXml( layer_node );
1965
1966 updateFields();
1967
1968 // If style doesn't include a legend, we'll need to make a default one later...
1969 mSetLegendFromStyle = false;
1970
1971 QString errorMsg;
1972 if ( !readSymbology( layer_node, errorMsg, context ) )
1973 {
1974 return false;
1975 }
1976
1977 readStyleManager( layer_node );
1978
1979 QDomNode depsNode = layer_node.namedItem( QStringLiteral( "dataDependencies" ) );
1980 QDomNodeList depsNodes = depsNode.childNodes();
1981 QSet<QgsMapLayerDependency> sources;
1982 for ( int i = 0; i < depsNodes.count(); i++ )
1983 {
1984 QString source = depsNodes.at( i ).toElement().attribute( QStringLiteral( "id" ) );
1985 sources << QgsMapLayerDependency( source );
1986 }
1987 setDependencies( sources );
1988
1989 if ( !mSetLegendFromStyle )
1991
1992 // read extent
1994 {
1995 mReadExtentFromXml = true;
1996 }
1997 if ( mReadExtentFromXml )
1998 {
1999 const QDomNode extentNode = layer_node.namedItem( QStringLiteral( "extent" ) );
2000 if ( !extentNode.isNull() )
2001 {
2002 mXmlExtent2D = QgsXmlUtils::readRectangle( extentNode.toElement() );
2003 }
2004 const QDomNode extent3DNode = layer_node.namedItem( QStringLiteral( "extent3D" ) );
2005 if ( !extent3DNode.isNull() )
2006 {
2007 mXmlExtent3D = QgsXmlUtils::readBox3D( extent3DNode.toElement() );
2008 }
2009 }
2010
2011 // auxiliary layer
2012 const QDomNode asNode = layer_node.namedItem( QStringLiteral( "auxiliaryLayer" ) );
2013 const QDomElement asElem = asNode.toElement();
2014 if ( !asElem.isNull() )
2015 {
2016 mAuxiliaryLayerKey = asElem.attribute( QStringLiteral( "key" ) );
2017 }
2018
2019 // QGIS Server WMS Dimensions
2020 mServerProperties->readXml( layer_node );
2021
2022 return isValid(); // should be true if read successfully
2023
2024} // void QgsVectorLayer::readXml
2025
2026
2027void QgsVectorLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider,
2029{
2031
2032 Qgis::GeometryType geomType = geometryType();
2033
2034 mDataSource = dataSource;
2035 setName( baseName );
2036 setDataProvider( provider, options, flags );
2037
2038 if ( !isValid() )
2039 {
2040 return;
2041 }
2042
2043 // Always set crs
2045
2046 bool loadDefaultStyleFlag = false;
2048 {
2049 loadDefaultStyleFlag = true;
2050 }
2051
2052 // reset style if loading default style, style is missing, or geometry type is has changed (and layer is valid)
2053 if ( !renderer() || !legend() || ( isValid() && geomType != geometryType() ) || loadDefaultStyleFlag )
2054 {
2055 std::unique_ptr< QgsScopedRuntimeProfile > profile;
2056 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
2057 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Load layer style" ), QStringLiteral( "projectload" ) );
2058
2059 bool defaultLoadedFlag = false;
2060
2061 // defer style changed signal until we've set the renderer, labeling, everything.
2062 // we don't want multiple signals!
2063 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
2064
2065 // need to check whether the default style included a legend, and if not, we need to make a default legend
2066 // later...
2067 mSetLegendFromStyle = false;
2068
2069 // first check if there is a default style / propertysheet defined
2070 // for this layer and if so apply it
2071 // this should take precedence over all
2072 if ( !defaultLoadedFlag && loadDefaultStyleFlag )
2073 {
2074 loadDefaultStyle( defaultLoadedFlag );
2075 }
2076
2077 if ( loadDefaultStyleFlag && !defaultLoadedFlag && isSpatial() && mDataProvider->capabilities() & Qgis::VectorProviderCapability::CreateRenderer )
2078 {
2079 // if we didn't load a default style for this layer, try to create a renderer directly from the data provider
2080 std::unique_ptr< QgsFeatureRenderer > defaultRenderer( mDataProvider->createRenderer() );
2081 if ( defaultRenderer )
2082 {
2083 defaultLoadedFlag = true;
2084 setRenderer( defaultRenderer.release() );
2085 }
2086 }
2087
2088 // if the default style failed to load or was disabled use some very basic defaults
2089 if ( !defaultLoadedFlag )
2090 {
2091 // add single symbol renderer for spatial layers
2093 }
2094
2095 if ( !mSetLegendFromStyle )
2097
2099 {
2100 std::unique_ptr< QgsAbstractVectorLayerLabeling > defaultLabeling( mDataProvider->createLabeling() );
2101 if ( defaultLabeling )
2102 {
2103 setLabeling( defaultLabeling.release() );
2104 setLabelsEnabled( true );
2105 }
2106 }
2107
2108 styleChangedSignalBlocker.release();
2110 }
2111}
2112
2113QString QgsVectorLayer::loadDefaultStyle( bool &resultFlag )
2114{
2116
2117 // first try to load a user-defined default style - this should always take precedence
2118 QString styleXml = QgsMapLayer::loadDefaultStyle( resultFlag );
2119
2120 if ( resultFlag )
2121 {
2122 // Try to load all stored styles from DB
2123 if ( mLoadAllStoredStyle && mDataProvider && mDataProvider->styleStorageCapabilities().testFlag( Qgis::ProviderStyleStorageCapability::LoadFromDatabase ) )
2124 {
2125 QStringList ids, names, descriptions;
2126 QString errorMessage;
2127 // Get the number of styles related to current layer.
2128 const int relatedStylesCount { listStylesInDatabase( ids, names, descriptions, errorMessage ) };
2129 Q_ASSERT( ids.count() == names.count() );
2130 const QString currentStyleName { mStyleManager->currentStyle() };
2131 for ( int i = 0; i < relatedStylesCount; ++i )
2132 {
2133 if ( names.at( i ) == currentStyleName )
2134 {
2135 continue;
2136 }
2137 errorMessage.clear();
2138 const QString styleXml { getStyleFromDatabase( ids.at( i ), errorMessage ) };
2139 if ( ! styleXml.isEmpty() && errorMessage.isEmpty() )
2140 {
2141 mStyleManager->addStyle( names.at( i ), QgsMapLayerStyle( styleXml ) );
2142 }
2143 else
2144 {
2145 QgsDebugMsgLevel( QStringLiteral( "Error retrieving style %1 from DB: %2" ).arg( ids.at( i ), errorMessage ), 2 );
2146 }
2147 }
2148 }
2149 return styleXml ;
2150 }
2151
2153 {
2154 // otherwise try to create a renderer directly from the data provider
2155 std::unique_ptr< QgsFeatureRenderer > defaultRenderer( mDataProvider->createRenderer() );
2156 if ( defaultRenderer )
2157 {
2158 resultFlag = true;
2159 setRenderer( defaultRenderer.release() );
2160 return QString();
2161 }
2162 }
2163
2164 return QString();
2165}
2166
2167bool QgsVectorLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
2168{
2170
2171 mProviderKey = provider;
2172 delete mDataProvider;
2173
2174 // For Postgres provider primary key unicity is tested at construction time,
2175 // so it has to be set before initializing the provider,
2176 // this manipulation is necessary to preserve default behavior when
2177 // "trust layer metadata" project level option is set and checkPrimaryKeyUnicity
2178 // was not explicitly passed in the uri
2179 if ( provider.compare( QLatin1String( "postgres" ) ) == 0 )
2180 {
2181 const QString checkUnicityKey { QStringLiteral( "checkPrimaryKeyUnicity" ) };
2183 if ( ! uri.hasParam( checkUnicityKey ) )
2184 {
2185 uri.setParam( checkUnicityKey, mReadExtentFromXml ? "0" : "1" );
2186 mDataSource = uri.uri( false );
2187 }
2188 }
2189
2190 std::unique_ptr< QgsScopedRuntimeProfile > profile;
2191 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
2192 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), QStringLiteral( "projectload" ) );
2193
2194 if ( mPreloadedProvider )
2195 mDataProvider = qobject_cast< QgsVectorDataProvider * >( mPreloadedProvider.release() );
2196 else
2197 mDataProvider = qobject_cast<QgsVectorDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, mDataSource, options, flags ) );
2198
2199 if ( !mDataProvider )
2200 {
2201 setValid( false );
2202 QgsDebugMsgLevel( QStringLiteral( "Unable to get data provider" ), 2 );
2203 return false;
2204 }
2205
2206 mDataProvider->setParent( this );
2207 connect( mDataProvider, &QgsVectorDataProvider::raiseError, this, &QgsVectorLayer::raiseError );
2208
2209 QgsDebugMsgLevel( QStringLiteral( "Instantiated the data provider plugin" ), 2 );
2210
2211 setValid( mDataProvider->isValid() );
2212 if ( !isValid() )
2213 {
2214 QgsDebugMsgLevel( QStringLiteral( "Invalid provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
2215 return false;
2216 }
2217
2218 if ( profile )
2219 profile->switchTask( tr( "Read layer metadata" ) );
2221 {
2222 // we combine the provider metadata with the layer's existing metadata, so as not to reset any user customizations to the metadata
2223 // back to the default if a layer's data source is changed
2224 QgsLayerMetadata newMetadata = mDataProvider->layerMetadata();
2225 // this overwrites the provider metadata with any properties which are non-empty from the existing layer metadata
2226 newMetadata.combine( &mMetadata );
2227
2228 setMetadata( newMetadata );
2229 QgsDebugMsgLevel( QStringLiteral( "Set Data provider QgsLayerMetadata identifier[%1]" ).arg( metadata().identifier() ), 4 );
2230 }
2231
2232 // TODO: Check if the provider has the capability to send fullExtentCalculated
2233 connect( mDataProvider, &QgsVectorDataProvider::fullExtentCalculated, this, [this] { updateExtents(); } );
2234
2235 // get and store the feature type
2236 mWkbType = mDataProvider->wkbType();
2237
2238 // before we update the layer fields from the provider, we first copy any default set alias and
2239 // editor widget config from the data provider fields, if present
2240 const QgsFields providerFields = mDataProvider->fields();
2241 for ( const QgsField &field : providerFields )
2242 {
2243 // we only copy defaults from the provider if we aren't overriding any configuration made in the layer
2244 if ( !field.editorWidgetSetup().isNull() && mFieldWidgetSetups.value( field.name() ).isNull() )
2245 {
2246 mFieldWidgetSetups[ field.name() ] = field.editorWidgetSetup();
2247 }
2248 if ( !field.alias().isEmpty() && mAttributeAliasMap.value( field.name() ).isEmpty() )
2249 {
2250 mAttributeAliasMap[ field.name() ] = field.alias();
2251 }
2252 if ( !mAttributeSplitPolicy.contains( field.name() ) )
2253 {
2254 mAttributeSplitPolicy[ field.name() ] = field.splitPolicy();
2255 }
2256 if ( !mAttributeDuplicatePolicy.contains( field.name() ) )
2257 {
2258 mAttributeDuplicatePolicy[ field.name() ] = field.duplicatePolicy();
2259 }
2260 if ( !mAttributeMergePolicy.contains( field.name() ) )
2261 {
2262 mAttributeMergePolicy[ field.name() ] = field.mergePolicy();
2263 }
2264 }
2265
2266 if ( profile )
2267 profile->switchTask( tr( "Read layer fields" ) );
2268 updateFields();
2269
2270 if ( mProviderKey == QLatin1String( "postgres" ) )
2271 {
2272 // update datasource from data provider computed one
2273 mDataSource = mDataProvider->dataSourceUri( false );
2274
2275 QgsDebugMsgLevel( QStringLiteral( "Beautifying layer name %1" ).arg( name() ), 3 );
2276
2277 // adjust the display name for postgres layers
2278 const thread_local QRegularExpression reg( R"lit("[^"]+"\."([^"] + )"( \‍([^)]+\))?)lit" );
2279 const QRegularExpressionMatch match = reg.match( name() );
2280 if ( match.hasMatch() )
2281 {
2282 QStringList stuff = match.capturedTexts();
2283 QString lName = stuff[1];
2284
2285 const QMap<QString, QgsMapLayer *> &layers = QgsProject::instance()->mapLayers(); // skip-keyword-check
2286
2287 QMap<QString, QgsMapLayer *>::const_iterator it;
2288 for ( it = layers.constBegin(); it != layers.constEnd() && ( *it )->name() != lName; ++it )
2289 ;
2290
2291 if ( it != layers.constEnd() && stuff.size() > 2 )
2292 {
2293 lName += '.' + stuff[2].mid( 2, stuff[2].length() - 3 );
2294 }
2295
2296 if ( !lName.isEmpty() )
2297 setName( lName );
2298 }
2299 QgsDebugMsgLevel( QStringLiteral( "Beautified layer name %1" ).arg( name() ), 3 );
2300 }
2301 else if ( mProviderKey == QLatin1String( "osm" ) )
2302 {
2303 // make sure that the "observer" has been removed from URI to avoid crashes
2304 mDataSource = mDataProvider->dataSourceUri();
2305 }
2306 else if ( provider == QLatin1String( "ogr" ) )
2307 {
2308 // make sure that the /vsigzip or /vsizip is added to uri, if applicable
2309 mDataSource = mDataProvider->dataSourceUri();
2310 if ( mDataSource.right( 10 ) == QLatin1String( "|layerid=0" ) )
2311 mDataSource.chop( 10 );
2312 }
2313 else if ( provider == QLatin1String( "memory" ) )
2314 {
2315 // required so that source differs between memory layers
2316 mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
2317 }
2318 else if ( provider == QLatin1String( "hana" ) )
2319 {
2320 // update datasource from data provider computed one
2321 mDataSource = mDataProvider->dataSourceUri( false );
2322 }
2323
2324 connect( mDataProvider, &QgsVectorDataProvider::dataChanged, this, &QgsVectorLayer::emitDataChanged );
2326
2327 return true;
2328} // QgsVectorLayer:: setDataProvider
2329
2330
2331
2332
2333/* virtual */
2334bool QgsVectorLayer::writeXml( QDomNode &layer_node,
2335 QDomDocument &document,
2336 const QgsReadWriteContext &context ) const
2337{
2339
2340 // first get the layer element so that we can append the type attribute
2341
2342 QDomElement mapLayerNode = layer_node.toElement();
2343
2344 if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) )
2345 {
2346 QgsDebugMsgLevel( QStringLiteral( "can't find <maplayer>" ), 2 );
2347 return false;
2348 }
2349
2350 mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( Qgis::LayerType::Vector ) );
2351
2352 // set the geometry type
2353 mapLayerNode.setAttribute( QStringLiteral( "geometry" ), QgsWkbTypes::geometryDisplayString( geometryType() ) );
2354 mapLayerNode.setAttribute( QStringLiteral( "wkbType" ), qgsEnumValueToKey( wkbType() ) );
2355
2356 // add provider node
2357 if ( mDataProvider )
2358 {
2359 QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
2360 provider.setAttribute( QStringLiteral( "encoding" ), mDataProvider->encoding() );
2361 QDomText providerText = document.createTextNode( providerType() );
2362 provider.appendChild( providerText );
2363 layer_node.appendChild( provider );
2364 }
2365
2366 //save joins
2367 mJoinBuffer->writeXml( layer_node, document );
2368
2369 // dependencies
2370 QDomElement dependenciesElement = document.createElement( QStringLiteral( "layerDependencies" ) );
2371 const auto constDependencies = dependencies();
2372 for ( const QgsMapLayerDependency &dep : constDependencies )
2373 {
2375 continue;
2376 QDomElement depElem = document.createElement( QStringLiteral( "layer" ) );
2377 depElem.setAttribute( QStringLiteral( "id" ), dep.layerId() );
2378 dependenciesElement.appendChild( depElem );
2379 }
2380 layer_node.appendChild( dependenciesElement );
2381
2382 // change dependencies
2383 QDomElement dataDependenciesElement = document.createElement( QStringLiteral( "dataDependencies" ) );
2384 for ( const QgsMapLayerDependency &dep : constDependencies )
2385 {
2386 if ( dep.type() != QgsMapLayerDependency::DataDependency )
2387 continue;
2388 QDomElement depElem = document.createElement( QStringLiteral( "layer" ) );
2389 depElem.setAttribute( QStringLiteral( "id" ), dep.layerId() );
2390 dataDependenciesElement.appendChild( depElem );
2391 }
2392 layer_node.appendChild( dataDependenciesElement );
2393
2394 // save expression fields
2395 mExpressionFieldBuffer->writeXml( layer_node, document );
2396
2397 writeStyleManager( layer_node, document );
2398
2399 // auxiliary layer
2400 QDomElement asElem = document.createElement( QStringLiteral( "auxiliaryLayer" ) );
2401 if ( mAuxiliaryLayer )
2402 {
2403 const QString pkField = mAuxiliaryLayer->joinInfo().targetFieldName();
2404 asElem.setAttribute( QStringLiteral( "key" ), pkField );
2405 }
2406 layer_node.appendChild( asElem );
2407
2408 // renderer specific settings
2409 QString errorMsg;
2410 return writeSymbology( layer_node, document, errorMsg, context );
2411}
2412
2413QString QgsVectorLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
2414{
2416
2417 if ( providerType() == QLatin1String( "memory" ) )
2418 {
2419 // Refetch the source from the provider, because adding fields actually changes the source for this provider.
2420 return dataProvider()->dataSourceUri();
2421 }
2422
2424}
2425
2426QString QgsVectorLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
2427{
2429
2430 return QgsProviderRegistry::instance()->relativeToAbsoluteUri( provider, source, context );
2431}
2432
2433
2434
2442
2443
2444bool QgsVectorLayer::readSymbology( const QDomNode &layerNode, QString &errorMessage,
2446{
2448
2449 if ( categories.testFlag( Fields ) )
2450 {
2451 if ( !mExpressionFieldBuffer )
2452 mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
2453 mExpressionFieldBuffer->readXml( layerNode );
2454
2455 updateFields();
2456 }
2457
2458 if ( categories.testFlag( Relations ) )
2459 {
2460 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Relations" ) );
2461
2462 // Restore referenced layers: relations where "this" is the child layer (the referencing part, that holds the FK)
2463 QDomNodeList referencedLayersNodeList = layerNode.toElement().elementsByTagName( QStringLiteral( "referencedLayers" ) );
2464 if ( referencedLayersNodeList.size() > 0 )
2465 {
2466 const QDomNodeList relationNodes { referencedLayersNodeList.at( 0 ).childNodes() };
2467 for ( int i = 0; i < relationNodes.length(); ++i )
2468 {
2469 const QDomElement relationElement = relationNodes.at( i ).toElement();
2470
2471 mWeakRelations.push_back( QgsWeakRelation::readXml( this, QgsWeakRelation::Referencing, relationElement, context.pathResolver() ) );
2472 }
2473 }
2474
2475 // Restore referencing layers: relations where "this" is the parent layer (the referenced part where the FK points to)
2476 QDomNodeList referencingLayersNodeList = layerNode.toElement().elementsByTagName( QStringLiteral( "referencingLayers" ) );
2477 if ( referencingLayersNodeList.size() > 0 )
2478 {
2479 const QDomNodeList relationNodes { referencingLayersNodeList.at( 0 ).childNodes() };
2480 for ( int i = 0; i < relationNodes.length(); ++i )
2481 {
2482 const QDomElement relationElement = relationNodes.at( i ).toElement();
2483 mWeakRelations.push_back( QgsWeakRelation::readXml( this, QgsWeakRelation::Referenced, relationElement, context.pathResolver() ) );
2484 }
2485 }
2486 }
2487
2488 QDomElement layerElement = layerNode.toElement();
2489
2490 readCommonStyle( layerElement, context, categories );
2491
2492 readStyle( layerNode, errorMessage, context, categories );
2493
2494 if ( categories.testFlag( MapTips ) )
2495 {
2496 QDomElement mapTipElem = layerNode.namedItem( QStringLiteral( "mapTip" ) ).toElement();
2497 setMapTipTemplate( mapTipElem.text() );
2498 setMapTipsEnabled( mapTipElem.attribute( QStringLiteral( "enabled" ), QStringLiteral( "1" ) ).toInt() == 1 );
2499 }
2500
2501 if ( categories.testFlag( LayerConfiguration ) )
2502 mDisplayExpression = layerNode.namedItem( QStringLiteral( "previewExpression" ) ).toElement().text();
2503
2504 // Try to migrate pre QGIS 3.0 display field property
2505 QString displayField = layerNode.namedItem( QStringLiteral( "displayfield" ) ).toElement().text();
2506 if ( mFields.lookupField( displayField ) < 0 )
2507 {
2508 // if it's not a field, it's a maptip
2509 if ( mMapTipTemplate.isEmpty() && categories.testFlag( MapTips ) )
2510 mMapTipTemplate = displayField;
2511 }
2512 else
2513 {
2514 if ( mDisplayExpression.isEmpty() && categories.testFlag( LayerConfiguration ) )
2515 mDisplayExpression = QgsExpression::quotedColumnRef( displayField );
2516 }
2517
2518 // process the attribute actions
2519 if ( categories.testFlag( Actions ) )
2520 mActions->readXml( layerNode );
2521
2522 if ( categories.testFlag( Fields ) )
2523 {
2524 // IMPORTANT - we don't clear mAttributeAliasMap here, as it may contain aliases which are coming direct
2525 // from the data provider. Instead we leave any existing aliases and only overwrite them if the style
2526 // has a specific value for that field's alias
2527 QDomNode aliasesNode = layerNode.namedItem( QStringLiteral( "aliases" ) );
2528 if ( !aliasesNode.isNull() )
2529 {
2530 QDomElement aliasElem;
2531
2532 QDomNodeList aliasNodeList = aliasesNode.toElement().elementsByTagName( QStringLiteral( "alias" ) );
2533 for ( int i = 0; i < aliasNodeList.size(); ++i )
2534 {
2535 aliasElem = aliasNodeList.at( i ).toElement();
2536
2537 QString field;
2538 if ( aliasElem.hasAttribute( QStringLiteral( "field" ) ) )
2539 {
2540 field = aliasElem.attribute( QStringLiteral( "field" ) );
2541 }
2542 else
2543 {
2544 int index = aliasElem.attribute( QStringLiteral( "index" ) ).toInt();
2545
2546 if ( index >= 0 && index < fields().count() )
2547 field = fields().at( index ).name();
2548 }
2549
2550 QString alias;
2551
2552 if ( !aliasElem.attribute( QStringLiteral( "name" ) ).isEmpty() )
2553 {
2554 //if it has alias
2555 alias = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ), aliasElem.attribute( QStringLiteral( "name" ) ) );
2556 QgsDebugMsgLevel( "context" + QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ) + " source " + aliasElem.attribute( QStringLiteral( "name" ) ), 3 );
2557 }
2558 else
2559 {
2560 //if it has no alias, it should be the fields translation
2561 alias = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ), field );
2562 QgsDebugMsgLevel( "context" + QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ) + " source " + field, 3 );
2563 //if it gets the exact field value, there has been no translation (or not even translation loaded) - so no alias should be generated;
2564 if ( alias == aliasElem.attribute( QStringLiteral( "field" ) ) )
2565 alias.clear();
2566 }
2567
2568 QgsDebugMsgLevel( "field " + field + " origalias " + aliasElem.attribute( QStringLiteral( "name" ) ) + " trans " + alias, 3 );
2569 mAttributeAliasMap.insert( field, alias );
2570 }
2571 }
2572
2573 // IMPORTANT - we don't clear mAttributeSplitPolicy here, as it may contain policies which are coming direct
2574 // from the data provider. Instead we leave any existing policies and only overwrite them if the style
2575 // has a specific value for that field's policy
2576 const QDomNode splitPoliciesNode = layerNode.namedItem( QStringLiteral( "splitPolicies" ) );
2577 if ( !splitPoliciesNode.isNull() )
2578 {
2579 const QDomNodeList splitPolicyNodeList = splitPoliciesNode.toElement().elementsByTagName( QStringLiteral( "policy" ) );
2580 for ( int i = 0; i < splitPolicyNodeList.size(); ++i )
2581 {
2582 const QDomElement splitPolicyElem = splitPolicyNodeList.at( i ).toElement();
2583 const QString field = splitPolicyElem.attribute( QStringLiteral( "field" ) );
2584 const Qgis::FieldDomainSplitPolicy policy = qgsEnumKeyToValue( splitPolicyElem.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDomainSplitPolicy::Duplicate );
2585 mAttributeSplitPolicy.insert( field, policy );
2586 }
2587 }
2588
2589 // The duplicate policy is - unlike alias and split policy - never defined by the data provider, so we clear the map
2590 mAttributeDuplicatePolicy.clear();
2591 const QDomNode duplicatePoliciesNode = layerNode.namedItem( QStringLiteral( "duplicatePolicies" ) );
2592 if ( !duplicatePoliciesNode.isNull() )
2593 {
2594 const QDomNodeList duplicatePolicyNodeList = duplicatePoliciesNode.toElement().elementsByTagName( QStringLiteral( "policy" ) );
2595 for ( int i = 0; i < duplicatePolicyNodeList.size(); ++i )
2596 {
2597 const QDomElement duplicatePolicyElem = duplicatePolicyNodeList.at( i ).toElement();
2598 const QString field = duplicatePolicyElem.attribute( QStringLiteral( "field" ) );
2599 const Qgis::FieldDuplicatePolicy policy = qgsEnumKeyToValue( duplicatePolicyElem.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDuplicatePolicy::Duplicate );
2600 mAttributeDuplicatePolicy.insert( field, policy );
2601 }
2602 }
2603
2604 const QDomNode mergePoliciesNode = layerNode.namedItem( QStringLiteral( "mergePolicies" ) );
2605 if ( !mergePoliciesNode.isNull() )
2606 {
2607 const QDomNodeList mergePolicyNodeList = mergePoliciesNode.toElement().elementsByTagName( QStringLiteral( "policy" ) );
2608 for ( int i = 0; i < mergePolicyNodeList.size(); ++i )
2609 {
2610 const QDomElement mergePolicyElem = mergePolicyNodeList.at( i ).toElement();
2611 const QString field = mergePolicyElem.attribute( QStringLiteral( "field" ) );
2612 const Qgis::FieldDomainMergePolicy policy = qgsEnumKeyToValue( mergePolicyElem.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDomainMergePolicy::UnsetField );
2613 mAttributeMergePolicy.insert( field, policy );
2614 }
2615 }
2616
2617 // default expressions
2618 mDefaultExpressionMap.clear();
2619 QDomNode defaultsNode = layerNode.namedItem( QStringLiteral( "defaults" ) );
2620 if ( !defaultsNode.isNull() )
2621 {
2622 QDomNodeList defaultNodeList = defaultsNode.toElement().elementsByTagName( QStringLiteral( "default" ) );
2623 for ( int i = 0; i < defaultNodeList.size(); ++i )
2624 {
2625 QDomElement defaultElem = defaultNodeList.at( i ).toElement();
2626
2627 QString field = defaultElem.attribute( QStringLiteral( "field" ), QString() );
2628 QString expression = defaultElem.attribute( QStringLiteral( "expression" ), QString() );
2629 bool applyOnUpdate = defaultElem.attribute( QStringLiteral( "applyOnUpdate" ), QStringLiteral( "0" ) ) == QLatin1String( "1" );
2630 if ( field.isEmpty() || expression.isEmpty() )
2631 continue;
2632
2633 mDefaultExpressionMap.insert( field, QgsDefaultValue( expression, applyOnUpdate ) );
2634 }
2635 }
2636
2637 // constraints
2638 mFieldConstraints.clear();
2639 mFieldConstraintStrength.clear();
2640 QDomNode constraintsNode = layerNode.namedItem( QStringLiteral( "constraints" ) );
2641 if ( !constraintsNode.isNull() )
2642 {
2643 QDomNodeList constraintNodeList = constraintsNode.toElement().elementsByTagName( QStringLiteral( "constraint" ) );
2644 for ( int i = 0; i < constraintNodeList.size(); ++i )
2645 {
2646 QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2647
2648 QString field = constraintElem.attribute( QStringLiteral( "field" ), QString() );
2649 int constraints = constraintElem.attribute( QStringLiteral( "constraints" ), QStringLiteral( "0" ) ).toInt();
2650 if ( field.isEmpty() || constraints == 0 )
2651 continue;
2652
2653 mFieldConstraints.insert( field, static_cast< QgsFieldConstraints::Constraints >( constraints ) );
2654
2655 int uniqueStrength = constraintElem.attribute( QStringLiteral( "unique_strength" ), QStringLiteral( "1" ) ).toInt();
2656 int notNullStrength = constraintElem.attribute( QStringLiteral( "notnull_strength" ), QStringLiteral( "1" ) ).toInt();
2657 int expStrength = constraintElem.attribute( QStringLiteral( "exp_strength" ), QStringLiteral( "1" ) ).toInt();
2658
2659 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintUnique ), static_cast< QgsFieldConstraints::ConstraintStrength >( uniqueStrength ) );
2660 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintNotNull ), static_cast< QgsFieldConstraints::ConstraintStrength >( notNullStrength ) );
2661 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintExpression ), static_cast< QgsFieldConstraints::ConstraintStrength >( expStrength ) );
2662 }
2663 }
2664 mFieldConstraintExpressions.clear();
2665 QDomNode constraintExpressionsNode = layerNode.namedItem( QStringLiteral( "constraintExpressions" ) );
2666 if ( !constraintExpressionsNode.isNull() )
2667 {
2668 QDomNodeList constraintNodeList = constraintExpressionsNode.toElement().elementsByTagName( QStringLiteral( "constraint" ) );
2669 for ( int i = 0; i < constraintNodeList.size(); ++i )
2670 {
2671 QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2672
2673 QString field = constraintElem.attribute( QStringLiteral( "field" ), QString() );
2674 QString exp = constraintElem.attribute( QStringLiteral( "exp" ), QString() );
2675 QString desc = constraintElem.attribute( QStringLiteral( "desc" ), QString() );
2676 if ( field.isEmpty() || exp.isEmpty() )
2677 continue;
2678
2679 mFieldConstraintExpressions.insert( field, qMakePair( exp, desc ) );
2680 }
2681 }
2682
2683 updateFields();
2684 }
2685
2686 // load field configuration
2687 if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
2688 {
2689 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Forms" ) );
2690
2691 QDomElement widgetsElem = layerNode.namedItem( QStringLiteral( "fieldConfiguration" ) ).toElement();
2692 QDomNodeList fieldConfigurationElementList = widgetsElem.elementsByTagName( QStringLiteral( "field" ) );
2693 for ( int i = 0; i < fieldConfigurationElementList.size(); ++i )
2694 {
2695 const QDomElement fieldConfigElement = fieldConfigurationElementList.at( i ).toElement();
2696 const QDomElement fieldWidgetElement = fieldConfigElement.elementsByTagName( QStringLiteral( "editWidget" ) ).at( 0 ).toElement();
2697
2698 QString fieldName = fieldConfigElement.attribute( QStringLiteral( "name" ) );
2699
2700 if ( categories.testFlag( Fields ) )
2701 mFieldConfigurationFlags[fieldName] = qgsFlagKeysToValue( fieldConfigElement.attribute( QStringLiteral( "configurationFlags" ) ), Qgis::FieldConfigurationFlag::NoFlag );
2702
2703 // load editor widget configuration
2704 if ( categories.testFlag( Forms ) )
2705 {
2706 const QString widgetType = fieldWidgetElement.attribute( QStringLiteral( "type" ) );
2707 const QDomElement cfgElem = fieldConfigElement.elementsByTagName( QStringLiteral( "config" ) ).at( 0 ).toElement();
2708 const QDomElement optionsElem = cfgElem.childNodes().at( 0 ).toElement();
2709 QVariantMap optionsMap = QgsXmlUtils::readVariant( optionsElem ).toMap();
2710 // translate widget configuration strings
2711 if ( widgetType == QStringLiteral( "ValueRelation" ) )
2712 {
2713 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() );
2714 }
2715 if ( widgetType == QStringLiteral( "ValueMap" ) )
2716 {
2717 if ( optionsMap[ QStringLiteral( "map" ) ].canConvert<QList<QVariant>>() )
2718 {
2719 QList<QVariant> translatedValueList;
2720 const QList<QVariant> valueList = optionsMap[ QStringLiteral( "map" )].toList();
2721 for ( int i = 0, row = 0; i < valueList.count(); i++, row++ )
2722 {
2723 QMap<QString, QVariant> translatedValueMap;
2724 QString translatedKey = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fields:%2:valuemapdescriptions" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text(), fieldName ), valueList[i].toMap().constBegin().key() );
2725 translatedValueMap.insert( translatedKey, valueList[i].toMap().constBegin().value() );
2726 translatedValueList.append( translatedValueMap );
2727 }
2728 optionsMap.insert( QStringLiteral( "map" ), translatedValueList );
2729 }
2730 }
2731 QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( widgetType, optionsMap );
2732 mFieldWidgetSetups[fieldName] = setup;
2733 }
2734 }
2735 }
2736
2737 // Legacy reading for QGIS 3.14 and older projects
2738 // Attributes excluded from WMS and WFS
2739 if ( categories.testFlag( Fields ) )
2740 {
2741 const QList<QPair<QString, Qgis::FieldConfigurationFlag>> legacyConfig
2742 {
2743 qMakePair( QStringLiteral( "excludeAttributesWMS" ), Qgis::FieldConfigurationFlag::HideFromWms ),
2744 qMakePair( QStringLiteral( "excludeAttributesWFS" ), Qgis::FieldConfigurationFlag::HideFromWfs )
2745 };
2746 for ( const auto &config : legacyConfig )
2747 {
2748 QDomNode excludeNode = layerNode.namedItem( config.first );
2749 if ( !excludeNode.isNull() )
2750 {
2751 QDomNodeList attributeNodeList = excludeNode.toElement().elementsByTagName( QStringLiteral( "attribute" ) );
2752 for ( int i = 0; i < attributeNodeList.size(); ++i )
2753 {
2754 QString fieldName = attributeNodeList.at( i ).toElement().text();
2755 if ( !mFieldConfigurationFlags.contains( fieldName ) )
2756 mFieldConfigurationFlags[fieldName] = config.second;
2757 else
2758 mFieldConfigurationFlags[fieldName].setFlag( config.second, true );
2759 }
2760 }
2761 }
2762 }
2763
2764 if ( categories.testFlag( GeometryOptions ) )
2765 mGeometryOptions->readXml( layerNode.namedItem( QStringLiteral( "geometryOptions" ) ) );
2766
2767 if ( categories.testFlag( Forms ) )
2768 mEditFormConfig.readXml( layerNode, context );
2769
2770 if ( categories.testFlag( AttributeTable ) )
2771 {
2772 mAttributeTableConfig.readXml( layerNode );
2773 mConditionalStyles->readXml( layerNode, context );
2774 mStoredExpressionManager->readXml( layerNode );
2775 }
2776
2777 if ( categories.testFlag( CustomProperties ) )
2778 readCustomProperties( layerNode, QStringLiteral( "variable" ) );
2779
2780 QDomElement mapLayerNode = layerNode.toElement();
2781 if ( categories.testFlag( LayerConfiguration )
2782 && mapLayerNode.attribute( QStringLiteral( "readOnly" ), QStringLiteral( "0" ) ).toInt() == 1 )
2783 mReadOnly = true;
2784
2785 updateFields();
2786
2787 if ( categories.testFlag( Legend ) )
2788 {
2789 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Legend" ) );
2790
2791 const QDomElement legendElem = layerNode.firstChildElement( QStringLiteral( "legend" ) );
2792 if ( !legendElem.isNull() )
2793 {
2794 std::unique_ptr< QgsMapLayerLegend > legend( QgsMapLayerLegend::defaultVectorLegend( this ) );
2795 legend->readXml( legendElem, context );
2796 setLegend( legend.release() );
2797 mSetLegendFromStyle = true;
2798 }
2799 }
2800
2801 return true;
2802}
2803
2804bool QgsVectorLayer::readStyle( const QDomNode &node, QString &errorMessage,
2806{
2808
2809 bool result = true;
2810 emit readCustomSymbology( node.toElement(), errorMessage );
2811
2812 // we must try to restore a renderer if our geometry type is unknown
2813 // as this allows the renderer to be correctly restored even for layers
2814 // with broken sources
2815 if ( isSpatial() || mWkbType == Qgis::WkbType::Unknown )
2816 {
2817 // defer style changed signal until we've set the renderer, labeling, everything.
2818 // we don't want multiple signals!
2819 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
2820
2821 // try renderer v2 first
2822 if ( categories.testFlag( Symbology ) )
2823 {
2824 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Symbology" ) );
2825
2826 QDomElement rendererElement = node.firstChildElement( RENDERER_TAG_NAME );
2827 if ( !rendererElement.isNull() )
2828 {
2829 QgsFeatureRenderer *r = QgsFeatureRenderer::load( rendererElement, context );
2830 if ( r )
2831 {
2832 setRenderer( r );
2833 }
2834 else
2835 {
2836 result = false;
2837 }
2838 }
2839 // make sure layer has a renderer - if none exists, fallback to a default renderer
2840 if ( isSpatial() && !renderer() )
2841 {
2843 }
2844
2845 if ( mSelectionProperties )
2846 mSelectionProperties->readXml( node.toElement(), context );
2847 }
2848
2849 // read labeling definition
2850 if ( categories.testFlag( Labeling ) )
2851 {
2852 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Labeling" ) );
2853
2854 QDomElement labelingElement = node.firstChildElement( QStringLiteral( "labeling" ) );
2856 if ( labelingElement.isNull() ||
2857 ( labelingElement.attribute( QStringLiteral( "type" ) ) == QLatin1String( "simple" ) && labelingElement.firstChildElement( QStringLiteral( "settings" ) ).isNull() ) )
2858 {
2859 // make sure we have custom properties for labeling for 2.x projects
2860 // (custom properties should be already loaded when reading the whole layer from XML,
2861 // but when reading style, custom properties are not read)
2862 readCustomProperties( node, QStringLiteral( "labeling" ) );
2863
2864 // support for pre-QGIS 3 labeling configurations written in custom properties
2865 labeling = readLabelingFromCustomProperties();
2866 }
2867 else
2868 {
2869 labeling = QgsAbstractVectorLayerLabeling::create( labelingElement, context );
2870 }
2872
2873 if ( node.toElement().hasAttribute( QStringLiteral( "labelsEnabled" ) ) )
2874 mLabelsEnabled = node.toElement().attribute( QStringLiteral( "labelsEnabled" ) ).toInt();
2875 else
2876 mLabelsEnabled = true;
2877 }
2878
2879 if ( categories.testFlag( Symbology ) )
2880 {
2881 // get and set the blend mode if it exists
2882 QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
2883 if ( !blendModeNode.isNull() )
2884 {
2885 QDomElement e = blendModeNode.toElement();
2886 setBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
2887 }
2888
2889 // get and set the feature blend mode if it exists
2890 QDomNode featureBlendModeNode = node.namedItem( QStringLiteral( "featureBlendMode" ) );
2891 if ( !featureBlendModeNode.isNull() )
2892 {
2893 QDomElement e = featureBlendModeNode.toElement();
2894 setFeatureBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
2895 }
2896 }
2897
2898 // get and set the layer transparency and scale visibility if they exists
2899 if ( categories.testFlag( Rendering ) )
2900 {
2901 QDomNode layerTransparencyNode = node.namedItem( QStringLiteral( "layerTransparency" ) );
2902 if ( !layerTransparencyNode.isNull() )
2903 {
2904 QDomElement e = layerTransparencyNode.toElement();
2905 setOpacity( 1.0 - e.text().toInt() / 100.0 );
2906 }
2907 QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
2908 if ( !layerOpacityNode.isNull() )
2909 {
2910 QDomElement e = layerOpacityNode.toElement();
2911 setOpacity( e.text().toDouble() );
2912 }
2913
2914 const bool hasScaleBasedVisibiliy { node.attributes().namedItem( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).nodeValue() == '1' };
2915 setScaleBasedVisibility( hasScaleBasedVisibiliy );
2916 bool ok;
2917 const double maxScale { node.attributes().namedItem( QStringLiteral( "maxScale" ) ).nodeValue().toDouble( &ok ) };
2918 if ( ok )
2919 {
2920 setMaximumScale( maxScale );
2921 }
2922 const double minScale { node.attributes().namedItem( QStringLiteral( "minScale" ) ).nodeValue().toDouble( &ok ) };
2923 if ( ok )
2924 {
2925 setMinimumScale( minScale );
2926 }
2927
2928 QDomElement e = node.toElement();
2929
2930 // get the simplification drawing settings
2931 mSimplifyMethod.setSimplifyHints( static_cast< Qgis::VectorRenderingSimplificationFlags >( e.attribute( QStringLiteral( "simplifyDrawingHints" ), QStringLiteral( "1" ) ).toInt() ) );
2932 mSimplifyMethod.setSimplifyAlgorithm( static_cast< Qgis::VectorSimplificationAlgorithm >( e.attribute( QStringLiteral( "simplifyAlgorithm" ), QStringLiteral( "0" ) ).toInt() ) );
2933 mSimplifyMethod.setThreshold( e.attribute( QStringLiteral( "simplifyDrawingTol" ), QStringLiteral( "1" ) ).toFloat() );
2934 mSimplifyMethod.setForceLocalOptimization( e.attribute( QStringLiteral( "simplifyLocal" ), QStringLiteral( "1" ) ).toInt() );
2935 mSimplifyMethod.setMaximumScale( e.attribute( QStringLiteral( "simplifyMaxScale" ), QStringLiteral( "1" ) ).toFloat() );
2936
2937 if ( mRenderer )
2938 mRenderer->setReferenceScale( e.attribute( QStringLiteral( "symbologyReferenceScale" ), QStringLiteral( "-1" ) ).toDouble() );
2939 }
2940
2941 //diagram renderer and diagram layer settings
2942 if ( categories.testFlag( Diagrams ) )
2943 {
2944 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Diagrams" ) );
2945
2946 delete mDiagramRenderer;
2947 mDiagramRenderer = nullptr;
2948 QDomElement singleCatDiagramElem = node.firstChildElement( QStringLiteral( "SingleCategoryDiagramRenderer" ) );
2949 if ( !singleCatDiagramElem.isNull() )
2950 {
2951 mDiagramRenderer = new QgsSingleCategoryDiagramRenderer();
2952 mDiagramRenderer->readXml( singleCatDiagramElem, context );
2953 }
2954 QDomElement linearDiagramElem = node.firstChildElement( QStringLiteral( "LinearlyInterpolatedDiagramRenderer" ) );
2955 if ( !linearDiagramElem.isNull() )
2956 {
2957 if ( linearDiagramElem.hasAttribute( QStringLiteral( "classificationAttribute" ) ) )
2958 {
2959 // fix project from before QGIS 3.0
2960 int idx = linearDiagramElem.attribute( QStringLiteral( "classificationAttribute" ) ).toInt();
2961 if ( idx >= 0 && idx < mFields.count() )
2962 linearDiagramElem.setAttribute( QStringLiteral( "classificationField" ), mFields.at( idx ).name() );
2963 }
2964
2965 mDiagramRenderer = new QgsLinearlyInterpolatedDiagramRenderer();
2966 mDiagramRenderer->readXml( linearDiagramElem, context );
2967 }
2968 QDomElement stackedDiagramElem = node.firstChildElement( QStringLiteral( "StackedDiagramRenderer" ) );
2969 if ( !stackedDiagramElem.isNull() )
2970 {
2971 mDiagramRenderer = new QgsStackedDiagramRenderer();
2972 mDiagramRenderer->readXml( stackedDiagramElem, context );
2973 }
2974
2975 if ( mDiagramRenderer )
2976 {
2977 QDomElement diagramSettingsElem = node.firstChildElement( QStringLiteral( "DiagramLayerSettings" ) );
2978 if ( !diagramSettingsElem.isNull() )
2979 {
2980 bool oldXPos = diagramSettingsElem.hasAttribute( QStringLiteral( "xPosColumn" ) );
2981 bool oldYPos = diagramSettingsElem.hasAttribute( QStringLiteral( "yPosColumn" ) );
2982 bool oldShow = diagramSettingsElem.hasAttribute( QStringLiteral( "showColumn" ) );
2983 if ( oldXPos || oldYPos || oldShow )
2984 {
2985 // fix project from before QGIS 3.0
2987 if ( oldXPos )
2988 {
2989 int xPosColumn = diagramSettingsElem.attribute( QStringLiteral( "xPosColumn" ) ).toInt();
2990 if ( xPosColumn >= 0 && xPosColumn < mFields.count() )
2992 }
2993 if ( oldYPos )
2994 {
2995 int yPosColumn = diagramSettingsElem.attribute( QStringLiteral( "yPosColumn" ) ).toInt();
2996 if ( yPosColumn >= 0 && yPosColumn < mFields.count() )
2998 }
2999 if ( oldShow )
3000 {
3001 int showColumn = diagramSettingsElem.attribute( QStringLiteral( "showColumn" ) ).toInt();
3002 if ( showColumn >= 0 && showColumn < mFields.count() )
3003 ddp.setProperty( QgsDiagramLayerSettings::Property::Show, QgsProperty::fromField( mFields.at( showColumn ).name(), true ) );
3004 }
3005 QDomElement propertiesElem = diagramSettingsElem.ownerDocument().createElement( QStringLiteral( "properties" ) );
3007 {
3008 { static_cast< int >( QgsDiagramLayerSettings::Property::PositionX ), QgsPropertyDefinition( "positionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double ) },
3009 { static_cast< int >( QgsDiagramLayerSettings::Property::PositionY ), QgsPropertyDefinition( "positionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double ) },
3010 { static_cast< int >( QgsDiagramLayerSettings::Property::Show ), QgsPropertyDefinition( "show", QObject::tr( "Show diagram" ), QgsPropertyDefinition::Boolean ) },
3011 };
3012 ddp.writeXml( propertiesElem, defs );
3013 diagramSettingsElem.appendChild( propertiesElem );
3014 }
3015
3016 delete mDiagramLayerSettings;
3017 mDiagramLayerSettings = new QgsDiagramLayerSettings();
3018 mDiagramLayerSettings->readXml( diagramSettingsElem );
3019 }
3020 }
3021 }
3022 // end diagram
3023
3024 styleChangedSignalBlocker.release();
3026 }
3027 return result;
3028}
3029
3030
3031bool QgsVectorLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
3032 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
3033{
3035
3036 QDomElement layerElement = node.toElement();
3037 writeCommonStyle( layerElement, doc, context, categories );
3038
3039 ( void )writeStyle( node, doc, errorMessage, context, categories );
3040
3041 if ( categories.testFlag( GeometryOptions ) )
3042 mGeometryOptions->writeXml( node );
3043
3044 if ( categories.testFlag( Legend ) && legend() )
3045 {
3046 QDomElement legendElement = legend()->writeXml( doc, context );
3047 if ( !legendElement.isNull() )
3048 node.appendChild( legendElement );
3049 }
3050
3051 // Relation information for both referenced and referencing sides
3052 if ( categories.testFlag( Relations ) )
3053 {
3054 if ( QgsProject *p = project() )
3055 {
3056 // Store referenced layers: relations where "this" is the child layer (the referencing part, that holds the FK)
3057 QDomElement referencedLayersElement = doc.createElement( QStringLiteral( "referencedLayers" ) );
3058 node.appendChild( referencedLayersElement );
3059
3060 const QList<QgsRelation> referencingRelations { p->relationManager()->referencingRelations( this ) };
3061 for ( const QgsRelation &rel : referencingRelations )
3062 {
3063 switch ( rel.type() )
3064 {
3066 QgsWeakRelation::writeXml( this, QgsWeakRelation::Referencing, rel, referencedLayersElement, doc );
3067 break;
3069 break;
3070 }
3071 }
3072
3073 // Store referencing layers: relations where "this" is the parent layer (the referenced part, that holds the FK)
3074 QDomElement referencingLayersElement = doc.createElement( QStringLiteral( "referencingLayers" ) );
3075 node.appendChild( referencedLayersElement );
3076
3077 const QList<QgsRelation> referencedRelations { p->relationManager()->referencedRelations( this ) };
3078 for ( const QgsRelation &rel : referencedRelations )
3079 {
3080 switch ( rel.type() )
3081 {
3083 QgsWeakRelation::writeXml( this, QgsWeakRelation::Referenced, rel, referencingLayersElement, doc );
3084 break;
3086 break;
3087 }
3088 }
3089 }
3090 }
3091
3092 // write field configurations
3093 if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
3094 {
3095 QDomElement fieldConfigurationElement;
3096 // field configuration flag
3097 fieldConfigurationElement = doc.createElement( QStringLiteral( "fieldConfiguration" ) );
3098 node.appendChild( fieldConfigurationElement );
3099
3100 for ( const QgsField &field : std::as_const( mFields ) )
3101 {
3102 QDomElement fieldElement = doc.createElement( QStringLiteral( "field" ) );
3103 fieldElement.setAttribute( QStringLiteral( "name" ), field.name() );
3104 fieldConfigurationElement.appendChild( fieldElement );
3105
3106 if ( categories.testFlag( Fields ) )
3107 {
3108 fieldElement.setAttribute( QStringLiteral( "configurationFlags" ), qgsFlagValueToKeys( field.configurationFlags() ) );
3109 }
3110
3111 if ( categories.testFlag( Forms ) )
3112 {
3113 QgsEditorWidgetSetup widgetSetup = field.editorWidgetSetup();
3114
3115 // TODO : wrap this part in an if to only save if it was user-modified
3116 QDomElement editWidgetElement = doc.createElement( QStringLiteral( "editWidget" ) );
3117 fieldElement.appendChild( editWidgetElement );
3118 editWidgetElement.setAttribute( QStringLiteral( "type" ), field.editorWidgetSetup().type() );
3119 QDomElement editWidgetConfigElement = doc.createElement( QStringLiteral( "config" ) );
3120
3121 editWidgetConfigElement.appendChild( QgsXmlUtils::writeVariant( widgetSetup.config(), doc ) );
3122 editWidgetElement.appendChild( editWidgetConfigElement );
3123 // END TODO : wrap this part in an if to only save if it was user-modified
3124 }
3125 }
3126 }
3127
3128 if ( categories.testFlag( Fields ) )
3129 {
3130 //attribute aliases
3131 QDomElement aliasElem = doc.createElement( QStringLiteral( "aliases" ) );
3132 for ( const QgsField &field : std::as_const( mFields ) )
3133 {
3134 QDomElement aliasEntryElem = doc.createElement( QStringLiteral( "alias" ) );
3135 aliasEntryElem.setAttribute( QStringLiteral( "field" ), field.name() );
3136 aliasEntryElem.setAttribute( QStringLiteral( "index" ), mFields.indexFromName( field.name() ) );
3137 aliasEntryElem.setAttribute( QStringLiteral( "name" ), field.alias() );
3138 aliasElem.appendChild( aliasEntryElem );
3139 }
3140 node.appendChild( aliasElem );
3141
3142 //split policies
3143 {
3144 QDomElement splitPoliciesElement = doc.createElement( QStringLiteral( "splitPolicies" ) );
3145 bool hasNonDefaultSplitPolicies = false;
3146 for ( const QgsField &field : std::as_const( mFields ) )
3147 {
3148 if ( field.splitPolicy() != Qgis::FieldDomainSplitPolicy::Duplicate )
3149 {
3150 QDomElement splitPolicyElem = doc.createElement( QStringLiteral( "policy" ) );
3151 splitPolicyElem.setAttribute( QStringLiteral( "field" ), field.name() );
3152 splitPolicyElem.setAttribute( QStringLiteral( "policy" ), qgsEnumValueToKey( field.splitPolicy() ) );
3153 splitPoliciesElement.appendChild( splitPolicyElem );
3154 hasNonDefaultSplitPolicies = true;
3155 }
3156 }
3157 if ( hasNonDefaultSplitPolicies )
3158 node.appendChild( splitPoliciesElement );
3159 }
3160
3161 //duplicate policies
3162 {
3163 QDomElement duplicatePoliciesElement = doc.createElement( QStringLiteral( "duplicatePolicies" ) );
3164 bool hasNonDefaultDuplicatePolicies = false;
3165 for ( const QgsField &field : std::as_const( mFields ) )
3166 {
3167 if ( field.duplicatePolicy() != Qgis::FieldDuplicatePolicy::Duplicate )
3168 {
3169 QDomElement duplicatePolicyElem = doc.createElement( QStringLiteral( "policy" ) );
3170 duplicatePolicyElem.setAttribute( QStringLiteral( "field" ), field.name() );
3171 duplicatePolicyElem.setAttribute( QStringLiteral( "policy" ), qgsEnumValueToKey( field.duplicatePolicy() ) );
3172 duplicatePoliciesElement.appendChild( duplicatePolicyElem );
3173 hasNonDefaultDuplicatePolicies = true;
3174 }
3175 }
3176 if ( hasNonDefaultDuplicatePolicies )
3177 node.appendChild( duplicatePoliciesElement );
3178 }
3179
3180 //merge policies
3181 {
3182 QDomElement mergePoliciesElement = doc.createElement( QStringLiteral( "mergePolicies" ) );
3183 bool hasNonDefaultMergePolicies = false;
3184 for ( const QgsField &field : std::as_const( mFields ) )
3185 {
3186 if ( field.mergePolicy() != Qgis::FieldDomainMergePolicy::UnsetField )
3187 {
3188 QDomElement mergePolicyElem = doc.createElement( QStringLiteral( "policy" ) );
3189 mergePolicyElem.setAttribute( QStringLiteral( "field" ), field.name() );
3190 mergePolicyElem.setAttribute( QStringLiteral( "policy" ), qgsEnumValueToKey( field.mergePolicy() ) );
3191 mergePoliciesElement.appendChild( mergePolicyElem );
3192 hasNonDefaultMergePolicies = true;
3193 }
3194 }
3195 if ( hasNonDefaultMergePolicies )
3196 node.appendChild( mergePoliciesElement );
3197 }
3198
3199 //default expressions
3200 QDomElement defaultsElem = doc.createElement( QStringLiteral( "defaults" ) );
3201 for ( const QgsField &field : std::as_const( mFields ) )
3202 {
3203 QDomElement defaultElem = doc.createElement( QStringLiteral( "default" ) );
3204 defaultElem.setAttribute( QStringLiteral( "field" ), field.name() );
3205 defaultElem.setAttribute( QStringLiteral( "expression" ), field.defaultValueDefinition().expression() );
3206 defaultElem.setAttribute( QStringLiteral( "applyOnUpdate" ), field.defaultValueDefinition().applyOnUpdate() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
3207 defaultsElem.appendChild( defaultElem );
3208 }
3209 node.appendChild( defaultsElem );
3210
3211 // constraints
3212 QDomElement constraintsElem = doc.createElement( QStringLiteral( "constraints" ) );
3213 for ( const QgsField &field : std::as_const( mFields ) )
3214 {
3215 QDomElement constraintElem = doc.createElement( QStringLiteral( "constraint" ) );
3216 constraintElem.setAttribute( QStringLiteral( "field" ), field.name() );
3217 constraintElem.setAttribute( QStringLiteral( "constraints" ), field.constraints().constraints() );
3218 constraintElem.setAttribute( QStringLiteral( "unique_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintUnique ) );
3219 constraintElem.setAttribute( QStringLiteral( "notnull_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintNotNull ) );
3220 constraintElem.setAttribute( QStringLiteral( "exp_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintExpression ) );
3221
3222 constraintsElem.appendChild( constraintElem );
3223 }
3224 node.appendChild( constraintsElem );
3225
3226 // constraint expressions
3227 QDomElement constraintExpressionsElem = doc.createElement( QStringLiteral( "constraintExpressions" ) );
3228 for ( const QgsField &field : std::as_const( mFields ) )
3229 {
3230 QDomElement constraintExpressionElem = doc.createElement( QStringLiteral( "constraint" ) );
3231 constraintExpressionElem.setAttribute( QStringLiteral( "field" ), field.name() );
3232 constraintExpressionElem.setAttribute( QStringLiteral( "exp" ), field.constraints().constraintExpression() );
3233 constraintExpressionElem.setAttribute( QStringLiteral( "desc" ), field.constraints().constraintDescription() );
3234 constraintExpressionsElem.appendChild( constraintExpressionElem );
3235 }
3236 node.appendChild( constraintExpressionsElem );
3237
3238 // save expression fields
3239 if ( !mExpressionFieldBuffer )
3240 {
3241 // can happen when saving style on a invalid layer
3243 dummy.writeXml( node, doc );
3244 }
3245 else
3246 {
3247 mExpressionFieldBuffer->writeXml( node, doc );
3248 }
3249 }
3250
3251 // add attribute actions
3252 if ( categories.testFlag( Actions ) )
3253 mActions->writeXml( node );
3254
3255 if ( categories.testFlag( AttributeTable ) )
3256 {
3257 mAttributeTableConfig.writeXml( node );
3258 mConditionalStyles->writeXml( node, doc, context );
3259 mStoredExpressionManager->writeXml( node );
3260 }
3261
3262 if ( categories.testFlag( Forms ) )
3263 mEditFormConfig.writeXml( node, context );
3264
3265 // save readonly state
3266 if ( categories.testFlag( LayerConfiguration ) )
3267 node.toElement().setAttribute( QStringLiteral( "readOnly" ), mReadOnly );
3268
3269 // save preview expression
3270 if ( categories.testFlag( LayerConfiguration ) )
3271 {
3272 QDomElement prevExpElem = doc.createElement( QStringLiteral( "previewExpression" ) );
3273 QDomText prevExpText = doc.createTextNode( mDisplayExpression );
3274 prevExpElem.appendChild( prevExpText );
3275 node.appendChild( prevExpElem );
3276 }
3277
3278 // save map tip
3279 if ( categories.testFlag( MapTips ) )
3280 {
3281 QDomElement mapTipElem = doc.createElement( QStringLiteral( "mapTip" ) );
3282 mapTipElem.setAttribute( QStringLiteral( "enabled" ), mapTipsEnabled() );
3283 QDomText mapTipText = doc.createTextNode( mMapTipTemplate );
3284 mapTipElem.appendChild( mapTipText );
3285 node.toElement().appendChild( mapTipElem );
3286 }
3287
3288 return true;
3289}
3290
3291bool QgsVectorLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
3292 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
3293{
3295
3296 QDomElement mapLayerNode = node.toElement();
3297
3298 emit writeCustomSymbology( mapLayerNode, doc, errorMessage );
3299
3300 // we must try to write the renderer if our geometry type is unknown
3301 // as this allows the renderer to be correctly restored even for layers
3302 // with broken sources
3303 if ( isSpatial() || mWkbType == Qgis::WkbType::Unknown )
3304 {
3305 if ( categories.testFlag( Symbology ) )
3306 {
3307 if ( mRenderer )
3308 {
3309 QDomElement rendererElement = mRenderer->save( doc, context );
3310 node.appendChild( rendererElement );
3311 }
3312 if ( mSelectionProperties )
3313 {
3314 mSelectionProperties->writeXml( mapLayerNode, doc, context );
3315 }
3316 }
3317
3318 if ( categories.testFlag( Labeling ) )
3319 {
3320 if ( mLabeling )
3321 {
3322 QDomElement labelingElement = mLabeling->save( doc, context );
3323 node.appendChild( labelingElement );
3324 }
3325 mapLayerNode.setAttribute( QStringLiteral( "labelsEnabled" ), mLabelsEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
3326 }
3327
3328 // save the simplification drawing settings
3329 if ( categories.testFlag( Rendering ) )
3330 {
3331 mapLayerNode.setAttribute( QStringLiteral( "simplifyDrawingHints" ), QString::number( static_cast< int >( mSimplifyMethod.simplifyHints() ) ) );
3332 mapLayerNode.setAttribute( QStringLiteral( "simplifyAlgorithm" ), QString::number( static_cast< int >( mSimplifyMethod.simplifyAlgorithm() ) ) );
3333 mapLayerNode.setAttribute( QStringLiteral( "simplifyDrawingTol" ), QString::number( mSimplifyMethod.threshold() ) );
3334 mapLayerNode.setAttribute( QStringLiteral( "simplifyLocal" ), mSimplifyMethod.forceLocalOptimization() ? 1 : 0 );
3335 mapLayerNode.setAttribute( QStringLiteral( "simplifyMaxScale" ), QString::number( mSimplifyMethod.maximumScale() ) );
3336 }
3337
3338 //save customproperties
3339 if ( categories.testFlag( CustomProperties ) )
3340 {
3341 writeCustomProperties( node, doc );
3342 }
3343
3344 if ( categories.testFlag( Symbology ) )
3345 {
3346 // add the blend mode field
3347 QDomElement blendModeElem = doc.createElement( QStringLiteral( "blendMode" ) );
3348 QDomText blendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( blendMode() ) ) ) );
3349 blendModeElem.appendChild( blendModeText );
3350 node.appendChild( blendModeElem );
3351
3352 // add the feature blend mode field
3353 QDomElement featureBlendModeElem = doc.createElement( QStringLiteral( "featureBlendMode" ) );
3354 QDomText featureBlendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( featureBlendMode() ) ) ) );
3355 featureBlendModeElem.appendChild( featureBlendModeText );
3356 node.appendChild( featureBlendModeElem );
3357 }
3358
3359 // add the layer opacity and scale visibility
3360 if ( categories.testFlag( Rendering ) )
3361 {
3362 QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
3363 QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
3364 layerOpacityElem.appendChild( layerOpacityText );
3365 node.appendChild( layerOpacityElem );
3366 mapLayerNode.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
3367 mapLayerNode.setAttribute( QStringLiteral( "maxScale" ), maximumScale() );
3368 mapLayerNode.setAttribute( QStringLiteral( "minScale" ), minimumScale() );
3369
3370 mapLayerNode.setAttribute( QStringLiteral( "symbologyReferenceScale" ), mRenderer ? mRenderer->referenceScale() : -1 );
3371 }
3372
3373 if ( categories.testFlag( Diagrams ) && mDiagramRenderer )
3374 {
3375 mDiagramRenderer->writeXml( mapLayerNode, doc, context );
3376 if ( mDiagramLayerSettings )
3377 mDiagramLayerSettings->writeXml( mapLayerNode, doc );
3378 }
3379 }
3380 return true;
3381}
3382
3383bool QgsVectorLayer::readSld( const QDomNode &node, QString &errorMessage )
3384{
3386
3387 // get the Name element
3388 QDomElement nameElem = node.firstChildElement( QStringLiteral( "Name" ) );
3389 if ( nameElem.isNull() )
3390 {
3391 errorMessage = QStringLiteral( "Warning: Name element not found within NamedLayer while it's required." );
3392 }
3393
3394 if ( isSpatial() )
3395 {
3396 QgsFeatureRenderer *r = QgsFeatureRenderer::loadSld( node, geometryType(), errorMessage );
3397 if ( !r )
3398 return false;
3399
3400 // defer style changed signal until we've set the renderer, labeling, everything.
3401 // we don't want multiple signals!
3402 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
3403
3404 setRenderer( r );
3405
3406 // labeling
3407 readSldLabeling( node );
3408
3409 styleChangedSignalBlocker.release();
3411 }
3412 return true;
3413}
3414
3415bool QgsVectorLayer::writeSld( QDomNode &node, QDomDocument &doc, QString &, const QVariantMap &props ) const
3416{
3418 QgsSldExportContext context;
3419 context.setExtraProperties( props );
3420 writeSld( node, doc, context );
3421 return true;
3422}
3423
3424bool QgsVectorLayer::writeSld( QDomNode &node, QDomDocument &doc, QgsSldExportContext &context ) const
3425{
3427
3428 QVariantMap localProps = context.extraProperties();
3430 {
3432 }
3433 context.setExtraProperties( localProps );
3434
3435 if ( isSpatial() )
3436 {
3437 // store the Name element
3438 QDomElement nameNode = doc.createElement( QStringLiteral( "se:Name" ) );
3439 nameNode.appendChild( doc.createTextNode( name() ) );
3440 node.appendChild( nameNode );
3441
3442 QDomElement userStyleElem = doc.createElement( QStringLiteral( "UserStyle" ) );
3443 node.appendChild( userStyleElem );
3444
3445 QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
3446 nameElem.appendChild( doc.createTextNode( name() ) );
3447
3448 userStyleElem.appendChild( nameElem );
3449
3450 QDomElement featureTypeStyleElem = doc.createElement( QStringLiteral( "se:FeatureTypeStyle" ) );
3451 userStyleElem.appendChild( featureTypeStyleElem );
3452
3453 mRenderer->toSld( doc, featureTypeStyleElem, context );
3454 if ( labelsEnabled() )
3455 {
3456 mLabeling->toSld( featureTypeStyleElem, context );
3457 }
3458 }
3459 return true;
3460}
3461
3462bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, QgsGeometry &geom, bool skipDefaultValue )
3463{
3465
3466 if ( !mEditBuffer || !mDataProvider )
3467 {
3468 return false;
3469 }
3470
3471 if ( mGeometryOptions->isActive() )
3472 mGeometryOptions->apply( geom );
3473
3474 updateExtents();
3475
3476 bool result = mEditBuffer->changeGeometry( fid, geom );
3477
3478 if ( result )
3479 {
3480 updateExtents();
3481 if ( !skipDefaultValue && !mDefaultValueOnUpdateFields.isEmpty() )
3482 updateDefaultValues( fid );
3483 }
3484 return result;
3485}
3486
3487
3488bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue, bool skipDefaultValues, QgsVectorLayerToolsContext *context )
3489{
3491
3492 bool result = false;
3493
3494 switch ( fields().fieldOrigin( field ) )
3495 {
3497 result = mJoinBuffer->changeAttributeValue( fid, field, newValue, oldValue );
3498 if ( result )
3499 emit attributeValueChanged( fid, field, newValue );
3500 break;
3501
3505 {
3506 if ( mEditBuffer && mDataProvider )
3507 result = mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
3508 break;
3509 }
3510
3512 break;
3513 }
3514
3515 if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
3516 updateDefaultValues( fid, QgsFeature(), context ? context->expressionContext() : nullptr );
3517
3518 return result;
3519}
3520
3521bool QgsVectorLayer::changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues, bool skipDefaultValues, QgsVectorLayerToolsContext *context )
3522{
3524
3525 bool result = true;
3526
3527 QgsAttributeMap newValuesJoin;
3528 QgsAttributeMap oldValuesJoin;
3529
3530 QgsAttributeMap newValuesNotJoin;
3531 QgsAttributeMap oldValuesNotJoin;
3532
3533 for ( auto it = newValues.constBegin(); it != newValues.constEnd(); ++it )
3534 {
3535 const int field = it.key();
3536 const QVariant newValue = it.value();
3537 QVariant oldValue;
3538
3539 if ( oldValues.contains( field ) )
3540 oldValue = oldValues[field];
3541
3542 switch ( fields().fieldOrigin( field ) )
3543 {
3545 newValuesJoin[field] = newValue;
3546 oldValuesJoin[field] = oldValue;
3547 break;
3548
3552 {
3553 newValuesNotJoin[field] = newValue;
3554 oldValuesNotJoin[field] = oldValue;
3555 break;
3556 }
3557
3559 break;
3560 }
3561 }
3562
3563 if ( ! newValuesJoin.isEmpty() && mJoinBuffer )
3564 {
3565 result = mJoinBuffer->changeAttributeValues( fid, newValuesJoin, oldValuesJoin );
3566 }
3567
3568 if ( ! newValuesNotJoin.isEmpty() )
3569 {
3570 if ( mEditBuffer && mDataProvider )
3571 result &= mEditBuffer->changeAttributeValues( fid, newValuesNotJoin, oldValues );
3572 else
3573 result = false;
3574 }
3575
3576 if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
3577 {
3578 updateDefaultValues( fid, QgsFeature(), context ? context->expressionContext() : nullptr );
3579 }
3580
3581 return result;
3582}
3583
3585{
3587
3588 if ( !mEditBuffer || !mDataProvider )
3589 return false;
3590
3591 return mEditBuffer->addAttribute( field );
3592}
3593
3595{
3597
3598 if ( attIndex < 0 || attIndex >= fields().count() )
3599 return;
3600
3601 QString name = fields().at( attIndex ).name();
3602 mFields[ attIndex ].setAlias( QString() );
3603 if ( mAttributeAliasMap.contains( name ) )
3604 {
3605 mAttributeAliasMap.remove( name );
3606 updateFields();
3607 mEditFormConfig.setFields( mFields );
3608 emit layerModified();
3609 }
3610}
3611
3612bool QgsVectorLayer::renameAttribute( int index, const QString &newName )
3613{
3615
3616 if ( index < 0 || index >= fields().count() )
3617 return false;
3618
3619 switch ( mFields.fieldOrigin( index ) )
3620 {
3622 {
3623 if ( mExpressionFieldBuffer )
3624 {
3625 int oi = mFields.fieldOriginIndex( index );
3626 mExpressionFieldBuffer->renameExpression( oi, newName );
3627 updateFields();
3628 return true;
3629 }
3630 else
3631 {
3632 return false;
3633 }
3634 }
3635
3638
3639 if ( !mEditBuffer || !mDataProvider )
3640 return false;
3641
3642 return mEditBuffer->renameAttribute( index, newName );
3643
3646 return false;
3647
3648 }
3649
3650 return false; // avoid warning
3651}
3652
3653void QgsVectorLayer::setFieldAlias( int attIndex, const QString &aliasString )
3654{
3656
3657 if ( attIndex < 0 || attIndex >= fields().count() )
3658 return;
3659
3660 QString name = fields().at( attIndex ).name();
3661
3662 mAttributeAliasMap.insert( name, aliasString );
3663 mFields[ attIndex ].setAlias( aliasString );
3664 mEditFormConfig.setFields( mFields );
3665 emit layerModified(); // TODO[MD]: should have a different signal?
3666}
3667
3668QString QgsVectorLayer::attributeAlias( int index ) const
3669{
3671
3672 if ( index < 0 || index >= fields().count() )
3673 return QString();
3674
3675 return fields().at( index ).alias();
3676}
3677
3679{
3681
3682 if ( index >= 0 && index < mFields.count() )
3683 return mFields.at( index ).displayName();
3684 else
3685 return QString();
3686}
3687
3689{
3691
3692 return mAttributeAliasMap;
3693}
3694
3696{
3698
3699 if ( index < 0 || index >= fields().count() )
3700 return;
3701
3702 const QString name = fields().at( index ).name();
3703
3704 mAttributeSplitPolicy.insert( name, policy );
3705 mFields[ index ].setSplitPolicy( policy );
3706 mEditFormConfig.setFields( mFields );
3707 emit layerModified(); // TODO[MD]: should have a different signal?
3708}
3709
3711{
3713
3714 if ( index < 0 || index >= fields().count() )
3715 return;
3716
3717 const QString name = fields().at( index ).name();
3718
3719 mAttributeDuplicatePolicy.insert( name, policy );
3720 mFields[ index ].setDuplicatePolicy( policy );
3721 mEditFormConfig.setFields( mFields );
3722 emit layerModified(); // TODO[MD]: should have a different signal?
3723}
3724
3726{
3728
3729 if ( index < 0 || index >= fields().count() )
3730 return;
3731
3732 const QString name = fields().at( index ).name();
3733
3734 mAttributeMergePolicy.insert( name, policy );
3735 mFields[ index ].setMergePolicy( policy );
3736 mEditFormConfig.setFields( mFields );
3737 emit layerModified(); // TODO[MD]: should have a different signal?
3738}
3739
3741{
3743
3744 QSet<QString> excludeList;
3745 QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
3746 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
3747 {
3748 if ( flagsIt->testFlag( Qgis::FieldConfigurationFlag::HideFromWms ) )
3749 {
3750 excludeList << flagsIt.key();
3751 }
3752 }
3753 return excludeList;
3754}
3755
3756void QgsVectorLayer::setExcludeAttributesWms( const QSet<QString> &att )
3757{
3759
3760 QMap< QString, Qgis::FieldConfigurationFlags >::iterator flagsIt = mFieldConfigurationFlags.begin();
3761 for ( ; flagsIt != mFieldConfigurationFlags.end(); ++flagsIt )
3762 {
3763 flagsIt->setFlag( Qgis::FieldConfigurationFlag::HideFromWms, att.contains( flagsIt.key() ) );
3764 }
3765 updateFields();
3766}
3767
3769{
3771
3772 QSet<QString> excludeList;
3773 QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
3774 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
3775 {
3776 if ( flagsIt->testFlag( Qgis::FieldConfigurationFlag::HideFromWfs ) )
3777 {
3778 excludeList << flagsIt.key();
3779 }
3780 }
3781 return excludeList;
3782}
3783
3784void QgsVectorLayer::setExcludeAttributesWfs( const QSet<QString> &att )
3785{
3787
3788 QMap< QString, Qgis::FieldConfigurationFlags >::iterator flagsIt = mFieldConfigurationFlags.begin();
3789 for ( ; flagsIt != mFieldConfigurationFlags.end(); ++flagsIt )
3790 {
3791 flagsIt->setFlag( Qgis::FieldConfigurationFlag::HideFromWfs, att.contains( flagsIt.key() ) );
3792 }
3793 updateFields();
3794}
3795
3797{
3799
3800 if ( index < 0 || index >= fields().count() )
3801 return false;
3802
3803 if ( mFields.fieldOrigin( index ) == Qgis::FieldOrigin::Expression )
3804 {
3805 removeExpressionField( index );
3806 return true;
3807 }
3808
3809 if ( !mEditBuffer || !mDataProvider )
3810 return false;
3811
3812 return mEditBuffer->deleteAttribute( index );
3813}
3814
3815bool QgsVectorLayer::deleteAttributes( const QList<int> &attrs )
3816{
3818
3819 bool deleted = false;
3820
3821 // Remove multiple occurrences of same attribute
3822 QList<int> attrList = qgis::setToList( qgis::listToSet( attrs ) );
3823
3824 std::sort( attrList.begin(), attrList.end(), std::greater<int>() );
3825
3826 for ( int attr : std::as_const( attrList ) )
3827 {
3828 if ( deleteAttribute( attr ) )
3829 {
3830 deleted = true;
3831 }
3832 }
3833
3834 return deleted;
3835}
3836
3837bool QgsVectorLayer::deleteFeatureCascade( QgsFeatureId fid, QgsVectorLayer::DeleteContext *context )
3838{
3840
3841 if ( !mEditBuffer )
3842 return false;
3843
3844 if ( context && context->cascade )
3845 {
3846 const QList<QgsRelation> relations = context->project->relationManager()->referencedRelations( this );
3847 const bool hasRelationsOrJoins = !relations.empty() || mJoinBuffer->containsJoins();
3848 if ( hasRelationsOrJoins )
3849 {
3850 if ( context->mHandledFeatures.contains( this ) )
3851 {
3852 QgsFeatureIds &handledFeatureIds = context->mHandledFeatures[ this ];
3853 if ( handledFeatureIds.contains( fid ) )
3854 {
3855 // avoid endless recursion
3856 return false;
3857 }
3858 else
3859 {
3860 // add feature id
3861 handledFeatureIds << fid;
3862 }
3863 }
3864 else
3865 {
3866 // add layer and feature id
3867 context->mHandledFeatures.insert( this, QgsFeatureIds() << fid );
3868 }
3869
3870 for ( const QgsRelation &relation : relations )
3871 {
3872 //check if composition (and not association)
3873 switch ( relation.strength() )
3874 {
3876 {
3877 //get features connected over this relation
3878 QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( getFeature( fid ) );
3879 QgsFeatureIds childFeatureIds;
3880 QgsFeature childFeature;
3881 while ( relatedFeaturesIt.nextFeature( childFeature ) )
3882 {
3883 childFeatureIds.insert( childFeature.id() );
3884 }
3885 if ( childFeatureIds.count() > 0 )
3886 {
3887 relation.referencingLayer()->startEditing();
3888 relation.referencingLayer()->deleteFeatures( childFeatureIds, context );
3889 }
3890 break;
3891 }
3892
3894 break;
3895 }
3896 }
3897 }
3898 }
3899
3900 if ( mJoinBuffer->containsJoins() )
3901 mJoinBuffer->deleteFeature( fid, context );
3902
3903 bool res = mEditBuffer->deleteFeature( fid );
3904
3905 return res;
3906}
3907
3909{
3911
3912 if ( !mEditBuffer )
3913 return false;
3914
3915 return deleteFeatureCascade( fid, context );
3916}
3917
3919{
3921
3922 bool res = true;
3923
3924 if ( ( context && context->cascade ) || mJoinBuffer->containsJoins() )
3925 {
3926 // should ideally be "deleteFeaturesCascade" for performance!
3927 for ( QgsFeatureId fid : fids )
3928 res = deleteFeatureCascade( fid, context ) && res;
3929 }
3930 else
3931 {
3932 res = mEditBuffer && mEditBuffer->deleteFeatures( fids );
3933 }
3934
3935 if ( res )
3936 {
3937 mSelectedFeatureIds.subtract( fids ); // remove it from selection
3938 updateExtents();
3939 }
3940
3941 return res;
3942}
3943
3945{
3946 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
3948
3949 return mFields;
3950}
3951
3953{
3955
3956 QgsAttributeList pkAttributesList;
3957 if ( !mDataProvider )
3958 return pkAttributesList;
3959
3960 QgsAttributeList providerIndexes = mDataProvider->pkAttributeIndexes();
3961 for ( int i = 0; i < mFields.count(); ++i )
3962 {
3963 if ( mFields.fieldOrigin( i ) == Qgis::FieldOrigin::Provider &&
3964 providerIndexes.contains( mFields.fieldOriginIndex( i ) ) )
3965 pkAttributesList << i;
3966 }
3967
3968 return pkAttributesList;
3969}
3970
3972{
3974
3975 if ( !mDataProvider )
3976 return static_cast< long long >( Qgis::FeatureCountState::UnknownCount );
3977 return mDataProvider->featureCount() +
3978 ( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->addedFeatures().size() - mEditBuffer->deletedFeatureIds().size() : 0 );
3979}
3980
3982{
3984
3985 const QgsFeatureIds deletedFeatures( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->deletedFeatureIds() : QgsFeatureIds() );
3986 const QgsFeatureMap addedFeatures( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->addedFeatures() : QgsFeatureMap() );
3987
3988 if ( mEditBuffer && !deletedFeatures.empty() )
3989 {
3990 if ( addedFeatures.size() > deletedFeatures.size() )
3992 else
3994 }
3995
3996 if ( ( !mEditBuffer || addedFeatures.empty() ) && mDataProvider && mDataProvider->empty() )
3998 else
4000}
4001
4002bool QgsVectorLayer::commitChanges( bool stopEditing )
4003{
4005
4006 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
4007 return project()->commitChanges( mCommitErrors, stopEditing, this );
4008
4009 mCommitErrors.clear();
4010
4011 if ( !mDataProvider )
4012 {
4013 mCommitErrors << tr( "ERROR: no provider" );
4014 return false;
4015 }
4016
4017 if ( !mEditBuffer )
4018 {
4019 mCommitErrors << tr( "ERROR: layer not editable" );
4020 return false;
4021 }
4022
4023 emit beforeCommitChanges( stopEditing );
4024
4025 if ( !mAllowCommit )
4026 return false;
4027
4028 mCommitChangesActive = true;
4029
4030 bool success = false;
4031 if ( mEditBuffer->editBufferGroup() )
4032 success = mEditBuffer->editBufferGroup()->commitChanges( mCommitErrors, stopEditing );
4033 else
4034 success = mEditBuffer->commitChanges( mCommitErrors );
4035
4036 mCommitChangesActive = false;
4037
4038 if ( !mDeletedFids.empty() )
4039 {
4040 emit featuresDeleted( mDeletedFids );
4041 mDeletedFids.clear();
4042 }
4043
4044 if ( success )
4045 {
4046 if ( stopEditing )
4047 {
4048 clearEditBuffer();
4049 }
4050 undoStack()->clear();
4051 emit afterCommitChanges();
4052 if ( stopEditing )
4053 emit editingStopped();
4054 }
4055 else
4056 {
4057 QgsMessageLog::logMessage( tr( "Commit errors:\n %1" ).arg( mCommitErrors.join( QLatin1String( "\n " ) ) ) );
4058 }
4059
4060 updateFields();
4061
4062 mDataProvider->updateExtents();
4063
4064 if ( stopEditing )
4065 {
4066 mDataProvider->leaveUpdateMode();
4067 }
4068
4069 // This second call is required because OGR provider with JSON
4070 // driver might have changed fields order after the call to
4071 // leaveUpdateMode
4072 if ( mFields.names() != mDataProvider->fields().names() )
4073 {
4074 updateFields();
4075 }
4076
4078
4079 return success;
4080}
4081
4083{
4085
4086 return mCommitErrors;
4087}
4088
4089bool QgsVectorLayer::rollBack( bool deleteBuffer )
4090{
4092
4093 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
4094 return project()->rollBack( mCommitErrors, deleteBuffer, this );
4095
4096 if ( !mEditBuffer )
4097 {
4098 return false;
4099 }
4100
4101 if ( !mDataProvider )
4102 {
4103 mCommitErrors << tr( "ERROR: no provider" );
4104 return false;
4105 }
4106
4107 bool rollbackExtent = !mDataProvider->transaction() && ( !mEditBuffer->deletedFeatureIds().isEmpty() ||
4108 !mEditBuffer->addedFeatures().isEmpty() ||
4109 !mEditBuffer->changedGeometries().isEmpty() );
4110
4111 emit beforeRollBack();
4112
4113 mEditBuffer->rollBack();
4114
4115 emit afterRollBack();
4116
4117 if ( isModified() )
4118 {
4119 // new undo stack roll back method
4120 // old method of calling every undo could cause many canvas refreshes
4121 undoStack()->setIndex( 0 );
4122 }
4123
4124 updateFields();
4125
4126 if ( deleteBuffer )
4127 {
4128 delete mEditBuffer;
4129 mEditBuffer = nullptr;
4130 undoStack()->clear();
4131 }
4132 emit editingStopped();
4133
4134 if ( rollbackExtent )
4135 updateExtents();
4136
4137 mDataProvider->leaveUpdateMode();
4138
4140 return true;
4141}
4142
4144{
4146
4147 return mSelectedFeatureIds.size();
4148}
4149
4151{
4152 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
4154
4155 return mSelectedFeatureIds;
4156}
4157
4159{
4161
4162 QgsFeatureList features;
4163 features.reserve( mSelectedFeatureIds.count() );
4164 QgsFeature f;
4165
4167
4168 while ( it.nextFeature( f ) )
4169 {
4170 features.push_back( f );
4171 }
4172
4173 return features;
4174}
4175
4177{
4179
4180 if ( mSelectedFeatureIds.isEmpty() )
4181 return QgsFeatureIterator();
4182
4185
4186 if ( mSelectedFeatureIds.count() == 1 )
4187 request.setFilterFid( *mSelectedFeatureIds.constBegin() );
4188 else
4189 request.setFilterFids( mSelectedFeatureIds );
4190
4191 return getFeatures( request );
4192}
4193
4195{
4197
4198 if ( !mEditBuffer || !mDataProvider )
4199 return false;
4200
4201 if ( mGeometryOptions->isActive() )
4202 {
4203 for ( auto feature = features.begin(); feature != features.end(); ++feature )
4204 {
4205 QgsGeometry geom = feature->geometry();
4206 mGeometryOptions->apply( geom );
4207 feature->setGeometry( geom );
4208 }
4209 }
4210
4211 bool res = mEditBuffer->addFeatures( features );
4212 updateExtents();
4213
4214 if ( res && mJoinBuffer->containsJoins() )
4215 res = mJoinBuffer->addFeatures( features );
4216
4217 return res;
4218}
4219
4221{
4223
4224 // if layer is not spatial, it has not CRS!
4225 setCrs( ( isSpatial() && mDataProvider ) ? mDataProvider->crs() : QgsCoordinateReferenceSystem() );
4226}
4227
4229{
4231
4233 if ( exp.isField() )
4234 {
4235 return static_cast<const QgsExpressionNodeColumnRef *>( exp.rootNode() )->name();
4236 }
4237
4238 return QString();
4239}
4240
4241void QgsVectorLayer::setDisplayExpression( const QString &displayExpression )
4242{
4244
4245 if ( mDisplayExpression == displayExpression )
4246 return;
4247
4248 mDisplayExpression = displayExpression;
4250}
4251
4253{
4255
4256 if ( !mDisplayExpression.isEmpty() || mFields.isEmpty() )
4257 {
4258 return mDisplayExpression;
4259 }
4260 else
4261 {
4262 const QString candidateName = QgsVectorLayerUtils::guessFriendlyIdentifierField( mFields );
4263 if ( !candidateName.isEmpty() )
4264 {
4265 return QgsExpression::quotedColumnRef( candidateName );
4266 }
4267 else
4268 {
4269 return QString();
4270 }
4271 }
4272}
4273
4275{
4277
4278 // display expressions are used as a fallback when no explicit map tip template is set
4279 return mapTipsEnabled() && ( !mapTipTemplate().isEmpty() || !displayExpression().isEmpty() );
4280}
4281
4283{
4285
4286 return ( mEditBuffer && mDataProvider );
4287}
4288
4290{
4291 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
4293
4296}
4297
4298bool QgsVectorLayer::isReadOnly() const
4299{
4301
4302 return mDataSourceReadOnly || mReadOnly;
4303}
4304
4305bool QgsVectorLayer::setReadOnly( bool readonly )
4306{
4308
4309 // exit if the layer is in editing mode
4310 if ( readonly && mEditBuffer )
4311 return false;
4312
4313 // exit if the data source is in read-only mode
4314 if ( !readonly && mDataSourceReadOnly )
4315 return false;
4316
4317 mReadOnly = readonly;
4318 emit readOnlyChanged();
4319 return true;
4320}
4321
4323{
4325
4326 if ( ! mDataProvider )
4327 return false;
4328
4329 if ( mDataSourceReadOnly )
4330 return false;
4331
4332 return mDataProvider->capabilities() & QgsVectorDataProvider::EditingCapabilities && ! mReadOnly;
4333}
4334
4336{
4338
4339 emit beforeModifiedCheck();
4340 return mEditBuffer && mEditBuffer->isModified();
4341}
4342
4343bool QgsVectorLayer::isAuxiliaryField( int index, int &srcIndex ) const
4344{
4346
4347 bool auxiliaryField = false;
4348 srcIndex = -1;
4349
4350 if ( !auxiliaryLayer() )
4351 return auxiliaryField;
4352
4353 if ( index >= 0 && fields().fieldOrigin( index ) == Qgis::FieldOrigin::Join )
4354 {
4355 const QgsVectorLayerJoinInfo *info = mJoinBuffer->joinForFieldIndex( index, fields(), srcIndex );
4356
4357 if ( info && info->joinLayerId() == auxiliaryLayer()->id() )
4358 auxiliaryField = true;
4359 }
4360
4361 return auxiliaryField;
4362}
4363
4365{
4367
4368 // we must allow setting a renderer if our geometry type is unknown
4369 // as this allows the renderer to be correctly set even for layers
4370 // with broken sources
4371 // (note that we allow REMOVING the renderer for non-spatial layers,
4372 // e.g. to permit removing the renderer when the layer changes from
4373 // a spatial layer to a non-spatial one)
4374 if ( r && !isSpatial() && mWkbType != Qgis::WkbType::Unknown )
4375 return;
4376
4377 if ( r != mRenderer )
4378 {
4379 delete mRenderer;
4380 mRenderer = r;
4381 mSymbolFeatureCounted = false;
4382 mSymbolFeatureCountMap.clear();
4383 mSymbolFeatureIdMap.clear();
4384
4385 if ( mRenderer )
4386 {
4387 const double refreshRate = QgsSymbolLayerUtils::rendererFrameRate( mRenderer );
4388 if ( refreshRate <= 0 )
4389 {
4390 mRefreshRendererTimer->stop();
4391 mRefreshRendererTimer->setInterval( 0 );
4392 }
4393 else
4394 {
4395 mRefreshRendererTimer->setInterval( 1000 / refreshRate );
4396 mRefreshRendererTimer->start();
4397 }
4398 }
4399
4400 emit rendererChanged();
4402 }
4403}
4404
4406{
4408
4409 if ( generator )
4410 {
4411 mRendererGenerators << generator;
4412 }
4413}
4414
4416{
4418
4419 for ( int i = mRendererGenerators.count() - 1; i >= 0; --i )
4420 {
4421 if ( mRendererGenerators.at( i )->id() == id )
4422 {
4423 delete mRendererGenerators.at( i );
4424 mRendererGenerators.removeAt( i );
4425 }
4426 }
4427}
4428
4429QList<const QgsFeatureRendererGenerator *> QgsVectorLayer::featureRendererGenerators() const
4430{
4431 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
4433
4434 QList< const QgsFeatureRendererGenerator * > res;
4435 for ( const QgsFeatureRendererGenerator *generator : mRendererGenerators )
4436 res << generator;
4437 return res;
4438}
4439
4440void QgsVectorLayer::beginEditCommand( const QString &text )
4441{
4443
4444 if ( !mDataProvider )
4445 {
4446 return;
4447 }
4448 if ( mDataProvider->transaction() )
4449 {
4450 QString ignoredError;
4451 mDataProvider->transaction()->createSavepoint( ignoredError );
4452 }
4453 undoStack()->beginMacro( text );
4454 mEditCommandActive = true;
4455 emit editCommandStarted( text );
4456}
4457
4459{
4461
4462 if ( !mDataProvider )
4463 {
4464 return;
4465 }
4466 undoStack()->endMacro();
4467 mEditCommandActive = false;
4468 if ( !mDeletedFids.isEmpty() )
4469 {
4470 if ( selectedFeatureCount() > 0 )
4471 {
4472 mSelectedFeatureIds.subtract( mDeletedFids );
4473 }
4474 emit featuresDeleted( mDeletedFids );
4475 mDeletedFids.clear();
4476 }
4477 emit editCommandEnded();
4478}
4479
4481{
4483
4484 if ( !mDataProvider )
4485 {
4486 return;
4487 }
4488 undoStack()->endMacro();
4489 undoStack()->undo();
4490
4491 // it's not directly possible to pop the last command off the stack (the destroyed one)
4492 // and delete, so we add a dummy obsolete command to force this to occur.
4493 // Pushing the new command deletes the destroyed one, and since the new
4494 // command is obsolete it's automatically deleted by the undo stack.
4495 auto command = std::make_unique< QUndoCommand >();
4496 command->setObsolete( true );
4497 undoStack()->push( command.release() );
4498
4499 mEditCommandActive = false;
4500 mDeletedFids.clear();
4501 emit editCommandDestroyed();
4502}
4503
4505{
4507
4508 return mJoinBuffer->addJoin( joinInfo );
4509}
4510
4511bool QgsVectorLayer::removeJoin( const QString &joinLayerId )
4512{
4514
4515 return mJoinBuffer->removeJoin( joinLayerId );
4516}
4517
4518const QList< QgsVectorLayerJoinInfo > QgsVectorLayer::vectorJoins() const
4519{
4521
4522 return mJoinBuffer->vectorJoins();
4523}
4524
4525int QgsVectorLayer::addExpressionField( const QString &exp, const QgsField &fld )
4526{
4528
4529 emit beforeAddingExpressionField( fld.name() );
4530 mExpressionFieldBuffer->addExpression( exp, fld );
4531 updateFields();
4532 int idx = mFields.indexFromName( fld.name() );
4533 emit attributeAdded( idx );
4534 return idx;
4535}
4536
4538{
4540
4541 emit beforeRemovingExpressionField( index );
4542 int oi = mFields.fieldOriginIndex( index );
4543 mExpressionFieldBuffer->removeExpression( oi );
4544 updateFields();
4545 emit attributeDeleted( index );
4546}
4547
4548QString QgsVectorLayer::expressionField( int index ) const
4549{
4551
4552 if ( mFields.fieldOrigin( index ) != Qgis::FieldOrigin::Expression )
4553 return QString();
4554
4555 int oi = mFields.fieldOriginIndex( index );
4556 if ( oi < 0 || oi >= mExpressionFieldBuffer->expressions().size() )
4557 return QString();
4558
4559 return mExpressionFieldBuffer->expressions().at( oi ).cachedExpression.expression();
4560}
4561
4562void QgsVectorLayer::updateExpressionField( int index, const QString &exp )
4563{
4565
4566 int oi = mFields.fieldOriginIndex( index );
4567 mExpressionFieldBuffer->updateExpression( oi, exp );
4568}
4569
4571{
4572 // non fatal for now -- the QgsVirtualLayerTask class is not thread safe and calls this
4574
4575 if ( !mDataProvider )
4576 return;
4577
4578 QgsFields oldFields = mFields;
4579
4580 mFields = mDataProvider->fields();
4581
4582 // added / removed fields
4583 if ( mEditBuffer )
4584 mEditBuffer->updateFields( mFields );
4585
4586 // joined fields
4587 if ( mJoinBuffer->containsJoins() )
4588 mJoinBuffer->updateFields( mFields );
4589
4590 if ( mExpressionFieldBuffer )
4591 mExpressionFieldBuffer->updateFields( mFields );
4592
4593 // set aliases and default values
4594 for ( auto aliasIt = mAttributeAliasMap.constBegin(); aliasIt != mAttributeAliasMap.constEnd(); ++aliasIt )
4595 {
4596 int index = mFields.lookupField( aliasIt.key() );
4597 if ( index < 0 )
4598 continue;
4599
4600 mFields[ index ].setAlias( aliasIt.value() );
4601 }
4602
4603 for ( auto splitPolicyIt = mAttributeSplitPolicy.constBegin(); splitPolicyIt != mAttributeSplitPolicy.constEnd(); ++splitPolicyIt )
4604 {
4605 int index = mFields.lookupField( splitPolicyIt.key() );
4606 if ( index < 0 )
4607 continue;
4608
4609 mFields[ index ].setSplitPolicy( splitPolicyIt.value() );
4610 }
4611
4612 for ( auto duplicatePolicyIt = mAttributeDuplicatePolicy.constBegin(); duplicatePolicyIt != mAttributeDuplicatePolicy.constEnd(); ++duplicatePolicyIt )
4613 {
4614 int index = mFields.lookupField( duplicatePolicyIt.key() );
4615 if ( index < 0 )
4616 continue;
4617
4618 mFields[ index ].setDuplicatePolicy( duplicatePolicyIt.value() );
4619 }
4620
4621 for ( auto mergePolicyIt = mAttributeMergePolicy.constBegin(); mergePolicyIt != mAttributeMergePolicy.constEnd(); ++mergePolicyIt )
4622 {
4623 int index = mFields.lookupField( mergePolicyIt.key() );
4624 if ( index < 0 )
4625 continue;
4626
4627 mFields[ index ].setMergePolicy( mergePolicyIt.value() );
4628 }
4629
4630 // Update configuration flags
4631 QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
4632 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
4633 {
4634 int index = mFields.lookupField( flagsIt.key() );
4635 if ( index < 0 )
4636 continue;
4637
4638 mFields[index].setConfigurationFlags( flagsIt.value() );
4639 }
4640
4641 // Update default values
4642 mDefaultValueOnUpdateFields.clear();
4643 QMap< QString, QgsDefaultValue >::const_iterator defaultIt = mDefaultExpressionMap.constBegin();
4644 for ( ; defaultIt != mDefaultExpressionMap.constEnd(); ++defaultIt )
4645 {
4646 int index = mFields.lookupField( defaultIt.key() );
4647 if ( index < 0 )
4648 continue;
4649
4650 mFields[ index ].setDefaultValueDefinition( defaultIt.value() );
4651 if ( defaultIt.value().applyOnUpdate() )
4652 mDefaultValueOnUpdateFields.insert( index );
4653 }
4654
4655 QMap< QString, QgsFieldConstraints::Constraints >::const_iterator constraintIt = mFieldConstraints.constBegin();
4656 for ( ; constraintIt != mFieldConstraints.constEnd(); ++constraintIt )
4657 {
4658 int index = mFields.lookupField( constraintIt.key() );
4659 if ( index < 0 )
4660 continue;
4661
4662 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4663
4664 // always keep provider constraints intact
4665 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintNotNull ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintNotNull ) )
4667 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintUnique ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintUnique ) )
4669 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintExpression ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintExpression ) )
4671 mFields[ index ].setConstraints( constraints );
4672 }
4673
4674 QMap< QString, QPair< QString, QString > >::const_iterator constraintExpIt = mFieldConstraintExpressions.constBegin();
4675 for ( ; constraintExpIt != mFieldConstraintExpressions.constEnd(); ++constraintExpIt )
4676 {
4677 int index = mFields.lookupField( constraintExpIt.key() );
4678 if ( index < 0 )
4679 continue;
4680
4681 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4682
4683 // always keep provider constraints intact
4685 continue;
4686
4687 constraints.setConstraintExpression( constraintExpIt.value().first, constraintExpIt.value().second );
4688 mFields[ index ].setConstraints( constraints );
4689 }
4690
4691 QMap< QPair< QString, QgsFieldConstraints::Constraint >, QgsFieldConstraints::ConstraintStrength >::const_iterator constraintStrengthIt = mFieldConstraintStrength.constBegin();
4692 for ( ; constraintStrengthIt != mFieldConstraintStrength.constEnd(); ++constraintStrengthIt )
4693 {
4694 int index = mFields.lookupField( constraintStrengthIt.key().first );
4695 if ( index < 0 )
4696 continue;
4697
4698 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4699
4700 // always keep provider constraints intact
4702 continue;
4703
4704 constraints.setConstraintStrength( constraintStrengthIt.key().second, constraintStrengthIt.value() );
4705 mFields[ index ].setConstraints( constraints );
4706 }
4707
4708 auto fieldWidgetIterator = mFieldWidgetSetups.constBegin();
4709 for ( ; fieldWidgetIterator != mFieldWidgetSetups.constEnd(); ++ fieldWidgetIterator )
4710 {
4711 int index = mFields.indexOf( fieldWidgetIterator.key() );
4712 if ( index < 0 )
4713 continue;
4714
4715 mFields[index].setEditorWidgetSetup( fieldWidgetIterator.value() );
4716 }
4717
4718 if ( oldFields != mFields )
4719 {
4720 emit updatedFields();
4721 mEditFormConfig.setFields( mFields );
4722 }
4723
4724}
4725
4726QVariant QgsVectorLayer::defaultValue( int index, const QgsFeature &feature, QgsExpressionContext *context ) const
4727{
4729
4730 if ( index < 0 || index >= mFields.count() || !mDataProvider )
4731 return QVariant();
4732
4733 QString expression = mFields.at( index ).defaultValueDefinition().expression();
4734 if ( expression.isEmpty() )
4735 return mDataProvider->defaultValue( index );
4736
4737 QgsExpressionContext *evalContext = context;
4738 std::unique_ptr< QgsExpressionContext > tempContext;
4739 if ( !evalContext )
4740 {
4741 // no context passed, so we create a default one
4743 evalContext = tempContext.get();
4744 }
4745
4746 if ( feature.isValid() )
4747 {
4749 featScope->setFeature( feature );
4750 featScope->setFields( feature.fields() );
4751 evalContext->appendScope( featScope );
4752 }
4753
4754 QVariant val;
4755 QgsExpression exp( expression );
4756 exp.prepare( evalContext );
4757 if ( exp.hasEvalError() )
4758 {
4759 QgsLogger::warning( "Error evaluating default value: " + exp.evalErrorString() );
4760 }
4761 else
4762 {
4763 val = exp.evaluate( evalContext );
4764 }
4765
4766 if ( feature.isValid() )
4767 {
4768 delete evalContext->popScope();
4769 }
4770
4771 return val;
4772}
4773
4775{
4777
4778 if ( index < 0 || index >= mFields.count() )
4779 return;
4780
4781 if ( definition.isValid() )
4782 {
4783 mDefaultExpressionMap.insert( mFields.at( index ).name(), definition );
4784 }
4785 else
4786 {
4787 mDefaultExpressionMap.remove( mFields.at( index ).name() );
4788 }
4789 updateFields();
4790}
4791
4793{
4795
4796 if ( index < 0 || index >= mFields.count() )
4797 return QgsDefaultValue();
4798 else
4799 return mFields.at( index ).defaultValueDefinition();
4800}
4801
4802QSet<QVariant> QgsVectorLayer::uniqueValues( int index, int limit ) const
4803{
4805
4806 QSet<QVariant> uniqueValues;
4807 if ( !mDataProvider )
4808 {
4809 return uniqueValues;
4810 }
4811
4812 Qgis::FieldOrigin origin = mFields.fieldOrigin( index );
4813 switch ( origin )
4814 {
4816 return uniqueValues;
4817
4818 case Qgis::FieldOrigin::Provider: //a provider field
4819 {
4820 uniqueValues = mDataProvider->uniqueValues( index, limit );
4821
4822 if ( mEditBuffer && ! mDataProvider->transaction() )
4823 {
4824 QSet<QString> vals;
4825 const auto constUniqueValues = uniqueValues;
4826 for ( const QVariant &v : constUniqueValues )
4827 {
4828 vals << v.toString();
4829 }
4830
4831 QgsFeatureMap added = mEditBuffer->addedFeatures();
4832 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4833 while ( addedIt.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
4834 {
4835 addedIt.next();
4836 QVariant v = addedIt.value().attribute( index );
4837 if ( v.isValid() )
4838 {
4839 QString vs = v.toString();
4840 if ( !vals.contains( vs ) )
4841 {
4842 vals << vs;
4843 uniqueValues << v;
4844 }
4845 }
4846 }
4847
4848 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4849 while ( it.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
4850 {
4851 it.next();
4852 QVariant v = it.value().value( index );
4853 if ( v.isValid() )
4854 {
4855 QString vs = v.toString();
4856 if ( !vals.contains( vs ) )
4857 {
4858 vals << vs;
4859 uniqueValues << v;
4860 }
4861 }
4862 }
4863 }
4864
4865 return uniqueValues;
4866 }
4867
4869 // the layer is editable, but in certain cases it can still be avoided going through all features
4870 if ( mDataProvider->transaction() || (
4871 mEditBuffer->deletedFeatureIds().isEmpty() &&
4872 mEditBuffer->addedFeatures().isEmpty() &&
4873 !mEditBuffer->deletedAttributeIds().contains( index ) &&
4874 mEditBuffer->changedAttributeValues().isEmpty() ) )
4875 {
4876 uniqueValues = mDataProvider->uniqueValues( index, limit );
4877 return uniqueValues;
4878 }
4879 [[fallthrough]];
4880 //we need to go through each feature
4883 {
4884 QgsAttributeList attList;
4885 attList << index;
4886
4889 .setSubsetOfAttributes( attList ) );
4890
4891 QgsFeature f;
4892 QVariant currentValue;
4893 QHash<QString, QVariant> val;
4894 while ( fit.nextFeature( f ) )
4895 {
4896 currentValue = f.attribute( index );
4897 val.insert( currentValue.toString(), currentValue );
4898 if ( limit >= 0 && val.size() >= limit )
4899 {
4900 break;
4901 }
4902 }
4903
4904 return qgis::listToSet( val.values() );
4905 }
4906 }
4907
4908 Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
4909 return uniqueValues;
4910}
4911
4912QStringList QgsVectorLayer::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
4913{
4915
4916 QStringList results;
4917 if ( !mDataProvider )
4918 {
4919 return results;
4920 }
4921
4922 Qgis::FieldOrigin origin = mFields.fieldOrigin( index );
4923 switch ( origin )
4924 {
4926 return results;
4927
4928 case Qgis::FieldOrigin::Provider: //a provider field
4929 {
4930 results = mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
4931
4932 if ( mEditBuffer && ! mDataProvider->transaction() )
4933 {
4934 QgsFeatureMap added = mEditBuffer->addedFeatures();
4935 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4936 while ( addedIt.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
4937 {
4938 addedIt.next();
4939 QVariant v = addedIt.value().attribute( index );
4940 if ( v.isValid() )
4941 {
4942 QString vs = v.toString();
4943 if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
4944 {
4945 results << vs;
4946 }
4947 }
4948 }
4949
4950 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4951 while ( it.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
4952 {
4953 it.next();
4954 QVariant v = it.value().value( index );
4955 if ( v.isValid() )
4956 {
4957 QString vs = v.toString();
4958 if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
4959 {
4960 results << vs;
4961 }
4962 }
4963 }
4964 }
4965
4966 return results;
4967 }
4968
4970 // the layer is editable, but in certain cases it can still be avoided going through all features
4971 if ( mDataProvider->transaction() || ( mEditBuffer->deletedFeatureIds().isEmpty() &&
4972 mEditBuffer->addedFeatures().isEmpty() &&
4973 !mEditBuffer->deletedAttributeIds().contains( index ) &&
4974 mEditBuffer->changedAttributeValues().isEmpty() ) )
4975 {
4976 return mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
4977 }
4978 [[fallthrough]];
4979 //we need to go through each feature
4982 {
4983 QgsAttributeList attList;
4984 attList << index;
4985
4986 QgsFeatureRequest request;
4987 request.setSubsetOfAttributes( attList );
4989 QString fieldName = mFields.at( index ).name();
4990 request.setFilterExpression( QStringLiteral( "\"%1\" ILIKE '%%2%'" ).arg( fieldName, substring ) );
4991 QgsFeatureIterator fit = getFeatures( request );
4992
4993 QgsFeature f;
4994 QString currentValue;
4995 while ( fit.nextFeature( f ) )
4996 {
4997 currentValue = f.attribute( index ).toString();
4998 if ( !results.contains( currentValue ) )
4999 results << currentValue;
5000
5001 if ( ( limit >= 0 && results.size() >= limit ) || ( feedback && feedback->isCanceled() ) )
5002 {
5003 break;
5004 }
5005 }
5006
5007 return results;
5008 }
5009 }
5010
5011 Q_ASSERT_X( false, "QgsVectorLayer::uniqueStringsMatching()", "Unknown source of the field!" );
5012 return results;
5013}
5014
5015QVariant QgsVectorLayer::minimumValue( int index ) const
5016{
5018
5019 QVariant minimum;
5020 minimumOrMaximumValue( index, &minimum, nullptr );
5021 return minimum;
5022}
5023
5024QVariant QgsVectorLayer::maximumValue( int index ) const
5025{
5027
5028 QVariant maximum;
5029 minimumOrMaximumValue( index, nullptr, &maximum );
5030 return maximum;
5031}
5032
5033void QgsVectorLayer::minimumAndMaximumValue( int index, QVariant &minimum, QVariant &maximum ) const
5034{
5036
5037 minimumOrMaximumValue( index, &minimum, &maximum );
5038}
5039
5040void QgsVectorLayer::minimumOrMaximumValue( int index, QVariant *minimum, QVariant *maximum ) const
5041{
5043
5044 if ( minimum )
5045 *minimum = QVariant();
5046 if ( maximum )
5047 *maximum = QVariant();
5048
5049 if ( !mDataProvider )
5050 {
5051 return;
5052 }
5053
5054 Qgis::FieldOrigin origin = mFields.fieldOrigin( index );
5055
5056 switch ( origin )
5057 {
5059 {
5060 return;
5061 }
5062
5063 case Qgis::FieldOrigin::Provider: //a provider field
5064 {
5065 if ( minimum )
5066 *minimum = mDataProvider->minimumValue( index );
5067 if ( maximum )
5068 *maximum = mDataProvider->maximumValue( index );
5069 if ( mEditBuffer && ! mDataProvider->transaction() )
5070 {
5071 const QgsFeatureMap added = mEditBuffer->addedFeatures();
5072 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
5073 while ( addedIt.hasNext() )
5074 {
5075 addedIt.next();
5076 const QVariant v = addedIt.value().attribute( index );
5077 if ( minimum && v.isValid() && qgsVariantLessThan( v, *minimum ) )
5078 *minimum = v;
5079 if ( maximum && v.isValid() && qgsVariantGreaterThan( v, *maximum ) )
5080 *maximum = v;
5081 }
5082
5083 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
5084 while ( it.hasNext() )
5085 {
5086 it.next();
5087 const QVariant v = it.value().value( index );
5088 if ( minimum && v.isValid() && qgsVariantLessThan( v, *minimum ) )
5089 *minimum = v;
5090 if ( maximum && v.isValid() && qgsVariantGreaterThan( v, *maximum ) )
5091 *maximum = v;
5092 }
5093 }
5094 return;
5095 }
5096
5098 {
5099 // the layer is editable, but in certain cases it can still be avoided going through all features
5100 if ( mDataProvider->transaction() || ( mEditBuffer->deletedFeatureIds().isEmpty() &&
5101 mEditBuffer->addedFeatures().isEmpty() &&
5102 !mEditBuffer->deletedAttributeIds().contains( index ) &&
5103 mEditBuffer->changedAttributeValues().isEmpty() ) )
5104 {
5105 if ( minimum )
5106 *minimum = mDataProvider->minimumValue( index );
5107 if ( maximum )
5108 *maximum = mDataProvider->maximumValue( index );
5109 return;
5110 }
5111 }
5112 [[fallthrough]];
5113 // no choice but to go through all features
5116 {
5117 // we need to go through each feature
5118 QgsAttributeList attList;
5119 attList << index;
5120
5123 .setSubsetOfAttributes( attList ) );
5124
5125 QgsFeature f;
5126 bool firstValue = true;
5127 while ( fit.nextFeature( f ) )
5128 {
5129 const QVariant currentValue = f.attribute( index );
5130 if ( QgsVariantUtils::isNull( currentValue ) )
5131 continue;
5132
5133 if ( firstValue )
5134 {
5135 if ( minimum )
5136 *minimum = currentValue;
5137 if ( maximum )
5138 *maximum = currentValue;
5139 firstValue = false;
5140 }
5141 else
5142 {
5143 if ( minimum && currentValue.isValid() && qgsVariantLessThan( currentValue, *minimum ) )
5144 *minimum = currentValue;
5145 if ( maximum && currentValue.isValid() && qgsVariantGreaterThan( currentValue, *maximum ) )
5146 *maximum = currentValue;
5147 }
5148 }
5149 return;
5150 }
5151 }
5152
5153 Q_ASSERT_X( false, "QgsVectorLayer::minimumOrMaximumValue()", "Unknown source of the field!" );
5154}
5155
5156void QgsVectorLayer::createEditBuffer()
5157{
5159
5160 if ( mEditBuffer )
5161 clearEditBuffer();
5162
5163 if ( mDataProvider->transaction() )
5164 {
5165 mEditBuffer = new QgsVectorLayerEditPassthrough( this );
5166
5167 connect( mDataProvider->transaction(), &QgsTransaction::dirtied, this, &QgsVectorLayer::onDirtyTransaction, Qt::UniqueConnection );
5168 }
5169 else
5170 {
5171 mEditBuffer = new QgsVectorLayerEditBuffer( this );
5172 }
5173 // forward signals
5174 connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::invalidateSymbolCountedFlag );
5175 connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::layerModified ); // TODO[MD]: necessary?
5176 //connect( mEditBuffer, SIGNAL( layerModified() ), this, SLOT( triggerRepaint() ) ); // TODO[MD]: works well?
5177 connect( mEditBuffer, &QgsVectorLayerEditBuffer::featureAdded, this, &QgsVectorLayer::onFeatureAdded );
5178 connect( mEditBuffer, &QgsVectorLayerEditBuffer::featureDeleted, this, &QgsVectorLayer::onFeatureDeleted );
5189
5190}
5191
5192void QgsVectorLayer::clearEditBuffer()
5193{
5195
5196 delete mEditBuffer;
5197 mEditBuffer = nullptr;
5198}
5199
5200QVariant QgsVectorLayer::aggregate( Qgis::Aggregate aggregate, const QString &fieldOrExpression,
5202 bool *ok, QgsFeatureIds *fids, QgsFeedback *feedback, QString *error ) const
5203{
5204 // non fatal for now -- the aggregate expression functions are not thread safe and call this
5206
5207 if ( ok )
5208 *ok = false;
5209 if ( error )
5210 error->clear();
5211
5212 if ( !mDataProvider )
5213 {
5214 if ( error )
5215 *error = tr( "Layer is invalid" );
5216 return QVariant();
5217 }
5218
5219 // test if we are calculating based on a field
5220 const int attrIndex = QgsExpression::expressionToLayerFieldIndex( fieldOrExpression, this );
5221 if ( attrIndex >= 0 )
5222 {
5223 // aggregate is based on a field - if it's a provider field, we could possibly hand over the calculation
5224 // to the provider itself
5225 Qgis::FieldOrigin origin = mFields.fieldOrigin( attrIndex );
5226 if ( origin == Qgis::FieldOrigin::Provider )
5227 {
5228 bool providerOk = false;
5229 QVariant val = mDataProvider->aggregate( aggregate, attrIndex, parameters, context, providerOk, fids );
5230 if ( providerOk )
5231 {
5232 // provider handled calculation
5233 if ( ok )
5234 *ok = true;
5235 return val;
5236 }
5237 }
5238 }
5239
5240 // fallback to using aggregate calculator to determine aggregate
5241 QgsAggregateCalculator c( this );
5242 if ( fids )
5243 c.setFidsFilter( *fids );
5244 c.setParameters( parameters );
5245 bool aggregateOk = false;
5246 const QVariant result = c.calculate( aggregate, fieldOrExpression, context, &aggregateOk, feedback );
5247 if ( ok )
5248 *ok = aggregateOk;
5249 if ( !aggregateOk && error )
5250 *error = c.lastError();
5251
5252 return result;
5253}
5254
5255void QgsVectorLayer::setFeatureBlendMode( QPainter::CompositionMode featureBlendMode )
5256{
5258
5259 if ( mFeatureBlendMode == featureBlendMode )
5260 return;
5261
5262 mFeatureBlendMode = featureBlendMode;
5265}
5266
5267QPainter::CompositionMode QgsVectorLayer::featureBlendMode() const
5268{
5269 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
5271
5272 return mFeatureBlendMode;
5273}
5274
5275void QgsVectorLayer::readSldLabeling( const QDomNode &node )
5276{
5278
5279 setLabeling( nullptr ); // start with no labeling
5280 setLabelsEnabled( false );
5281
5282 QDomElement element = node.toElement();
5283 if ( element.isNull() )
5284 return;
5285
5286 QDomElement userStyleElem = element.firstChildElement( QStringLiteral( "UserStyle" ) );
5287 if ( userStyleElem.isNull() )
5288 {
5289 QgsDebugMsgLevel( QStringLiteral( "Info: UserStyle element not found." ), 4 );
5290 return;
5291 }
5292
5293 QDomElement featTypeStyleElem = userStyleElem.firstChildElement( QStringLiteral( "FeatureTypeStyle" ) );
5294 if ( featTypeStyleElem.isNull() )
5295 {
5296 QgsDebugMsgLevel( QStringLiteral( "Info: FeatureTypeStyle element not found." ), 4 );
5297 return;
5298 }
5299
5300 // create empty FeatureTypeStyle element to merge TextSymbolizer's Rule's from all FeatureTypeStyle's
5301 QDomElement mergedFeatTypeStyle = featTypeStyleElem.cloneNode( false ).toElement();
5302
5303 // use the RuleRenderer when more rules are present or the rule
5304 // has filters or min/max scale denominators set,
5305 // otherwise use the Simple labeling
5306 bool needRuleBasedLabeling = false;
5307 int ruleCount = 0;
5308
5309 while ( !featTypeStyleElem.isNull() )
5310 {
5311 QDomElement ruleElem = featTypeStyleElem.firstChildElement( QStringLiteral( "Rule" ) );
5312 while ( !ruleElem.isNull() )
5313 {
5314 // test rule children element to check if we need to create RuleRenderer
5315 // and if the rule has a symbolizer
5316 bool hasTextSymbolizer = false;
5317 bool hasRuleBased = false;
5318 QDomElement ruleChildElem = ruleElem.firstChildElement();
5319 while ( !ruleChildElem.isNull() )
5320 {
5321 // rule has filter or min/max scale denominator, use the RuleRenderer
5322 if ( ruleChildElem.localName() == QLatin1String( "Filter" ) ||
5323 ruleChildElem.localName() == QLatin1String( "MinScaleDenominator" ) ||
5324 ruleChildElem.localName() == QLatin1String( "MaxScaleDenominator" ) )
5325 {
5326 hasRuleBased = true;
5327 }
5328 // rule has a renderer symbolizer, not a text symbolizer
5329 else if ( ruleChildElem.localName() == QLatin1String( "TextSymbolizer" ) )
5330 {
5331 QgsDebugMsgLevel( QStringLiteral( "Info: TextSymbolizer element found" ), 4 );
5332 hasTextSymbolizer = true;
5333 }
5334
5335 ruleChildElem = ruleChildElem.nextSiblingElement();
5336 }
5337
5338 if ( hasTextSymbolizer )
5339 {
5340 ruleCount++;
5341
5342 // append a clone of all Rules to the merged FeatureTypeStyle element
5343 mergedFeatTypeStyle.appendChild( ruleElem.cloneNode().toElement() );
5344
5345 if ( hasRuleBased )
5346 {
5347 QgsDebugMsgLevel( QStringLiteral( "Info: Filter or Min/MaxScaleDenominator element found: need a RuleBasedLabeling" ), 4 );
5348 needRuleBasedLabeling = true;
5349 }
5350 }
5351
5352 // more rules present, use the RuleRenderer
5353 if ( ruleCount > 1 )
5354 {
5355 QgsDebugMsgLevel( QStringLiteral( "Info: More Rule elements found: need a RuleBasedLabeling" ), 4 );
5356 needRuleBasedLabeling = true;
5357 }
5358
5359 // not use the rule based labeling if no rules with textSymbolizer
5360 if ( ruleCount == 0 )
5361 {
5362 needRuleBasedLabeling = false;
5363 }
5364
5365 ruleElem = ruleElem.nextSiblingElement( QStringLiteral( "Rule" ) );
5366 }
5367 featTypeStyleElem = featTypeStyleElem.nextSiblingElement( QStringLiteral( "FeatureTypeStyle" ) );
5368 }
5369
5370 if ( ruleCount == 0 )
5371 {
5372 QgsDebugMsgLevel( QStringLiteral( "Info: No TextSymbolizer element." ), 4 );
5373 return;
5374 }
5375
5376 QDomElement ruleElem = mergedFeatTypeStyle.firstChildElement( QStringLiteral( "Rule" ) );
5377
5378 if ( needRuleBasedLabeling )
5379 {
5380 QgsDebugMsgLevel( QStringLiteral( "Info: rule based labeling" ), 4 );
5381 QgsRuleBasedLabeling::Rule *rootRule = new QgsRuleBasedLabeling::Rule( nullptr );
5382 while ( !ruleElem.isNull() )
5383 {
5384
5385 QString label, description, filterExp;
5386 int scaleMinDenom = 0, scaleMaxDenom = 0;
5387 QgsPalLayerSettings settings;
5388
5389 // retrieve the Rule element child nodes
5390 QDomElement childElem = ruleElem.firstChildElement();
5391 while ( !childElem.isNull() )
5392 {
5393 if ( childElem.localName() == QLatin1String( "Name" ) )
5394 {
5395 // <se:Name> tag contains the rule identifier,
5396 // so prefer title tag for the label property value
5397 if ( label.isEmpty() )
5398 label = childElem.firstChild().nodeValue();
5399 }
5400 else if ( childElem.localName() == QLatin1String( "Description" ) )
5401 {
5402 // <se:Description> can contains a title and an abstract
5403 QDomElement titleElem = childElem.firstChildElement( QStringLiteral( "Title" ) );
5404 if ( !titleElem.isNull() )
5405 {
5406 label = titleElem.firstChild().nodeValue();
5407 }
5408
5409 QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( "Abstract" ) );
5410 if ( !abstractElem.isNull() )
5411 {
5412 description = abstractElem.firstChild().nodeValue();
5413 }
5414 }
5415 else if ( childElem.localName() == QLatin1String( "Abstract" ) )
5416 {
5417 // <sld:Abstract> (v1.0)
5418 description = childElem.firstChild().nodeValue();
5419 }
5420 else if ( childElem.localName() == QLatin1String( "Title" ) )
5421 {
5422 // <sld:Title> (v1.0)
5423 label = childElem.firstChild().nodeValue();
5424 }
5425 else if ( childElem.localName() == QLatin1String( "Filter" ) )
5426 {
5428 if ( filter )
5429 {
5430 if ( filter->hasParserError() )
5431 {
5432 QgsDebugMsgLevel( QStringLiteral( "SLD Filter parsing error: %1" ).arg( filter->parserErrorString() ), 3 );
5433 }
5434 else
5435 {
5436 filterExp = filter->expression();
5437 }
5438 delete filter;
5439 }
5440 }
5441 else if ( childElem.localName() == QLatin1String( "MinScaleDenominator" ) )
5442 {
5443 bool ok;
5444 int v = childElem.firstChild().nodeValue().toInt( &ok );
5445 if ( ok )
5446 scaleMinDenom = v;
5447 }
5448 else if ( childElem.localName() == QLatin1String( "MaxScaleDenominator" ) )
5449 {
5450 bool ok;
5451 int v = childElem.firstChild().nodeValue().toInt( &ok );
5452 if ( ok )
5453 scaleMaxDenom = v;
5454 }
5455 else if ( childElem.localName() == QLatin1String( "TextSymbolizer" ) )
5456 {
5457 readSldTextSymbolizer( childElem, settings );
5458 }
5459
5460 childElem = childElem.nextSiblingElement();
5461 }
5462
5463 QgsRuleBasedLabeling::Rule *ruleLabeling = new QgsRuleBasedLabeling::Rule( new QgsPalLayerSettings( settings ), scaleMinDenom, scaleMaxDenom, filterExp, label );
5464 rootRule->appendChild( ruleLabeling );
5465
5466 ruleElem = ruleElem.nextSiblingElement();
5467 }
5468
5469 setLabeling( new QgsRuleBasedLabeling( rootRule ) );
5470 setLabelsEnabled( true );
5471 }
5472 else
5473 {
5474 QgsDebugMsgLevel( QStringLiteral( "Info: simple labeling" ), 4 );
5475 // retrieve the TextSymbolizer element child node
5476 QDomElement textSymbolizerElem = ruleElem.firstChildElement( QStringLiteral( "TextSymbolizer" ) );
5478 if ( readSldTextSymbolizer( textSymbolizerElem, s ) )
5479 {
5481 setLabelsEnabled( true );
5482 }
5483 }
5484}
5485
5486bool QgsVectorLayer::readSldTextSymbolizer( const QDomNode &node, QgsPalLayerSettings &settings ) const
5487{
5489
5490 if ( node.localName() != QLatin1String( "TextSymbolizer" ) )
5491 {
5492 QgsDebugMsgLevel( QStringLiteral( "Not a TextSymbolizer element: %1" ).arg( node.localName() ), 3 );
5493 return false;
5494 }
5495 QDomElement textSymbolizerElem = node.toElement();
5496 // Label
5497 QDomElement labelElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Label" ) );
5498 if ( !labelElem.isNull() )
5499 {
5500 QDomElement propertyNameElem = labelElem.firstChildElement( QStringLiteral( "PropertyName" ) );
5501 if ( !propertyNameElem.isNull() )
5502 {
5503 // set labeling defaults
5504
5505 // label attribute
5506 QString labelAttribute = propertyNameElem.text();
5507 settings.fieldName = labelAttribute;
5508 settings.isExpression = false;
5509
5510 int fieldIndex = mFields.lookupField( labelAttribute );
5511 if ( fieldIndex == -1 )
5512 {
5513 // label attribute is not in columns, check if it is an expression
5514 QgsExpression exp( labelAttribute );
5515 if ( !exp.hasEvalError() )
5516 {
5517 settings.isExpression = true;
5518 }
5519 else
5520 {
5521 QgsDebugMsgLevel( QStringLiteral( "SLD label attribute error: %1" ).arg( exp.evalErrorString() ), 3 );
5522 }
5523 }
5524 }
5525 else
5526 {
5527 QgsDebugMsgLevel( QStringLiteral( "Info: PropertyName element not found." ), 4 );
5528 return false;
5529 }
5530 }
5531 else
5532 {
5533 QgsDebugMsgLevel( QStringLiteral( "Info: Label element not found." ), 4 );
5534 return false;
5535 }
5536
5538 if ( textSymbolizerElem.hasAttribute( QStringLiteral( "uom" ) ) )
5539 {
5540 sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( textSymbolizerElem.attribute( QStringLiteral( "uom" ) ) );
5541 }
5542
5543 QString fontFamily = QStringLiteral( "Sans-Serif" );
5544 int fontPointSize = 10;
5546 int fontWeight = -1;
5547 bool fontItalic = false;
5548 bool fontUnderline = false;
5549
5550 // Font
5551 QDomElement fontElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Font" ) );
5552 if ( !fontElem.isNull() )
5553 {
5554 QgsStringMap fontSvgParams = QgsSymbolLayerUtils::getSvgParameterList( fontElem );
5555 for ( QgsStringMap::iterator it = fontSvgParams.begin(); it != fontSvgParams.end(); ++it )
5556 {
5557 QgsDebugMsgLevel( QStringLiteral( "found fontSvgParams %1: %2" ).arg( it.key(), it.value() ), 4 );
5558
5559 if ( it.key() == QLatin1String( "font-family" ) )
5560 {
5561 fontFamily = it.value();
5562 }
5563 else if ( it.key() == QLatin1String( "font-style" ) )
5564 {
5565 fontItalic = ( it.value() == QLatin1String( "italic" ) ) || ( it.value() == QLatin1String( "Italic" ) );
5566 }
5567 else if ( it.key() == QLatin1String( "font-size" ) )
5568 {
5569 bool ok;
5570 int fontSize = it.value().toInt( &ok );
5571 if ( ok )
5572 {
5573 fontPointSize = fontSize;
5574 fontUnitSize = sldUnitSize;
5575 }
5576 }
5577 else if ( it.key() == QLatin1String( "font-weight" ) )
5578 {
5579 if ( ( it.value() == QLatin1String( "bold" ) ) || ( it.value() == QLatin1String( "Bold" ) ) )
5580 fontWeight = QFont::Bold;
5581 }
5582 else if ( it.key() == QLatin1String( "font-underline" ) )
5583 {
5584 fontUnderline = ( it.value() == QLatin1String( "underline" ) ) || ( it.value() == QLatin1String( "Underline" ) );
5585 }
5586 }
5587 }
5588
5589 QgsTextFormat format;
5590 QFont font( fontFamily, fontPointSize, fontWeight, fontItalic );
5591 font.setUnderline( fontUnderline );
5592 format.setFont( font );
5593 format.setSize( fontPointSize );
5594 format.setSizeUnit( fontUnitSize );
5595
5596 // Fill
5597 QDomElement fillElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Fill" ) );
5598 QColor textColor;
5599 Qt::BrushStyle textBrush = Qt::SolidPattern;
5600 QgsSymbolLayerUtils::fillFromSld( fillElem, textBrush, textColor );
5601 if ( textColor.isValid() )
5602 {
5603 QgsDebugMsgLevel( QStringLiteral( "Info: textColor %1." ).arg( QVariant( textColor ).toString() ), 4 );
5604 format.setColor( textColor );
5605 }
5606
5607 QgsTextBufferSettings bufferSettings;
5608
5609 // Halo
5610 QDomElement haloElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Halo" ) );
5611 if ( !haloElem.isNull() )
5612 {
5613 bufferSettings.setEnabled( true );
5614 bufferSettings.setSize( 1 );
5615
5616 QDomElement radiusElem = haloElem.firstChildElement( QStringLiteral( "Radius" ) );
5617 if ( !radiusElem.isNull() )
5618 {
5619 bool ok;
5620 double bufferSize = radiusElem.text().toDouble( &ok );
5621 if ( ok )
5622 {
5623 bufferSettings.setSize( bufferSize );
5624 bufferSettings.setSizeUnit( sldUnitSize );
5625 }
5626 }
5627
5628 QDomElement haloFillElem = haloElem.firstChildElement( QStringLiteral( "Fill" ) );
5629 QColor bufferColor;
5630 Qt::BrushStyle bufferBrush = Qt::SolidPattern;
5631 QgsSymbolLayerUtils::fillFromSld( haloFillElem, bufferBrush, bufferColor );
5632 if ( bufferColor.isValid() )
5633 {
5634 QgsDebugMsgLevel( QStringLiteral( "Info: bufferColor %1." ).arg( QVariant( bufferColor ).toString() ), 4 );
5635 bufferSettings.setColor( bufferColor );
5636 }
5637 }
5638
5639 // LabelPlacement
5640 QDomElement labelPlacementElem = textSymbolizerElem.firstChildElement( QStringLiteral( "LabelPlacement" ) );
5641 if ( !labelPlacementElem.isNull() )
5642 {
5643 // PointPlacement
5644 QDomElement pointPlacementElem = labelPlacementElem.firstChildElement( QStringLiteral( "PointPlacement" ) );
5645 if ( !pointPlacementElem.isNull() )
5646 {
5649 {
5651 }
5652
5653 QDomElement displacementElem = pointPlacementElem.firstChildElement( QStringLiteral( "Displacement" ) );
5654 if ( !displacementElem.isNull() )
5655 {
5656 QDomElement displacementXElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementX" ) );
5657 if ( !displacementXElem.isNull() )
5658 {
5659 bool ok;
5660 double xOffset = displacementXElem.text().toDouble( &ok );
5661 if ( ok )
5662 {
5663 settings.xOffset = xOffset;
5664 settings.offsetUnits = sldUnitSize;
5665 }
5666 }
5667 QDomElement displacementYElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementY" ) );
5668 if ( !displacementYElem.isNull() )
5669 {
5670 bool ok;
5671 double yOffset = displacementYElem.text().toDouble( &ok );
5672 if ( ok )
5673 {
5674 settings.yOffset = yOffset;
5675 settings.offsetUnits = sldUnitSize;
5676 }
5677 }
5678 }
5679 QDomElement anchorPointElem = pointPlacementElem.firstChildElement( QStringLiteral( "AnchorPoint" ) );
5680 if ( !anchorPointElem.isNull() )
5681 {
5682 QDomElement anchorPointXElem = anchorPointElem.firstChildElement( QStringLiteral( "AnchorPointX" ) );
5683 if ( !anchorPointXElem.isNull() )
5684 {
5685 bool ok;
5686 double xOffset = anchorPointXElem.text().toDouble( &ok );
5687 if ( ok )
5688 {
5689 settings.xOffset = xOffset;
5690 settings.offsetUnits = sldUnitSize;
5691 }
5692 }
5693 QDomElement anchorPointYElem = anchorPointElem.firstChildElement( QStringLiteral( "AnchorPointY" ) );
5694 if ( !anchorPointYElem.isNull() )
5695 {
5696 bool ok;
5697 double yOffset = anchorPointYElem.text().toDouble( &ok );
5698 if ( ok )
5699 {
5700 settings.yOffset = yOffset;
5701 settings.offsetUnits = sldUnitSize;
5702 }
5703 }
5704 }
5705
5706 QDomElement rotationElem = pointPlacementElem.firstChildElement( QStringLiteral( "Rotation" ) );
5707 if ( !rotationElem.isNull() )
5708 {
5709 bool ok;
5710 double rotation = rotationElem.text().toDouble( &ok );
5711 if ( ok )
5712 {
5713 settings.angleOffset = 360 - rotation;
5714 }
5715 }
5716 }
5717 else
5718 {
5719 // PointPlacement
5720 QDomElement linePlacementElem = labelPlacementElem.firstChildElement( QStringLiteral( "LinePlacement" ) );
5721 if ( !linePlacementElem.isNull() )
5722 {
5724 }
5725 }
5726 }
5727
5728 // read vendor options
5729 QgsStringMap vendorOptions;
5730 QDomElement vendorOptionElem = textSymbolizerElem.firstChildElement( QStringLiteral( "VendorOption" ) );
5731 while ( !vendorOptionElem.isNull() && vendorOptionElem.localName() == QLatin1String( "VendorOption" ) )
5732 {
5733 QString optionName = vendorOptionElem.attribute( QStringLiteral( "name" ) );
5734 QString optionValue;
5735 if ( vendorOptionElem.firstChild().nodeType() == QDomNode::TextNode )
5736 {
5737 optionValue = vendorOptionElem.firstChild().nodeValue();
5738 }
5739 else
5740 {
5741 if ( vendorOptionElem.firstChild().nodeType() == QDomNode::ElementNode &&
5742 vendorOptionElem.firstChild().localName() == QLatin1String( "Literal" ) )
5743 {
5744 QgsDebugMsgLevel( vendorOptionElem.firstChild().localName(), 2 );
5745 optionValue = vendorOptionElem.firstChild().firstChild().nodeValue();
5746 }
5747 else
5748 {
5749 QgsDebugError( QStringLiteral( "unexpected child of %1 named %2" ).arg( vendorOptionElem.localName(), optionName ) );
5750 }
5751 }
5752
5753 if ( !optionName.isEmpty() && !optionValue.isEmpty() )
5754 {
5755 vendorOptions[ optionName ] = optionValue;
5756 }
5757
5758 vendorOptionElem = vendorOptionElem.nextSiblingElement();
5759 }
5760 if ( !vendorOptions.isEmpty() )
5761 {
5762 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
5763 {
5764 if ( it.key() == QLatin1String( "underlineText" ) && it.value() == QLatin1String( "true" ) )
5765 {
5766 font.setUnderline( true );
5767 format.setFont( font );
5768 }
5769 else if ( it.key() == QLatin1String( "strikethroughText" ) && it.value() == QLatin1String( "true" ) )
5770 {
5771 font.setStrikeOut( true );
5772 format.setFont( font );
5773 }
5774 else if ( it.key() == QLatin1String( "maxDisplacement" ) )
5775 {
5777 }
5778 else if ( it.key() == QLatin1String( "followLine" ) && it.value() == QLatin1String( "true" ) )
5779 {
5781 {
5783 }
5784 else
5785 {
5787 }
5788 }
5789 else if ( it.key() == QLatin1String( "maxAngleDelta" ) )
5790 {
5791 bool ok;
5792 double angle = it.value().toDouble( &ok );
5793 if ( ok )
5794 {
5795 settings.maxCurvedCharAngleIn = angle;
5796 settings.maxCurvedCharAngleOut = angle;
5797 }
5798 }
5799 // miscellaneous options
5800 else if ( it.key() == QLatin1String( "conflictResolution" ) && it.value() == QLatin1String( "false" ) )
5801 {
5803 }
5804 else if ( it.key() == QLatin1String( "forceLeftToRight" ) && it.value() == QLatin1String( "false" ) )
5805 {
5807 }
5808 else if ( it.key() == QLatin1String( "group" ) && it.value() == QLatin1String( "yes" ) )
5809 {
5810 settings.lineSettings().setMergeLines( true );
5811 }
5812 else if ( it.key() == QLatin1String( "labelAllGroup" ) && it.value() == QLatin1String( "true" ) )
5813 {
5814 settings.lineSettings().setMergeLines( true );
5815 }
5816 }
5817 }
5818
5819 format.setBuffer( bufferSettings );
5820 settings.setFormat( format );
5821 return true;
5822}
5823
5825{
5827
5828 return mEditFormConfig;
5829}
5830
5832{
5834
5835 if ( mEditFormConfig == editFormConfig )
5836 return;
5837
5838 mEditFormConfig = editFormConfig;
5839 mEditFormConfig.onRelationsLoaded();
5840 emit editFormConfigChanged();
5841}
5842
5844{
5846
5847 QgsAttributeTableConfig config = mAttributeTableConfig;
5848
5849 if ( config.isEmpty() )
5850 config.update( fields() );
5851
5852 return config;
5853}
5854
5856{
5858
5859 if ( mAttributeTableConfig != attributeTableConfig )
5860 {
5861 mAttributeTableConfig = attributeTableConfig;
5862 emit configChanged();
5863 }
5864}
5865
5867{
5868 // called in a non-thread-safe way in some cases when calculating aggregates in a different thread
5870
5872}
5873
5880
5882{
5884
5885 if ( !mDiagramLayerSettings )
5886 mDiagramLayerSettings = new QgsDiagramLayerSettings();
5887 *mDiagramLayerSettings = s;
5888}
5889
5891{
5893
5894 QgsLayerMetadataFormatter htmlFormatter( metadata() );
5895 QString myMetadata = QStringLiteral( "<html><head></head>\n<body>\n" );
5896
5897 myMetadata += generalHtmlMetadata();
5898
5899 // Begin Provider section
5900 myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
5901 myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
5902
5903 // storage type
5904 if ( !storageType().isEmpty() )
5905 {
5906 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Storage" ) + QStringLiteral( "</td><td>" ) + storageType() + QStringLiteral( "</td></tr>\n" );
5907 }
5908
5909 // comment
5910 if ( !dataComment().isEmpty() )
5911 {
5912 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Comment" ) + QStringLiteral( "</td><td>" ) + dataComment() + QStringLiteral( "</td></tr>\n" );
5913 }
5914
5915 // encoding
5916 if ( const QgsVectorDataProvider *provider = dataProvider() )
5917 {
5918 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Encoding" ) + QStringLiteral( "</td><td>" ) + provider->encoding() + QStringLiteral( "</td></tr>\n" );
5919 myMetadata += provider->htmlMetadata();
5920 }
5921
5922 if ( isSpatial() )
5923 {
5924 // geom type
5926 if ( static_cast<int>( type ) < 0 || static_cast< int >( type ) > static_cast< int >( Qgis::GeometryType::Null ) )
5927 {
5928 QgsDebugMsgLevel( QStringLiteral( "Invalid vector type" ), 2 );
5929 }
5930 else
5931 {
5932 QString typeString( QStringLiteral( "%1 (%2)" ).arg( QgsWkbTypes::geometryDisplayString( geometryType() ),
5934 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Geometry" ) + QStringLiteral( "</td><td>" ) + typeString + QStringLiteral( "</td></tr>\n" );
5935 }
5936
5937 // Extent
5938 // Try to display extent 3D by default. If empty (probably because the data is 2D), fallback to the 2D version
5939 const QgsBox3D extentBox3D = extent3D();
5940 const QString extentAsStr = !extentBox3D.isEmpty() ? extentBox3D.toString() : extent().toString();
5941 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extentAsStr + QStringLiteral( "</td></tr>\n" );
5942 }
5943
5944 // feature count
5945 QLocale locale = QLocale();
5946 locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
5947 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
5948 + tr( "Feature count" ) + QStringLiteral( "</td><td>" )
5949 + ( featureCount() == -1 ? tr( "unknown" ) : locale.toString( static_cast<qlonglong>( featureCount() ) ) )
5950 + QStringLiteral( "</td></tr>\n" );
5951
5952 // End Provider section
5953 myMetadata += QLatin1String( "</table>\n<br><br>" );
5954
5955 if ( isSpatial() )
5956 {
5957 // CRS
5958 myMetadata += crsHtmlMetadata();
5959 }
5960
5961 // identification section
5962 myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
5963 myMetadata += htmlFormatter.identificationSectionHtml( );
5964 myMetadata += QLatin1String( "<br><br>\n" );
5965
5966 // extent section
5967 myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
5968 myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
5969 myMetadata += QLatin1String( "<br><br>\n" );
5970
5971 // Start the Access section
5972 myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
5973 myMetadata += htmlFormatter.accessSectionHtml( );
5974 myMetadata += QLatin1String( "<br><br>\n" );
5975
5976 // Fields section
5977 myMetadata += QStringLiteral( "<h1>" ) + tr( "Fields" ) + QStringLiteral( "</h1>\n<hr>\n<table class=\"list-view\">\n" );
5978
5979 // primary key
5981 if ( !pkAttrList.isEmpty() )
5982 {
5983 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Primary key attributes" ) + QStringLiteral( "</td><td>" );
5984 const auto constPkAttrList = pkAttrList;
5985 for ( int idx : constPkAttrList )
5986 {
5987 myMetadata += fields().at( idx ).name() + ' ';
5988 }
5989 myMetadata += QLatin1String( "</td></tr>\n" );
5990 }
5991
5992 const QgsFields myFields = fields();
5993
5994 // count fields
5995 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Count" ) + QStringLiteral( "</td><td>" ) + QString::number( myFields.size() ) + QStringLiteral( "</td></tr>\n" );
5996
5997 myMetadata += QLatin1String( "</table>\n<br><table width=\"100%\" class=\"tabular-view\">\n" );
5998 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" );
5999
6000 for ( int i = 0; i < myFields.size(); ++i )
6001 {
6002 QgsField myField = myFields.at( i );
6003 QString rowClass;
6004 if ( i % 2 )
6005 rowClass = QStringLiteral( "class=\"odd-row\"" );
6006 myMetadata += QLatin1String( "<tr " ) + rowClass + QLatin1String( "><td>" ) + myField.displayNameWithAlias() + 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" );
6007 }
6008
6009 //close field list
6010 myMetadata += QLatin1String( "</table>\n<br><br>" );
6011
6012 // Start the contacts section
6013 myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
6014 myMetadata += htmlFormatter.contactsSectionHtml( );
6015 myMetadata += QLatin1String( "<br><br>\n" );
6016
6017 // Start the links section
6018 myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
6019 myMetadata += htmlFormatter.linksSectionHtml( );
6020 myMetadata += QLatin1String( "<br><br>\n" );
6021
6022 // Start the history section
6023 myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
6024 myMetadata += htmlFormatter.historySectionHtml( );
6025 myMetadata += QLatin1String( "<br><br>\n" );
6026
6027 myMetadata += customPropertyHtmlMetadata();
6028
6029 myMetadata += QLatin1String( "\n</body>\n</html>\n" );
6030 return myMetadata;
6031}
6032
6033void QgsVectorLayer::invalidateSymbolCountedFlag()
6034{
6036
6037 mSymbolFeatureCounted = false;
6038}
6039
6040void QgsVectorLayer::onFeatureCounterCompleted()
6041{
6043
6044 onSymbolsCounted();
6045 mFeatureCounter = nullptr;
6046}
6047
6048void QgsVectorLayer::onFeatureCounterTerminated()
6049{
6051
6052 mFeatureCounter = nullptr;
6053}
6054
6055void QgsVectorLayer::onJoinedFieldsChanged()
6056{
6058
6059 // some of the fields of joined layers have changed -> we need to update this layer's fields too
6060 updateFields();
6061}
6062
6063void QgsVectorLayer::onFeatureAdded( QgsFeatureId fid )
6064{
6066
6067 updateExtents();
6068
6069 emit featureAdded( fid );
6070}
6071
6072void QgsVectorLayer::onFeatureDeleted( QgsFeatureId fid )
6073{
6075
6076 updateExtents();
6077
6078 if ( mEditCommandActive || mCommitChangesActive )
6079 {
6080 mDeletedFids << fid;
6081 }
6082 else
6083 {
6084 mSelectedFeatureIds.remove( fid );
6085 emit featuresDeleted( QgsFeatureIds() << fid );
6086 }
6087
6088 emit featureDeleted( fid );
6089}
6090
6091void QgsVectorLayer::onRelationsLoaded()
6092{
6094
6095 mEditFormConfig.onRelationsLoaded();
6096}
6097
6098void QgsVectorLayer::onSymbolsCounted()
6099{
6101
6102 if ( mFeatureCounter )
6103 {
6104 mSymbolFeatureCounted = true;
6105 mSymbolFeatureCountMap = mFeatureCounter->symbolFeatureCountMap();
6106 mSymbolFeatureIdMap = mFeatureCounter->symbolFeatureIdMap();
6108 }
6109}
6110
6111QList<QgsRelation> QgsVectorLayer::referencingRelations( int idx ) const
6112{
6114
6115 if ( QgsProject *p = project() )
6116 return p->relationManager()->referencingRelations( this, idx );
6117 else
6118 return {};
6119}
6120
6121QList<QgsWeakRelation> QgsVectorLayer::weakRelations() const
6122{
6124
6125 return mWeakRelations;
6126}
6127
6128void QgsVectorLayer::setWeakRelations( const QList<QgsWeakRelation> &relations )
6129{
6131
6132 mWeakRelations = relations;
6133}
6134
6135bool QgsVectorLayer::loadAuxiliaryLayer( const QgsAuxiliaryStorage &storage, const QString &key )
6136{
6138
6139 bool rc = false;
6140
6141 QString joinKey = mAuxiliaryLayerKey;
6142 if ( !key.isEmpty() )
6143 joinKey = key;
6144
6145 if ( storage.isValid() && !joinKey.isEmpty() )
6146 {
6147 QgsAuxiliaryLayer *alayer = nullptr;
6148
6149 int idx = fields().lookupField( joinKey );
6150
6151 if ( idx >= 0 )
6152 {
6153 alayer = storage.createAuxiliaryLayer( fields().field( idx ), this );
6154
6155 if ( alayer )
6156 {
6157 setAuxiliaryLayer( alayer );
6158 rc = true;
6159 }
6160 }
6161 }
6162
6163 return rc;
6164}
6165
6167{
6169
6170 mAuxiliaryLayerKey.clear();
6171
6172 if ( mAuxiliaryLayer )
6173 removeJoin( mAuxiliaryLayer->id() );
6174
6175 if ( alayer )
6176 {
6177 addJoin( alayer->joinInfo() );
6178
6179 if ( !alayer->isEditable() )
6180 alayer->startEditing();
6181
6182 mAuxiliaryLayerKey = alayer->joinInfo().targetFieldName();
6183 }
6184
6185 mAuxiliaryLayer.reset( alayer );
6186 if ( mAuxiliaryLayer )
6187 mAuxiliaryLayer->setParent( this );
6188 updateFields();
6189}
6190
6192{
6194
6195 return mAuxiliaryLayer.get();
6196}
6197
6199{
6201
6202 return mAuxiliaryLayer.get();
6203}
6204
6205QSet<QgsMapLayerDependency> QgsVectorLayer::dependencies() const
6206{
6208
6209 if ( mDataProvider )
6210 return mDataProvider->dependencies() + mDependencies;
6211 return mDependencies;
6212}
6213
6214void QgsVectorLayer::emitDataChanged()
6215{
6217
6218 if ( mDataChangedFired )
6219 return;
6220
6221 // If we are asked to fire dataChanged from a layer we depend on,
6222 // be sure that this layer is not in the process of committing its changes, because
6223 // we will be asked to fire dataChanged at the end of his commit, and we don't
6224 // want to fire this signal more than necessary.
6225 if ( QgsVectorLayer *layerWeDependUpon = qobject_cast<QgsVectorLayer *>( sender() );
6226 layerWeDependUpon && layerWeDependUpon->mCommitChangesActive )
6227 return;
6228
6229 updateExtents(); // reset cached extent to reflect data changes
6230
6231 mDataChangedFired = true;
6232 emit dataChanged();
6233 mDataChangedFired = false;
6234}
6235
6236bool QgsVectorLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
6237{
6239
6240 QSet<QgsMapLayerDependency> deps;
6241 const auto constODeps = oDeps;
6242 for ( const QgsMapLayerDependency &dep : constODeps )
6243 {
6244 if ( dep.origin() == QgsMapLayerDependency::FromUser )
6245 deps << dep;
6246 }
6247
6248 QSet<QgsMapLayerDependency> toAdd = deps - dependencies();
6249
6250 // disconnect layers that are not present in the list of dependencies anymore
6251 if ( QgsProject *p = project() )
6252 {
6253 for ( const QgsMapLayerDependency &dep : std::as_const( mDependencies ) )
6254 {
6255 QgsVectorLayer *lyr = static_cast<QgsVectorLayer *>( p->mapLayer( dep.layerId() ) );
6256 if ( !lyr )
6257 continue;
6258 disconnect( lyr, &QgsVectorLayer::featureAdded, this, &QgsVectorLayer::emitDataChanged );
6259 disconnect( lyr, &QgsVectorLayer::featureDeleted, this, &QgsVectorLayer::emitDataChanged );
6260 disconnect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
6261 disconnect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );
6263 disconnect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::emitDataChanged );
6264 }
6265 }
6266
6267 // assign new dependencies
6268 if ( mDataProvider )
6269 mDependencies = mDataProvider->dependencies() + deps;
6270 else
6271 mDependencies = deps;
6272 emit dependenciesChanged();
6273
6274 // connect to new layers
6275 if ( QgsProject *p = project() )
6276 {
6277 for ( const QgsMapLayerDependency &dep : std::as_const( mDependencies ) )
6278 {
6279 QgsVectorLayer *lyr = static_cast<QgsVectorLayer *>( p->mapLayer( dep.layerId() ) );
6280 if ( !lyr )
6281 continue;
6282 connect( lyr, &QgsVectorLayer::featureAdded, this, &QgsVectorLayer::emitDataChanged );
6283 connect( lyr, &QgsVectorLayer::featureDeleted, this, &QgsVectorLayer::emitDataChanged );
6284 connect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
6285 connect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );
6287 connect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::emitDataChanged );
6288 }
6289 }
6290
6291 // if new layers are present, emit a data change
6292 if ( ! toAdd.isEmpty() )
6293 emitDataChanged();
6294
6295 return true;
6296}
6297
6299{
6301
6302 if ( fieldIndex < 0 || fieldIndex >= mFields.count() || !mDataProvider )
6304
6305 QgsFieldConstraints::Constraints constraints = mFields.at( fieldIndex ).constraints().constraints();
6306
6307 // make sure provider constraints are always present!
6308 if ( mFields.fieldOrigin( fieldIndex ) == Qgis::FieldOrigin::Provider )
6309 {
6310 constraints |= mDataProvider->fieldConstraints( mFields.fieldOriginIndex( fieldIndex ) );
6311 }
6312
6313 return constraints;
6314}
6315
6316QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength> QgsVectorLayer::fieldConstraintsAndStrength( int fieldIndex ) const
6317{
6319
6320 QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength > m;
6321
6322 if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
6323 return m;
6324
6325 QString name = mFields.at( fieldIndex ).name();
6326
6327 QMap< QPair< QString, QgsFieldConstraints::Constraint >, QgsFieldConstraints::ConstraintStrength >::const_iterator conIt = mFieldConstraintStrength.constBegin();
6328 for ( ; conIt != mFieldConstraintStrength.constEnd(); ++conIt )
6329 {
6330 if ( conIt.key().first == name )
6331 {
6332 m[ conIt.key().second ] = mFieldConstraintStrength.value( conIt.key() );
6333 }
6334 }
6335
6336 return m;
6337}
6338
6340{
6342
6343 if ( index < 0 || index >= mFields.count() )
6344 return;
6345
6346 QString name = mFields.at( index ).name();
6347
6348 // add constraint to existing constraints
6349 QgsFieldConstraints::Constraints constraints = mFieldConstraints.value( name, QgsFieldConstraints::Constraints() );
6350 constraints |= constraint;
6351 mFieldConstraints.insert( name, constraints );
6352
6353 mFieldConstraintStrength.insert( qMakePair( name, constraint ), strength );
6354
6355 updateFields();
6356}
6357
6359{
6361
6362 if ( index < 0 || index >= mFields.count() )
6363 return;
6364
6365 QString name = mFields.at( index ).name();
6366
6367 // remove constraint from existing constraints
6368 QgsFieldConstraints::Constraints constraints = mFieldConstraints.value( name, QgsFieldConstraints::Constraints() );
6369 constraints &= ~constraint;
6370 mFieldConstraints.insert( name, constraints );
6371
6372 mFieldConstraintStrength.remove( qMakePair( name, constraint ) );
6373
6374 updateFields();
6375}
6376
6378{
6380
6381 if ( index < 0 || index >= mFields.count() )
6382 return QString();
6383
6384 return mFields.at( index ).constraints().constraintExpression();
6385}
6386
6388{
6390
6391 if ( index < 0 || index >= mFields.count() )
6392 return QString();
6393
6394 return mFields.at( index ).constraints().constraintDescription();
6395}
6396
6397void QgsVectorLayer::setConstraintExpression( int index, const QString &expression, const QString &description )
6398{
6400
6401 if ( index < 0 || index >= mFields.count() )
6402 return;
6403
6404 if ( expression.isEmpty() )
6405 {
6406 mFieldConstraintExpressions.remove( mFields.at( index ).name() );
6407 }
6408 else
6409 {
6410 mFieldConstraintExpressions.insert( mFields.at( index ).name(), qMakePair( expression, description ) );
6411 }
6412 updateFields();
6413}
6414
6416{
6418
6419 if ( index < 0 || index >= mFields.count() )
6420 return;
6421
6422 mFieldConfigurationFlags.insert( mFields.at( index ).name(), flags );
6423 updateFields();
6424}
6425
6427{
6429
6430 if ( index < 0 || index >= mFields.count() )
6431 return;
6433 flags.setFlag( flag, active );
6435}
6436
6438{
6440
6441 if ( index < 0 || index >= mFields.count() )
6443
6444 return mFields.at( index ).configurationFlags();
6445}
6446
6448{
6450
6451 if ( index < 0 || index >= mFields.count() )
6452 return;
6453
6454 if ( setup.isNull() )
6455 mFieldWidgetSetups.remove( mFields.at( index ).name() );
6456 else
6457 mFieldWidgetSetups.insert( mFields.at( index ).name(), setup );
6458 updateFields();
6459}
6460
6462{
6464
6465 if ( index < 0 || index >= mFields.count() )
6466 return QgsEditorWidgetSetup();
6467
6468 return mFields.at( index ).editorWidgetSetup();
6469}
6470
6471QgsAbstractVectorLayerLabeling *QgsVectorLayer::readLabelingFromCustomProperties()
6472{
6474
6476 if ( customProperty( QStringLiteral( "labeling" ) ).toString() == QLatin1String( "pal" ) )
6477 {
6478 if ( customProperty( QStringLiteral( "labeling/enabled" ), QVariant( false ) ).toBool() )
6479 {
6480 // try to load from custom properties
6481 QgsPalLayerSettings settings;
6482 settings.readFromLayerCustomProperties( this );
6483 labeling = new QgsVectorLayerSimpleLabeling( settings );
6484 }
6485
6486 // also clear old-style labeling config
6487 removeCustomProperty( QStringLiteral( "labeling" ) );
6488 const auto constCustomPropertyKeys = customPropertyKeys();
6489 for ( const QString &key : constCustomPropertyKeys )
6490 {
6491 if ( key.startsWith( QLatin1String( "labeling/" ) ) )
6492 removeCustomProperty( key );
6493 }
6494 }
6495
6496 return labeling;
6497}
6498
6500{
6502
6503 return mAllowCommit;
6504}
6505
6506void QgsVectorLayer::setAllowCommit( bool allowCommit )
6507{
6509
6510 if ( mAllowCommit == allowCommit )
6511 return;
6512
6513 mAllowCommit = allowCommit;
6514 emit allowCommitChanged();
6515}
6516
6518{
6520
6521 return mGeometryOptions.get();
6522}
6523
6524void QgsVectorLayer::setReadExtentFromXml( bool readExtentFromXml )
6525{
6527
6528 mReadExtentFromXml = readExtentFromXml;
6529}
6530
6532{
6534
6535 return mReadExtentFromXml;
6536}
6537
6538void QgsVectorLayer::onDirtyTransaction( const QString &sql, const QString &name )
6539{
6541
6543 if ( tr && mEditBuffer )
6544 {
6545 qobject_cast<QgsVectorLayerEditPassthrough *>( mEditBuffer )->update( tr, sql, name );
6546 }
6547}
6548
6549QList<QgsVectorLayer *> QgsVectorLayer::DeleteContext::handledLayers( bool includeAuxiliaryLayers ) const
6550{
6551 QList<QgsVectorLayer *> layers;
6552 QMap<QgsVectorLayer *, QgsFeatureIds>::const_iterator i;
6553 for ( i = mHandledFeatures.begin(); i != mHandledFeatures.end(); ++i )
6554 {
6555 if ( includeAuxiliaryLayers || !qobject_cast< QgsAuxiliaryLayer * >( i.key() ) )
6556 layers.append( i.key() );
6557 }
6558 return layers;
6559}
6560
6562{
6563 return mHandledFeatures[layer];
6564}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:54
@ SelectAtId
Fast access to features using their ID.
@ CreateRenderer
Provider can create feature renderers using backend-specific formatting information....
@ CreateLabeling
Provider can set labeling settings using backend-specific formatting information. Since QGIS 3....
@ ReadLayerMetadata
Provider can read layer metadata from data store. Since QGIS 3.0. See QgsDataProvider::layerMetadata(...
@ DeleteFeatures
Allows deletion of features.
QFlags< VectorRenderingSimplificationFlag > VectorRenderingSimplificationFlags
Simplification flags for vector feature rendering.
Definition qgis.h:2973
@ Composition
Fix relation, related elements are part of the parent and a parent copy will copy any children or del...
@ Association
Loose relation, related elements are not part of the parent and a parent copy will not copy any child...
GeometryOperationResult
Success or failure of a geometry operation.
Definition qgis.h:2005
@ InvalidInputGeometryType
The input geometry (ring, part, split line, etc.) has not the correct geometry type.
@ Success
Operation succeeded.
@ SelectionIsEmpty
No features were selected.
@ AddRingNotInExistingFeature
The input ring doesn't have any existing ring to fit into.
@ AddRingNotClosed
The input ring is not closed.
@ SelectionIsGreaterThanOne
More than one features were selected.
@ LayerNotEditable
Cannot edit layer.
SpatialIndexPresence
Enumeration of spatial index presence states.
Definition qgis.h:522
@ Unknown
Spatial index presence cannot be determined, index may or may not exist.
VectorRenderingSimplificationFlag
Simplification flags for vector feature rendering.
Definition qgis.h:2958
@ NoSimplification
No simplification can be applied.
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
@ Curved
Arranges candidates following the curvature of a line feature. Applies to line layers only.
@ AroundPoint
Arranges candidates in a circle around a point (or centroid of a polygon). Applies to point or polygo...
@ Line
Arranges candidates parallel to a generalised line representing the feature or parallel to a polygon'...
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
@ PerimeterCurved
Arranges candidates following the curvature of a polygon's boundary. Applies to polygon layers only.
QFlags< VectorLayerTypeFlag > VectorLayerTypeFlags
Vector layer type flags.
Definition qgis.h:395
VectorSimplificationAlgorithm
Simplification algorithms for vector features.
Definition qgis.h:2942
@ Distance
The simplification uses the distance between points to remove duplicate points.
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
@ SubsetOfAttributes
Fetch only a subset of attributes (setSubsetOfAttributes sets this flag)
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
@ FastExtent3D
Provider's 3D extent retrieval via QgsDataProvider::extent3D() is always guaranteed to be trivial/fas...
@ FastExtent2D
Provider's 2D extent retrieval via QgsDataProvider::extent() is always guaranteed to be trivial/fast ...
@ BufferedGroups
Buffered transactional editing means that all editable layers in the buffered transaction group are t...
FieldDomainMergePolicy
Merge policy for field domains.
Definition qgis.h:3824
@ UnsetField
Clears the field value so that the data provider backend will populate using any backend triggers or ...
FieldDomainSplitPolicy
Split policy for field domains.
Definition qgis.h:3807
@ Duplicate
Duplicate original value.
BlendMode
Blending modes defining the available composition modes that can be used when painting.
Definition qgis.h:4811
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition qgis.h:337
@ Polygon
Polygons.
@ Unknown
Unknown types.
@ Null
No geometry.
@ Generated
A generated relation is a child of a polymorphic relation.
@ Normal
A normal relation.
FieldDuplicatePolicy
Duplicate policy for fields.
Definition qgis.h:3844
@ Duplicate
Duplicate original value.
static const float DEFAULT_MAPTOPIXEL_THRESHOLD
Default threshold between map coordinates and device coordinates for map2pixel simplification.
Definition qgis.h:5985
QFlags< DataProviderReadFlag > DataProviderReadFlags
Flags which control data provider construction.
Definition qgis.h:450
FeatureAvailability
Possible return value for QgsFeatureSource::hasFeatures() to determine if a source is empty.
Definition qgis.h:541
@ FeaturesMaybeAvailable
There may be features available in this source.
@ FeaturesAvailable
There is at least one feature available in this source.
@ NoFeaturesAvailable
There are certainly no features available in this source.
@ Vector
Vector layer.
FieldOrigin
Field origin.
Definition qgis.h:1667
@ Provider
Field originates from the underlying data provider of the vector layer.
@ Edit
Field has been temporarily added in editing mode.
@ Unknown
The field origin has not been specified.
@ Expression
Field is calculated from an expression.
@ Join
Field originates from a joined layer.
RenderUnit
Rendering size units.
Definition qgis.h:5064
@ Points
Points (e.g., for font sizes)
@ LoadDefaultStyle
Reset the layer's style to the default for the datasource.
@ ForceReadOnly
Open layer in a read-only mode.
Aggregate
Available aggregates to calculate.
Definition qgis.h:5681
VertexMarkerType
Editing vertex markers, used for showing vertices during a edit operation.
Definition qgis.h:1796
@ SemiTransparentCircle
Semi-transparent circle marker.
@ Cross
Cross marker.
VectorEditResult
Specifies the result of a vector layer edit operation.
Definition qgis.h:1781
@ Success
Edit operation was successful.
@ InvalidLayer
Edit failed due to invalid layer.
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:256
@ Unknown
Unknown.
FieldConfigurationFlag
Configuration flags for fields These flags are meant to be user-configurable and are not describing a...
Definition qgis.h:1684
@ HideFromWfs
Field is not available if layer is served as WFS from QGIS server.
@ NoFlag
No flag is defined.
@ HideFromWms
Field is not available if layer is served as WMS from QGIS server.
@ AllowOverlapIfRequired
Avoids overlapping labels when possible, but permit overlaps if labels for features cannot otherwise ...
QFlags< FieldConfigurationFlag > FieldConfigurationFlags
Configuration flags for fields These flags are meant to be user-configurable and are not describing a...
Definition qgis.h:1699
@ AlwaysAllowUpsideDown
Show upside down for all labels, including dynamic ones.
SelectBehavior
Specifies how a selection should be applied.
Definition qgis.h:1734
@ SetSelection
Set selection, removing any existing selection.
@ AddToSelection
Add selection to current selection.
@ IntersectSelection
Modify current selection to include only select features which match.
@ RemoveFromSelection
Remove from current selection.
Abstract base class for objects which generate elevation profiles.
virtual bool writeXml(QDomElement &collectionElem, const QgsPropertiesDefinition &definitions) const
Writes the current state of the property collection into an XML element.
Abstract base class - its implementations define different approaches to the labeling of a vector lay...
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the labeling...
virtual Q_DECL_DEPRECATED void toSld(QDomNode &parent, const QVariantMap &props) const
Writes the SE 1.1 TextSymbolizer element based on the current layer labeling settings.
static QgsAbstractVectorLayerLabeling * create(const QDomElement &element, const QgsReadWriteContext &context)
Try to create instance of an implementation based on the XML data.
virtual QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) const =0
Returns labeling configuration as XML element.
Storage and management of actions associated with a layer.
bool writeXml(QDomNode &layer_node) const
Writes the actions out in XML format.
QList< QgsAction > actions(const QString &actionScope=QString()) const
Returns a list of actions that are available in the given action scope.
QUuid addAction(Qgis::AttributeActionType type, const QString &name, const QString &command, bool capture=false)
Add an action with the given name and action details.
bool readXml(const QDomNode &layer_node)
Reads the actions in in XML format.
Utility class that encapsulates an action based on vector attributes.
Definition qgsaction.h:37
Utility class for calculating aggregates for a field (or expression) over the features from a vector ...
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling.
A container for configuration of the attribute table.
void readXml(const QDomNode &node)
Deserialize to XML on layer load.
void update(const QgsFields &fields)
Update the configuration with the given fields.
void writeXml(QDomNode &node) const
Serialize to XML on layer save.
A vector of attributes.
Allows managing the auxiliary storage for a vector layer.
QgsVectorLayerJoinInfo joinInfo() const
Returns information to use for joining with primary key and so on.
Providing some utility methods to manage auxiliary storage.
QgsAuxiliaryLayer * createAuxiliaryLayer(const QgsField &field, QgsVectorLayer *layer) const
Creates an auxiliary layer for a vector layer.
bool isValid() const
Returns the status of the auxiliary storage currently defined.
A 3-dimensional box composed of x, y, z coordinates.
Definition qgsbox3d.h:43
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin,zmin : xmax,ymax,zmax Coordinates will be truncated...
Definition qgsbox3d.cpp:325
bool isNull() const
Test if the box is null (holding no spatial information).
Definition qgsbox3d.cpp:310
bool isEmpty() const
Returns true if the box is empty.
Definition qgsbox3d.cpp:320
Holds conditional style information for a layer.
bool readXml(const QDomNode &node, const QgsReadWriteContext &context)
Reads the condition styles state from a DOM node.
bool writeXml(QDomNode &node, QDomDocument &doc, const QgsReadWriteContext &context) const
Writes the condition styles state to a DOM node.
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Contains information about the context in which a coordinate transform is executed.
Abstract base class for curved geometry type.
Definition qgscurve.h:35
virtual bool isClosed() const
Returns true if the curve is closed.
Definition qgscurve.cpp:53
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
virtual bool containsElevationData() const
Returns true if the data provider definitely contains elevation related data.
virtual bool leaveUpdateMode()
Leave update mode.
virtual QString subsetString() const
Returns the subset definition string currently in use by the layer and used by the provider to limit ...
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
virtual Qgis::DataProviderFlags flags() const
Returns the generic data provider flags.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
void dataChanged()
Emitted whenever a change is made to the data provider which may have caused changes in the provider'...
void fullExtentCalculated()
Emitted whenever a deferred extent calculation is completed by the provider.
virtual Qgis::ProviderStyleStorageCapabilities styleStorageCapabilities() const
Returns the style storage capabilities.
virtual QgsBox3D extent3D() const
Returns the 3D extent of the layer.
virtual QgsLayerMetadata layerMetadata() const
Returns layer metadata collected from the provider's source.
virtual bool isValid() const =0
Returns true if this is a valid layer.
virtual bool setSubsetString(const QString &subset, bool updateFeatureCount=true)
Set the subset string used to create a subset of features in the layer.
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
virtual void updateExtents()
Update the extents of the layer.
virtual void reloadData()
Reloads the data from the source for providers with data caches to synchronize, changes in the data s...
virtual bool enterUpdateMode()
Enter update mode.
virtual QgsRectangle extent() const =0
Returns the extent of the layer.
virtual void setTransformContext(const QgsCoordinateTransformContext &transformContext)
Sets data coordinate transform context to transformContext.
Stores the component parts of a data source URI (e.g.
bool useEstimatedMetadata() const
Returns true if estimated metadata should be used for the connection.
Provides a container for managing client side default values for fields.
bool isValid() const
Returns if this default value should be applied.
Stores the settings for rendering of all diagrams for a layer.
@ PositionX
X-coordinate data defined diagram position.
@ PositionY
Y-coordinate data defined diagram position.
@ Show
Whether to show the diagram.
void readXml(const QDomElement &elem)
Reads the diagram settings from a DOM element.
void writeXml(QDomElement &layerElem, QDomDocument &doc) const
Writes the diagram settings to a DOM element.
Evaluates and returns the diagram settings relating to a diagram for a specific feature.
virtual void writeXml(QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context) const =0
Writes diagram state to a DOM element.
virtual QList< QgsDiagramSettings > diagramSettings() const =0
Returns list with all diagram settings in the renderer.
virtual void readXml(const QDomElement &elem, const QgsReadWriteContext &context)=0
Reads diagram state from a DOM element.
Contains configuration settings for an editor form.
void readXml(const QDomNode &node, QgsReadWriteContext &context)
Read XML information Deserialize on project load.
void writeXml(QDomNode &node, const QgsReadWriteContext &context) const
Write XML information Serialize on project save.
Holder for the widget type and its configuration for a field.
QVariantMap config() const
Returns the widget configuration.
bool isNull() const
Returns true if there is no widget configured.
void clear()
Clear error messages.
Definition qgserror.h:126
Single scope for storing variables and functions for use within a QgsExpressionContext.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the scope.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the scope.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsExpressionContextScope * popScope()
Removes the last scope from the expression context and return it.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Buffers information about expression fields for a vector layer.
void removeExpression(int index)
Remove an expression from the buffer.
void writeXml(QDomNode &layer_node, QDomDocument &document) const
Saves expressions to xml under the layer node.
void readXml(const QDomNode &layer_node)
Reads expressions from project file.
void updateFields(QgsFields &flds) const
Adds fields with the expressions buffered in this object to a QgsFields object.
void addExpression(const QString &exp, const QgsField &fld)
Add an expression to the buffer.
QList< QgsExpressionFieldBuffer::ExpressionField > expressions() const
void updateExpression(int index, const QString &exp)
Changes the expression at a given index.
void renameExpression(int index, const QString &name)
Renames an expression field at a given index.
An expression node which takes its value from a feature's field.
Handles parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
QString expression() const
Returns the original, unmodified expression string.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QString evalErrorString() const
Returns evaluation error.
QString parserErrorString() const
Returns parser error.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
static int expressionToLayerFieldIndex(const QString &expression, const QgsVectorLayer *layer)
Attempts to resolve an expression to a field index from the given layer.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
QVariant evaluate()
Evaluate the feature and return the result.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
bool close()
Call to end the iteration.
An interface for objects which generate feature renderers for vector layers.
Abstract base class for all 2D vector feature renderers.
static QgsFeatureRenderer * defaultRenderer(Qgis::GeometryType geomType)
Returns a new renderer - used by default in vector layers.
virtual QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context)
Stores renderer properties to an XML element.
double referenceScale() const
Returns the symbology reference scale.
void setReferenceScale(double scale)
Sets the symbology reference scale.
virtual Q_DECL_DEPRECATED void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const
Used from subclasses to create SLD Rule elements following SLD v1.1 specs.
static QgsFeatureRenderer * load(QDomElement &symbologyElem, const QgsReadWriteContext &context)
create a renderer from XML element
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
static QgsFeatureRenderer * loadSld(const QDomNode &node, Qgis::GeometryType geomType, QString &errorMessage)
Create a new renderer according to the information contained in the UserStyle element of a SLD style ...
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets the feature ID that should be fetched.
virtual bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags())
Adds a single feature to the sink.
QFlags< Flag > Flags
virtual QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const
Returns the set of unique values contained within the specified fieldIndex from this source.
virtual Qgis::SpatialIndexPresence hasSpatialIndex() const
Returns an enum value representing the presence of a valid spatial index on the source,...
virtual QgsFeatureIds allFeatureIds() const
Returns a list of all feature IDs for features present in the source.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
Q_INVOKABLE bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
QgsAttributes attributes
Definition qgsfeature.h:67
QgsFields fields
Definition qgsfeature.h:68
QgsFeatureId id
Definition qgsfeature.h:66
QgsGeometry geometry
Definition qgsfeature.h:69
bool hasGeometry() const
Returns true if the feature has an associated geometry.
bool isValid() const
Returns the validity of this feature.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:53
Stores information about constraints which may be present on a field.
ConstraintStrength
Strength of constraints.
void setConstraintStrength(Constraint constraint, ConstraintStrength strength)
Sets the strength of a constraint.
void setConstraintExpression(const QString &expression, const QString &description=QString())
Set the constraint expression for the field.
@ ConstraintOriginProvider
Constraint was set at data provider.
@ ConstraintOriginLayer
Constraint was set by layer.
ConstraintOrigin constraintOrigin(Constraint constraint) const
Returns the origin of a field constraint, or ConstraintOriginNotSet if the constraint is not present ...
QString constraintExpression() const
Returns the constraint expression for the field, if set.
Constraint
Constraints which may be present on a field.
@ ConstraintNotNull
Field may not be null.
@ ConstraintUnique
Field must have a unique value.
@ ConstraintExpression
Field has an expression constraint set. See constraintExpression().
QString constraintDescription() const
Returns the descriptive name for the constraint expression.
void setConstraint(Constraint constraint, ConstraintOrigin origin=ConstraintOriginLayer)
Sets a constraint on the field.
QFlags< Constraint > Constraints
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:53
QString typeName() const
Gets the field type.
Definition qgsfield.cpp:162
QString name
Definition qgsfield.h:62
int precision
Definition qgsfield.h:59
int length
Definition qgsfield.h:58
QString displayNameWithAlias() const
Returns the name to use when displaying this field and adds the alias in parenthesis if it is defined...
Definition qgsfield.cpp:104
QString displayName() const
Returns the name to use when displaying this field.
Definition qgsfield.cpp:96
Qgis::FieldConfigurationFlags configurationFlags
Definition qgsfield.h:66
QString alias
Definition qgsfield.h:63
QgsDefaultValue defaultValueDefinition
Definition qgsfield.h:64
QString comment
Definition qgsfield.h:61
QgsFieldConstraints constraints
Definition qgsfield.h:65
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition qgsfield.cpp:746
Container of fields for a vector layer.
Definition qgsfields.h:46
int count
Definition qgsfields.h:50
bool isEmpty
Definition qgsfields.h:49
Q_INVOKABLE int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
Q_INVOKABLE int indexOf(const QString &fieldName) const
Gets the field index from the field name.
Qgis::FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
int size() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
int fieldOriginIndex(int fieldIdx) const
Returns the field's origin index (its meaning is specific to each type of origin).
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
QStringList names
Definition qgsfields.h:51
Contains options to automatically adjust geometries to constraints on a layer.
A geometry is the spatial representation of a feature.
QgsBox3D boundingBox3D() const
Returns the 3D bounding box of the geometry.
bool equals(const QgsGeometry &geometry) const
Test if this geometry is exactly equal to another geometry.
Qgis::GeometryType type
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
void setMergeLines(bool merge)
Sets whether connected line features with identical label text should be merged prior to generating l...
void setOverlapHandling(Qgis::LabelOverlapHandling handling)
Sets the technique used to handle overlapping labels.
Formats layer metadata into HTML.
A structured metadata store for a map layer.
void combine(const QgsAbstractMetadataBase *other) override
Combines the metadata from this object with the metadata from an other object.
Line string geometry type, with support for z-dimension and m-values.
Alters the size of rendered diagrams using linear scaling.
static void warning(const QString &msg)
Goes to qWarning.
Models dependencies with or between map layers.
Base class for storage of map layer elevation properties.
static QString typeToString(Qgis::LayerType type)
Converts a map layer type to a string value.
virtual void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads configuration from a DOM element previously written by writeXml()
virtual QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Writes configuration to a DOM element, to be used later with readXml()
static QgsMapLayerLegend * defaultVectorLegend(QgsVectorLayer *vl)
Create new legend implementation for vector layer.
Base class for utility classes that encapsulate information necessary for rendering of map layers.
Base class for storage of map layer selection properties.
Stores style information (renderer, opacity, labeling, diagrams etc.) applicable to a map layer.
Base class for storage of map layer temporal properties.
Base class for all map layer types.
Definition qgsmaplayer.h:77
QString name
Definition qgsmaplayer.h:81
void readStyleManager(const QDomNode &layerNode)
Read style manager's configuration (if any). To be called by subclasses.
void dependenciesChanged()
Emitted when dependencies are changed.
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager's configuration (if exists). To be called by subclasses.
QgsMapLayerLegend * legend() const
Can be nullptr.
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
void recalculateExtents() const
This is used to send a request that any mapcanvas using this layer update its extents.
virtual QgsRectangle extent() const
Returns the extent of the layer.
QString source() const
Returns the source for the layer.
Q_INVOKABLE QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
int mBlockStyleChangedSignal
If non-zero, the styleChanged signal should not be emitted.
QString providerType() const
Returns the provider type (provider key) for this layer.
virtual void setExtent3D(const QgsBox3D &box)
Sets the extent.
void removeCustomProperty(const QString &key)
Remove a custom property from layer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
void configChanged()
Emitted whenever the configuration is changed.
void setMinimumScale(double scale)
Sets the minimum map scale (i.e.
static Qgis::DataProviderReadFlags providerReadFlags(const QDomNode &layerNode, QgsMapLayer::ReadFlags layerReadFlags)
Returns provider read flag deduced from layer read flags layerReadFlags and a dom node layerNode that...
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
void editingStarted()
Emitted when editing on this layer has started.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:84
friend class QgsVectorLayer
void writeCustomProperties(QDomNode &layerNode, QDomDocument &doc) const
Write custom properties to project file.
virtual int listStylesInDatabase(QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError)
Lists all the style in db split into related to the layer and not related to.
virtual QString loadDefaultStyle(bool &resultFlag)
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
void setDataSource(const QString &dataSource, const QString &baseName=QString(), const QString &provider=QString(), bool loadDefaultStyleFlag=false)
Updates the data source of the layer.
QString id
Definition qgsmaplayer.h:80
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
QString crsHtmlMetadata() const
Returns a HTML fragment containing the layer's CRS metadata, for use in the htmlMetadata() method.
void setMaximumScale(double scale)
Sets the maximum map scale (i.e.
QgsLayerMetadata metadata
Definition qgsmaplayer.h:83
Qgis::LayerType type
Definition qgsmaplayer.h:87
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
virtual void setOpacity(double opacity)
Sets the opacity for the layer, where opacity is a value between 0 (totally transparent) and 1....
void setFlags(QgsMapLayer::LayerFlags flags)
Returns the flags for this layer.
QString publicSource(bool hidePassword=false) const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
QSet< QgsMapLayerDependency > mDependencies
List of layers that may modify this layer on modification.
void readCustomProperties(const QDomNode &layerNode, const QString &keyStartsWith=QString())
Read custom properties from project file.
virtual void setMetadata(const QgsLayerMetadata &metadata)
Sets the layer's metadata store.
QFlags< StyleCategory > StyleCategories
Q_INVOKABLE void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
QString mProviderKey
Data provider key (name of the data provider)
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
void styleChanged()
Signal emitted whenever a change affects the layer's style.
QUndoStack * undoStack()
Returns pointer to layer's undo stack.
std::unique_ptr< QgsDataProvider > mPreloadedProvider
Optionally used when loading a project, it is released when the layer is effectively created.
void rendererChanged()
Signal emitted when renderer is changed.
virtual QgsError error() const
Gets current status error.
void setScaleBasedVisibility(bool enabled)
Sets whether scale based visibility is enabled for the layer.
void dataSourceChanged()
Emitted whenever the layer's data source has been changed.
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
virtual QString getStyleFromDatabase(const QString &styleId, QString &msgError)
Returns the named style corresponding to style id provided.
void emitStyleChanged()
Triggers an emission of the styleChanged() signal.
void dataChanged()
Data of layer changed.
void willBeDeleted()
Emitted in the destructor when the layer is about to be deleted, but it is still in a perfectly valid...
virtual QgsBox3D extent3D() const
Returns the 3D extent of the layer.
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
void setName(const QString &name)
Set the display name of the layer.
virtual void setExtent(const QgsRectangle &rect)
Sets the extent.
virtual void resolveReferences(QgsProject *project)
Resolve references to other layers (kept as layer IDs after reading XML) into layer objects.
QString mDataSource
Data source description string, varies by layer type.
void setMapTipsEnabled(bool enabled)
Enable or disable map tips for this layer.
@ FlagReadExtentFromXml
Read extent from xml and skip get extent from provider.
@ FlagForceReadOnly
Force open as read only.
@ FlagDontResolveLayers
Don't resolve layer paths or create data providers for layers.
void setValid(bool valid)
Sets whether layer is valid or not.
void readCommonStyle(const QDomElement &layerElement, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)
Read style data common to all layer types.
QgsMapLayer::ReadFlags mReadFlags
Read flags. It's up to the subclass to respect these when restoring state from XML.
double minimumScale() const
Returns the minimum map scale (i.e.
void repaintRequested(bool deferredUpdate=false)
By emitting this signal the layer tells that either appearance or content have been changed and any v...
void setMapTipTemplate(const QString &mapTipTemplate)
The mapTip is a pretty, html representation for feature information.
Q_INVOKABLE QStringList customPropertyKeys() const
Returns list of all keys within custom properties.
QgsProject * project() const
Returns the parent project if this map layer is added to a project.
bool mapTipsEnabled
Definition qgsmaplayer.h:91
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
double opacity
Definition qgsmaplayer.h:89
bool mValid
Indicates if the layer is valid and can be drawn.
@ GeometryOptions
Geometry validation configuration.
@ AttributeTable
Attribute table settings: choice and order of columns, conditional styling.
@ LayerConfiguration
General configuration: identifiable, removable, searchable, display expression, read-only.
@ Symbology
Symbology.
@ MapTips
Map tips.
@ Rendering
Rendering: scale visibility, simplify method, opacity.
@ Relations
Relations.
@ CustomProperties
Custom properties (by plugins for instance)
@ Actions
Actions.
@ Forms
Feature form.
@ Fields
Aliases, widgets, WMS/WFS, expressions, constraints, virtual fields.
@ Legend
Legend settings.
@ Diagrams
Diagrams.
@ Labeling
Labeling.
void layerModified()
Emitted when modifications has been done on layer.
void setProviderType(const QString &providerType)
Sets the providerType (provider key)
QString customPropertyHtmlMetadata() const
Returns an HTML fragment containing custom property information, for use in the htmlMetadata() method...
QString generalHtmlMetadata() const
Returns an HTML fragment containing general metadata information, for use in the htmlMetadata() metho...
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
double maximumScale() const
Returns the maximum map scale (i.e.
QString mapTipTemplate
Definition qgsmaplayer.h:90
bool mShouldValidateCrs
true if the layer's CRS should be validated and invalid CRSes are not permitted.
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
static QgsExpression * expressionFromOgcFilter(const QDomElement &element, QgsVectorLayer *layer=nullptr)
Parse XML with OGC filter into QGIS expression.
static Qgis::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a Qgis::BlendMode corresponding to a QPainter::CompositionMode.
static QPainter::CompositionMode getCompositionMode(Qgis::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a Qgis::BlendMode.
Contains settings for how a map layer will be labeled.
double yOffset
Vertical offset of label.
const QgsLabelPlacementSettings & placementSettings() const
Returns the label placement settings.
double maxCurvedCharAngleIn
Maximum angle between inside curved label characters (valid range 20.0 to 60.0).
void setFormat(const QgsTextFormat &format)
Sets the label text formatting settings, e.g., font settings, buffer settings, etc.
double xOffset
Horizontal offset of label.
Qgis::LabelPlacement placement
Label placement mode.
double angleOffset
Label rotation, in degrees clockwise.
double maxCurvedCharAngleOut
Maximum angle between outside curved label characters (valid range -20.0 to -95.0)
Qgis::RenderUnit offsetUnits
Units for offsets of label.
bool isExpression
true if this label is made from a expression string, e.g., FieldName || 'mm'
const QgsLabelLineSettings & lineSettings() const
Returns the label line settings, which contain settings related to how the label engine places and fo...
Qgis::UpsideDownLabelHandling upsidedownLabels
Controls whether upside down labels are displayed and how they are handled.
QString fieldName
Name of field (or an expression) to use for label text.
Represents a 2D point.
Definition qgspointxy.h:60
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
Encapsulates properties and constraints relating to fetching elevation profiles from different source...
virtual QString translate(const QString &context, const QString &sourceText, const char *disambiguation=nullptr, int n=-1) const =0
Translates a string using the Qt QTranslator mechanism.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:107
QgsRelationManager * relationManager
Definition qgsproject.h:117
bool commitChanges(QStringList &commitErrors, bool stopEditing=true, QgsVectorLayer *vectorLayer=nullptr)
Attempts to commit to the underlying data provider any buffered changes made since the last to call t...
static QgsProject * instance()
Returns the QgsProject singleton instance.
bool rollBack(QStringList &rollbackErrors, bool stopEditing=true, QgsVectorLayer *vectorLayer=nullptr)
Stops a current editing operation on vectorLayer and discards any uncommitted edits.
bool startEditing(QgsVectorLayer *vectorLayer=nullptr)
Makes the layer editable.
QMap< QString, QgsMapLayer * > mapLayers(const bool validOnly=false) const
Returns a map of all registered layers by layer ID.
A grouped map of multiple QgsProperty objects, each referenced by an integer key value.
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
Definition for a property.
Definition qgsproperty.h:45
@ Double
Double value (including negative values)
Definition qgsproperty.h:55
@ Boolean
Boolean value.
Definition qgsproperty.h:51
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
QString absoluteToRelativeUri(const QString &providerKey, const QString &uri, const QgsReadWriteContext &context) const
Converts absolute path(s) to relative path(s) in the given provider-specific URI.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QString relativeToAbsoluteUri(const QString &providerKey, const QString &uri, const QgsReadWriteContext &context) const
Converts relative path(s) to absolute path(s) in the given provider-specific URI.
Allows entering a context category and takes care of leaving this category on deletion of the class.
A container for the context for various read/write operations on objects.
MAYBE_UNUSED NODISCARD QgsReadWriteContextCategoryPopper enterCategory(const QString &category, const QString &details=QString()) const
Push a category to the stack.
const QgsProjectTranslator * projectTranslator() const
Returns the project translator.
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
A rectangle specified with double values.
Q_INVOKABLE QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
double xMinimum
double yMinimum
double xMaximum
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
double yMaximum
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
void normalize()
Normalize the rectangle so it has non-negative width/height.
void setNull()
Mark a rectangle as being null (holding no spatial information).
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
void relationsLoaded()
Emitted when the relations were loaded after reading a project.
Represents a relationship between two vector layers.
Definition qgsrelation.h:44
Contains information about the context of a rendering operation.
double rendererScale() const
Returns the renderer map scale.
bool useRenderingOptimization() const
Returns true if the rendering optimization (geometry simplification) can be executed.
A child rule for QgsRuleBasedLabeling.
void appendChild(QgsRuleBasedLabeling::Rule *rule)
add child rule, take ownership, sets this as parent
Rule based labeling for a vector layer.
A boolean settings entry.
A double settings entry.
A template class for enum and flag settings entry.
static QgsSettingsTreeNode * sTreeQgis
Stores settings for use within QGIS.
Definition qgssettings.h:65
Renders the diagrams for all features with the same settings.
Holds SLD export options and other information related to SLD export of a QGIS layer style.
void setExtraProperties(const QVariantMap &properties)
Sets the open ended set of properties that can drive/inform the SLD encoding.
QVariantMap extraProperties() const
Returns the open ended set of properties that can drive/inform the SLD encoding.
Renders diagrams using mixed diagram render types.
Manages stored expressions regarding creation, modification and storing in the project.
bool writeXml(QDomNode &layerNode) const
Writes the stored expressions out in XML format.
bool readXml(const QDomNode &layerNode)
Reads the stored expressions in in XML format.
An interface for classes which can visit style entity (e.g.
static double rendererFrameRate(const QgsFeatureRenderer *renderer)
Calculates the frame rate (in frames per second) at which the given renderer must be redrawn.
static QgsStringMap getSvgParameterList(QDomElement &element)
static void mergeScaleDependencies(double mScaleMinDenom, double mScaleMaxDenom, QVariantMap &props)
Merges the local scale limits, if any, with the ones already in the map, if any.
static bool fillFromSld(QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color)
static Qgis::RenderUnit decodeSldUom(const QString &str, double *scaleFactor=nullptr)
Decodes a SLD unit of measure string to a render unit.
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
void taskCompleted()
Will be emitted by task to indicate its successful completion.
void taskTerminated()
Will be emitted by task if it has terminated for any reason other then completion (e....
bool isActive() const
Returns true if the temporal property is active.
Container for settings relating to a text buffer.
void setColor(const QColor &color)
Sets the color for the buffer.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units used for the buffer size.
void setEnabled(bool enabled)
Sets whether the text buffer will be drawn.
void setSize(double size)
Sets the size of the buffer.
Container for all settings relating to text rendering.
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setSize(double size)
Sets the size for rendered text.
void setFont(const QFont &font)
Sets the font used for rendering text.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the size of rendered text.
void setBuffer(const QgsTextBufferSettings &bufferSettings)
Sets the text's buffer settings.
Allows creation of a multi-layer database-side transaction.
QString createSavepoint(QString &error)
creates a save point returns empty string on error returns the last created savepoint if it's not dir...
void dirtied(const QString &sql, const QString &name)
Emitted if a sql query is executed and the underlying data is modified.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Base class for vector data providers.
virtual QString dataComment() const override
Returns a short comment for the data that this provider is providing access to (e....
virtual QVariant aggregate(Qgis::Aggregate aggregate, int index, const QgsAggregateCalculator::AggregateParameters &parameters, QgsExpressionContext *context, bool &ok, QgsFeatureIds *fids=nullptr) const
Calculates an aggregated value from the layer's features.
static const int EditingCapabilities
Bitmask of all provider's editing capabilities.
long long featureCount() const override=0
Number of features in the layer.
virtual QgsFeatureRenderer * createRenderer(const QVariantMap &configuration=QVariantMap()) const
Creates a new vector layer feature renderer, using provider backend specific information.
virtual QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
virtual QStringList uniqueStringsMatching(int index, const QString &substring, int limit=-1, QgsFeedback *feedback=nullptr) const
Returns unique string values of an attribute which contain a specified subset string.
void raiseError(const QString &msg) const
Signals an error in this provider.
virtual bool isSqlQuery() const
Returns true if the layer is a query (SQL) layer.
virtual bool empty() const
Returns true if the layer does not contain any feature.
virtual Q_INVOKABLE Qgis::VectorProviderCapabilities capabilities() const
Returns flags containing the supported capabilities.
virtual QgsAttributeList pkAttributeIndexes() const
Returns list of indexes of fields that make up the primary key.
virtual void handlePostCloneOperations(QgsVectorDataProvider *source)
Handles any post-clone operations required after this vector data provider was cloned from the source...
virtual QSet< QgsMapLayerDependency > dependencies() const
Gets the list of layer ids on which this layer depends.
virtual void setEncoding(const QString &e)
Set encoding used for accessing data from layer.
virtual Qgis::VectorLayerTypeFlags vectorLayerTypeFlags() const
Returns the vector layer type flags.
QVariant maximumValue(int index) const override
Returns the maximum value of an attribute.
QgsDataProviderElevationProperties * elevationProperties() override
Returns the provider's elevation properties.
QgsFields fields() const override=0
Returns the fields associated with this data provider.
Qgis::WkbType wkbType() const override=0
Returns the geometry type which is returned by this layer.
QVariant minimumValue(int index) const override
Returns the minimum value of an attribute.
QString encoding() const
Returns the encoding which is used for accessing data.
virtual QVariant defaultValue(int fieldIndex) const
Returns any literal default values which are present at the provider for a specified field index.
QgsFieldConstraints::Constraints fieldConstraints(int fieldIndex) const
Returns any constraints which are present at the provider for a specified field index.
virtual QgsTransaction * transaction() const
Returns the transaction this data provider is included in, if any.
virtual QgsAbstractVectorLayerLabeling * createLabeling(const QVariantMap &configuration=QVariantMap()) const
Creates labeling settings, using provider backend specific information.
QgsVectorDataProviderTemporalCapabilities * temporalCapabilities() override
Returns the provider's temporal capabilities.
QString capabilitiesString() const
Returns the above in friendly format.
bool commitChanges(QStringList &commitErrors, bool stopEditing=true)
Attempts to commit any changes to disk.
void committedAttributesDeleted(const QString &layerId, const QgsAttributeList &deletedAttributes)
Emitted after attribute deletion has been committed to the layer.
virtual bool deleteFeature(QgsFeatureId fid)
Delete a feature from the layer (but does not commit it)
QgsFeatureIds deletedFeatureIds() const
Returns a list of deleted feature IDs which are not committed.
QgsChangedAttributesMap changedAttributeValues() const
Returns a map of features with changed attributes values which are not committed.
void committedAttributeValuesChanges(const QString &layerId, const QgsChangedAttributesMap &changedAttributesValues)
Emitted after feature attribute value changes have been committed to the layer.
virtual bool renameAttribute(int attr, const QString &newName)
Renames an attribute field (but does not commit it)
void geometryChanged(QgsFeatureId fid, const QgsGeometry &geom)
Emitted when a feature's geometry is changed.
virtual bool deleteFeatures(const QgsFeatureIds &fid)
Deletes a set of features from the layer (but does not commit it)
virtual bool addAttribute(const QgsField &field)
Adds an attribute field (but does not commit it) returns true if the field was added.
void committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)
Emitted after attribute addition has been committed to the layer.
virtual bool addFeatures(QgsFeatureList &features)
Insert a copy of the given features into the layer (but does not commit it)
virtual bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues)
Changes values of attributes (but does not commit it).
QgsFeatureMap addedFeatures() const
Returns a map of new features which are not committed.
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
void updateFields(QgsFields &fields)
Updates fields.
void committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)
Emitted after feature addition has been committed to the layer.
void featureDeleted(QgsFeatureId fid)
Emitted when a feature was deleted from the buffer.
QgsGeometryMap changedGeometries() const
Returns a map of features with changed geometries which are not committed.
QgsVectorLayerEditBufferGroup * editBufferGroup() const
Returns the parent edit buffer group for this edit buffer, or nullptr if not part of a group.
QgsAttributeList deletedAttributeIds() const
Returns a list of deleted attributes fields which are not committed.
void attributeAdded(int idx)
Emitted when an attribute was added to the buffer.
void committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)
Emitted after feature geometry changes have been committed to the layer.
virtual bool addFeature(QgsFeature &f)
Adds a feature.
virtual void rollBack()
Stop editing and discard the edits.
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &value)
Emitted when a feature's attribute value has been changed.
void attributeDeleted(int idx)
Emitted when an attribute was deleted from the buffer.
void featureAdded(QgsFeatureId fid)
Emitted when a feature has been added to the buffer.
virtual bool commitChanges(QStringList &commitErrors)
Attempts to commit any changes to disk.
virtual bool deleteAttribute(int attr)
Deletes an attribute field (but does not commit it)
virtual bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant())
Changed an attribute value (but does not commit it)
virtual bool changeGeometry(QgsFeatureId fid, const QgsGeometry &geom)
Change feature's geometry.
void layerModified()
Emitted when modifications has been done on layer.
void committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)
Emitted after feature removal has been committed to the layer.
Contains utility functions for editing vector layers.
int translateFeature(QgsFeatureId featureId, double dx, double dy)
Translates feature by dx, dy.
bool insertVertex(double x, double y, QgsFeatureId atFeatureId, int beforeVertex)
Insert a new vertex before the given vertex number, in the given ring, item (first number is index 0)...
Q_DECL_DEPRECATED Qgis::GeometryOperationResult addPart(const QVector< QgsPointXY > &ring, QgsFeatureId featureId)
Adds a new part polygon to a multipart feature.
Qgis::VectorEditResult deleteVertex(QgsFeatureId featureId, int vertex)
Deletes a vertex from a feature.
int addTopologicalPoints(const QgsGeometry &geom)
Adds topological points for every vertex of the geometry.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult splitParts(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits parts cut by the given line.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult splitFeatures(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits features cut by the given line.
bool moveVertex(double x, double y, QgsFeatureId atFeatureId, int atVertex)
Moves the vertex at the given position number, ring and item (first number is index 0),...
Q_DECL_DEPRECATED Qgis::GeometryOperationResult addRing(const QVector< QgsPointXY > &ring, const QgsFeatureIds &targetFeatureIds=QgsFeatureIds(), QgsFeatureId *modifiedFeatureId=nullptr)
Adds a ring to polygon/multipolygon features.
Vector layer specific subclass of QgsMapLayerElevationProperties.
void setDefaultsFromLayer(QgsMapLayer *layer) override
Sets default properties based on sensible choices for the given map layer.
QgsVectorLayerElevationProperties * clone() const override
Creates a clone of the properties.
Counts the features in a QgsVectorLayer in task.
QHash< QString, long long > symbolFeatureCountMap() const
Returns the count for each symbol.
void cancel() override
Notifies the task that it should terminate.
QHash< QString, QgsFeatureIds > symbolFeatureIdMap() const
Returns the QgsFeatureIds for each symbol.
A feature iterator which iterates over features from a QgsVectorLayer.
Manages joined fields for a vector layer.
void resolveReferences(QgsProject *project)
Resolves layer IDs of joined layers using given project's available layers.
bool addJoin(const QgsVectorLayerJoinInfo &joinInfo)
Joins another vector layer to this layer.
void readXml(const QDomNode &layer_node)
Reads joins from project file.
void writeXml(QDomNode &layer_node, QDomDocument &document) const
Saves mVectorJoins to xml under the layer node.
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant())
Changes attribute value in joined layers.
bool removeJoin(const QString &joinLayerId)
Removes a vector layer join.
bool containsJoins() const
Quick way to test if there is any join at all.
bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues=QgsAttributeMap())
Changes attributes' values in joined layers.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a list of features in joined layers.
void joinedFieldsChanged()
Emitted whenever the list of joined fields changes (e.g.
void updateFields(QgsFields &fields)
Updates field map with joined attributes.
bool deleteFeature(QgsFeatureId fid, QgsVectorLayer::DeleteContext *context=nullptr) const
Deletes a feature from joined layers.
const QgsVectorJoinList & vectorJoins() const
Defines left outer join from our vector layer to some other vector layer.
QString targetFieldName() const
Returns name of the field of our layer that will be used for join.
QString joinLayerId() const
ID of the joined layer - may be used to resolve reference to the joined layer.
Implementation of QgsAbstractProfileGenerator for vector layers.
Implementation of threaded rendering for vector layers.
Implementation of layer selection properties for vector layers.
QgsVectorLayerSelectionProperties * clone() const override
Creates a clone of the properties.
QDomElement writeXml(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context) override
Writes the properties to a DOM element, to be used later with readXml().
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads temporal properties from a DOM element previously written by writeXml().
Basic implementation of the labeling interface.
Implementation of map layer temporal properties for vector layers.
void guessDefaultsFromFields(const QgsFields &fields)
Attempts to setup the temporal properties by scanning a set of fields and looking for standard naming...
void setDefaultsFromDataProviderTemporalCapabilities(const QgsDataProviderTemporalCapabilities *capabilities) override
Sets the layers temporal settings to appropriate defaults based on a provider's temporal capabilities...
Contains settings which reflect the context in which vector layer tool operations should be considere...
QgsExpressionContext * expressionContext() const
Returns the optional expression context used by the vector layer tools.
static QString guessFriendlyIdentifierField(const QgsFields &fields, bool *foundFriendly=nullptr)
Given a set of fields, attempts to pick the "most useful" field for user-friendly identification of f...
Represents a vector layer which manages a vector based dataset.
void setLabeling(QgsAbstractVectorLayerLabeling *labeling)
Sets labeling configuration.
QString attributeDisplayName(int index) const
Convenience function that returns the attribute alias if defined or the field name else.
QVariant maximumValue(int index) const FINAL
Returns the maximum value for an attribute column or an invalid variant in case of error.
int addExpressionField(const QString &exp, const QgsField &fld)
Add a new field which is calculated by the expression specified.
void committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)
Emitted when features are added to the provider if not in transaction mode.
void setExtent(const QgsRectangle &rect) FINAL
Sets the extent.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult addPart(const QList< QgsPointXY > &ring)
Adds a new part polygon to a multipart feature.
static const QgsSettingsEntryEnumFlag< Qgis::VectorRenderingSimplificationFlags > * settingsSimplifyDrawingHints
QgsRectangle sourceExtent() const FINAL
Returns the extent of all geometries from the source.
void featureBlendModeChanged(QPainter::CompositionMode blendMode)
Signal emitted when setFeatureBlendMode() is called.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const FINAL
Write the style for the layer into the document provided.
bool isModified() const override
Returns true if the provider has been modified since the last commit.
bool writeStyle(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const FINAL
Write just the symbology information for the layer into the document.
void addFeatureRendererGenerator(QgsFeatureRendererGenerator *generator)
Adds a new feature renderer generator to the layer.
Q_DECL_DEPRECATED void setExcludeAttributesWfs(const QSet< QString > &att)
A set of attributes that are not advertised in WFS requests with QGIS server.
Q_INVOKABLE bool deleteSelectedFeatures(int *deletedCount=nullptr, QgsVectorLayer::DeleteContext *context=nullptr)
Deletes the selected features.
Q_INVOKABLE void selectByRect(QgsRectangle &rect, Qgis::SelectBehavior behavior=Qgis::SelectBehavior::SetSelection)
Selects features found within the search rectangle (in layer's coordinates)
void removeFieldAlias(int index)
Removes an alias (a display name) for attributes to display in dialogs.
void setAuxiliaryLayer(QgsAuxiliaryLayer *layer=nullptr)
Sets the current auxiliary layer.
void beforeRemovingExpressionField(int idx)
Will be emitted, when an expression field is going to be deleted from this vector layer.
Q_INVOKABLE bool deleteFeatures(const QgsFeatureIds &fids, QgsVectorLayer::DeleteContext *context=nullptr)
Deletes a set of features from the layer (but does not commit it)
QString loadDefaultStyle(bool &resultFlag) FINAL
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
void committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)
Emitted when geometry changes are saved to the provider if not in transaction mode.
void beforeCommitChanges(bool stopEditing)
Emitted before changes are committed to the data provider.
Q_INVOKABLE bool startEditing()
Makes the layer editable.
void setFieldConfigurationFlags(int index, Qgis::FieldConfigurationFlags flags)
Sets the configuration flags of the field at given index.
QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength > fieldConstraintsAndStrength(int fieldIndex) const
Returns a map of constraint with their strength for a specific field of the layer.
bool addJoin(const QgsVectorLayerJoinInfo &joinInfo)
Joins another vector layer to this layer.
QSet< QgsMapLayerDependency > dependencies() const FINAL
Gets the list of dependencies.
QgsMapLayerTemporalProperties * temporalProperties() override
Returns the layer's temporal properties.
Q_INVOKABLE bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false, QgsVectorLayerToolsContext *context=nullptr)
Changes an attribute value for a feature (but does not immediately commit the changes).
Q_DECL_DEPRECATED Qgis::GeometryOperationResult splitFeatures(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits features cut by the given line.
QgsDefaultValue defaultValueDefinition(int index) const
Returns the definition of the expression used when calculating the default value for a field.
QgsExpressionContextScope * createExpressionContextScope() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext) FINAL
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context.
QgsVectorLayerFeatureCounter * countSymbolFeatures(bool storeSymbolFids=false)
Count features for symbols.
QPainter::CompositionMode featureBlendMode() const
Returns the current blending mode for features.
bool hasMapTips() const FINAL
Returns true if the layer contains map tips.
QString constraintExpression(int index) const
Returns the constraint expression for for a specified field index, if set.
bool addAttribute(const QgsField &field)
Add an attribute field (but does not commit it) returns true if the field was added.
void attributeAdded(int idx)
Will be emitted, when a new attribute has been added to this vector layer.
QString capabilitiesString() const
Capabilities for this layer, comma separated and translated.
void deselect(QgsFeatureId featureId)
Deselects feature by its ID.
void allowCommitChanged()
Emitted whenever the allowCommit() property of this layer changes.
friend class QgsVectorLayerEditBuffer
void editCommandStarted(const QString &text)
Signal emitted when a new edit command has been started.
void updateFields()
Will regenerate the fields property of this layer by obtaining all fields from the dataProvider,...
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
const QgsDiagramLayerSettings * diagramLayerSettings() const
void setFieldConstraint(int index, QgsFieldConstraints::Constraint constraint, QgsFieldConstraints::ConstraintStrength strength=QgsFieldConstraints::ConstraintStrengthHard)
Sets a constraint for a specified field index.
bool loadAuxiliaryLayer(const QgsAuxiliaryStorage &storage, const QString &key=QString())
Loads the auxiliary layer for this vector layer.
bool insertVertex(double x, double y, QgsFeatureId atFeatureId, int beforeVertex)
Inserts a new vertex before the given vertex number, in the given ring, item (first number is index 0...
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsAbstractProfileGenerator * createProfileGenerator(const QgsProfileRequest &request) override
Given a profile request, returns a new profile generator ready for generating elevation profiles.
QString htmlMetadata() const FINAL
Obtain a formatted HTML string containing assorted metadata for this layer.
Q_INVOKABLE QgsRectangle boundingBoxOfSelected() const
Returns the bounding box of the selected features. If there is no selection, QgsRectangle(0,...
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a list of features to the sink.
Q_INVOKABLE QgsFeatureList selectedFeatures() const
Returns a copy of the user-selected features.
QString expressionField(int index) const
Returns the expression used for a given expression field.
bool readSymbology(const QDomNode &layerNode, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) FINAL
Read the symbology for the current layer from the DOM node supplied.
void removeFeatureRendererGenerator(const QString &id)
Removes the feature renderer with matching id from the layer.
Q_INVOKABLE bool deleteFeature(QgsFeatureId fid, QgsVectorLayer::DeleteContext *context=nullptr)
Deletes a feature from the layer (but does not commit it).
friend class QgsVectorLayerEditPassthrough
void setSimplifyMethod(const QgsVectorSimplifyMethod &simplifyMethod)
Sets the simplification settings for fast rendering of features.
void editCommandDestroyed()
Signal emitted, when an edit command is destroyed.
QVariant aggregate(Qgis::Aggregate aggregate, const QString &fieldOrExpression, const QgsAggregateCalculator::AggregateParameters &parameters=QgsAggregateCalculator::AggregateParameters(), QgsExpressionContext *context=nullptr, bool *ok=nullptr, QgsFeatureIds *fids=nullptr, QgsFeedback *feedback=nullptr, QString *error=nullptr) const
Calculates an aggregated value from the layer's features.
QgsFieldConstraints::Constraints fieldConstraints(int fieldIndex) const
Returns any constraints which are present for a specified field index.
static const QgsSettingsEntryEnumFlag< Qgis::VectorSimplificationAlgorithm > * settingsSimplifyAlgorithm
Q_DECL_DEPRECATED QSet< QString > excludeAttributesWms() const
A set of attributes that are not advertised in WMS requests with QGIS server.
QgsBox3D sourceExtent3D() const FINAL
Returns the 3D extent of all geometries from the source.
QgsFeatureIds symbolFeatureIds(const QString &legendKey) const
Ids of features rendered with specified legend key.
void removeFieldConstraint(int index, QgsFieldConstraints::Constraint constraint)
Removes a constraint for a specified field index.
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
void featuresDeleted(const QgsFeatureIds &fids)
Emitted when features have been deleted.
Qgis::VectorLayerTypeFlags vectorLayerTypeFlags() const
Returns the vector layer type flags.
void setLabelsEnabled(bool enabled)
Sets whether labels should be enabled for the layer.
void subsetStringChanged()
Emitted when the layer's subset string has changed.
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer.
void setCoordinateSystem()
Setup the coordinate system transformation for the layer.
void committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)
Emitted when features are deleted from the provider if not in transaction mode.
void setFieldMergePolicy(int index, Qgis::FieldDomainMergePolicy policy)
Sets a merge policy for the field with the specified index.
void updateExpressionField(int index, const QString &exp)
Changes the expression used to define an expression based (virtual) field.
Q_INVOKABLE void selectByExpression(const QString &expression, Qgis::SelectBehavior behavior=Qgis::SelectBehavior::SetSelection, QgsExpressionContext *context=nullptr)
Selects matching features using an expression.
static const QgsSettingsEntryDouble * settingsSimplifyMaxScale
~QgsVectorLayer() override
QgsCoordinateReferenceSystem sourceCrs() const FINAL
Returns the coordinate reference system for features in the source.
void endEditCommand()
Finish edit command and add it to undo/redo stack.
void destroyEditCommand()
Destroy active command and reverts all changes in it.
bool isAuxiliaryField(int index, int &srcIndex) const
Returns true if the field comes from the auxiliary layer, false otherwise.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QList< QgsRelation > referencingRelations(int idx) const
Returns the layer's relations, where the foreign key is on this layer.
Q_DECL_DEPRECATED QSet< QString > excludeAttributesWfs() const
A set of attributes that are not advertised in WFS requests with QGIS server.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult splitParts(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits parts cut by the given line.
void setDefaultValueDefinition(int index, const QgsDefaultValue &definition)
Sets the definition of the expression to use when calculating the default value for a field.
bool diagramsEnabled() const
Returns whether the layer contains diagrams which are enabled and should be drawn.
void setAllowCommit(bool allowCommit)
Controls, if the layer is allowed to commit changes.
bool setDependencies(const QSet< QgsMapLayerDependency > &layers) FINAL
Sets the list of dependencies.
void symbolFeatureCountMapChanged()
Emitted when the feature count for symbols on this layer has been recalculated.
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
Qgis::VectorEditResult deleteVertex(QgsFeatureId featureId, int vertex)
Deletes a vertex from a feature.
void setFeatureBlendMode(QPainter::CompositionMode blendMode)
Sets the blending mode used for rendering each feature.
QString constraintDescription(int index) const
Returns the descriptive name for the constraint expression for a specified field index.
void writeCustomSymbology(QDomElement &element, QDomDocument &doc, QString &errorMessage) const
Signal emitted whenever the symbology (QML-file) for this layer is being written.
const QgsAbstractVectorLayerLabeling * labeling() const
Access to const labeling configuration.
void setProviderEncoding(const QString &encoding)
Sets the text encoding of the data provider.
Q_DECL_DEPRECATED bool writeSld(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QVariantMap &props=QVariantMap()) const
Writes the symbology of the layer into the document provided in SLD 1.1 format.
void setDisplayExpression(const QString &displayExpression)
Set the preview expression, used to create a human readable preview string.
virtual bool deleteAttribute(int attr)
Deletes an attribute field (but does not commit it).
static const QgsSettingsEntryBool * settingsSimplifyLocal
void resolveReferences(QgsProject *project) FINAL
Resolves references to other layers (kept as layer IDs after reading XML) into layer objects.
bool simplifyDrawingCanbeApplied(const QgsRenderContext &renderContext, Qgis::VectorRenderingSimplificationFlag simplifyHint) const
Returns whether the VectorLayer can apply the specified simplification hint.
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
bool removeJoin(const QString &joinLayerId)
Removes a vector layer join.
Q_INVOKABLE void invertSelectionInRectangle(QgsRectangle &rect)
Inverts selection of features found within the search rectangle (in layer's coordinates)
void setRenderer(QgsFeatureRenderer *r)
Sets the feature renderer which will be invoked to represent this layer in 2D map views.
Q_INVOKABLE void selectAll()
Select all the features.
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
QStringList commitErrors() const
Returns a list containing any error messages generated when attempting to commit changes to the layer...
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
bool readExtentFromXml() const
Returns true if the extent is read from the XML document when data source has no metadata,...
QString dataComment() const
Returns a description for this layer as defined in the data provider.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
QgsGeometryOptions * geometryOptions() const
Configuration and logic to apply automatically on any edit happening on this layer.
QgsStringMap attributeAliases() const
Returns a map of field name to attribute alias.
Q_INVOKABLE int translateFeature(QgsFeatureId featureId, double dx, double dy)
Translates feature by dx, dy.
Q_INVOKABLE Qgis::WkbType wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
virtual void updateExtents(bool force=false)
Update the extents for the layer.
void attributeDeleted(int idx)
Will be emitted, when an attribute has been deleted from this vector layer.
QgsFeatureRenderer * renderer()
Returns the feature renderer used for rendering the features in the layer in 2D map views.
void beforeEditingStarted()
Emitted before editing on this layer is started.
void committedAttributeValuesChanges(const QString &layerId, const QgsChangedAttributesMap &changedAttributesValues)
Emitted when attribute value changes are saved to the provider if not in transaction mode.
void committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)
Emitted when attributes are added to the provider if not in transaction mode.
void setEditFormConfig(const QgsEditFormConfig &editFormConfig)
Sets the editFormConfig (configuration) of the form used to represent this vector layer.
Qgis::FieldConfigurationFlags fieldConfigurationFlags(int index) const
Returns the configuration flags of the field at given index.
void committedAttributesDeleted(const QString &layerId, const QgsAttributeList &deletedAttributes)
Emitted when attributes are deleted from the provider if not in transaction mode.
QString displayExpression
void displayExpressionChanged()
Emitted when the display expression changes.
QVariant minimumValue(int index) const FINAL
Returns the minimum value for an attribute column or an invalid variant in case of error.
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
void setEditorWidgetSetup(int index, const QgsEditorWidgetSetup &setup)
Sets the editor widget setup for the field at the specified index.
void setConstraintExpression(int index, const QString &expression, const QString &description=QString())
Sets the constraint expression for the specified field index.
Q_INVOKABLE bool rollBack(bool deleteBuffer=true)
Stops a current editing operation and discards any uncommitted edits.
bool readStyle(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) FINAL
Read the style for the current layer from the DOM node supplied.
bool updateFeature(QgsFeature &feature, bool skipDefaultValues=false)
Updates an existing feature in the layer, replacing the attributes and geometry for the feature with ...
Q_INVOKABLE bool commitChanges(bool stopEditing=true)
Attempts to commit to the underlying data provider any buffered changes made since the last to call t...
void setFieldConfigurationFlag(int index, Qgis::FieldConfigurationFlag flag, bool active)
Sets the given configuration flag for the field at given index to be active or not.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
void setFieldDuplicatePolicy(int index, Qgis::FieldDuplicatePolicy policy)
Sets a duplicate policy for the field with the specified index.
bool setReadOnly(bool readonly=true)
Makes layer read-only (editing disabled) or not.
void editFormConfigChanged()
Will be emitted whenever the edit form configuration of this layer changes.
Q_INVOKABLE void modifySelection(const QgsFeatureIds &selectIds, const QgsFeatureIds &deselectIds)
Modifies the current selection on this layer.
void setWeakRelations(const QList< QgsWeakRelation > &relations)
Sets the layer's weak relations.
void reselect()
Reselects the previous set of selected features.
void select(QgsFeatureId featureId)
Selects feature by its ID.
QgsEditorWidgetSetup editorWidgetSetup(int index) const
Returns the editor widget setup for the field at the specified index.
long long featureCount() const FINAL
Returns feature count including changes which have not yet been committed If you need only the count ...
void setReadExtentFromXml(bool readExtentFromXml)
Flag allowing to indicate if the extent has to be read from the XML document when data source has no ...
void afterCommitChanges()
Emitted after changes are committed to the data provider.
QgsVectorLayer * clone() const override
Returns a new instance equivalent to this one.
QgsAttributeTableConfig attributeTableConfig() const
Returns the attribute table configuration object.
QgsActionManager * actions()
Returns all layer actions defined on this layer.
bool readSld(const QDomNode &node, QString &errorMessage) FINAL
Q_INVOKABLE void selectByIds(const QgsFeatureIds &ids, Qgis::SelectBehavior behavior=Qgis::SelectBehavior::SetSelection)
Selects matching features using a list of feature IDs.
QStringList uniqueStringsMatching(int index, const QString &substring, int limit=-1, QgsFeedback *feedback=nullptr) const
Returns unique string values of an attribute which contain a specified subset string.
void raiseError(const QString &msg)
Signals an error related to this vector layer.
void editCommandEnded()
Signal emitted, when an edit command successfully ended.
void supportsEditingChanged()
Emitted when the read only state or the data provider of this layer is changed.
void readOnlyChanged()
Emitted when the read only state of this layer is changed.
void removeExpressionField(int index)
Removes an expression field.
virtual void setTransformContext(const QgsCoordinateTransformContext &transformContext) override
Sets the coordinate transform context to transformContext.
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &value)
Emitted whenever an attribute value change is done in the edit buffer.
static Q_DECL_DEPRECATED void drawVertexMarker(double x, double y, QPainter &p, Qgis::VertexMarkerType type, int vertexSize)
Draws a vertex symbol at (screen) coordinates x, y.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a single feature to the sink.
void setFieldAlias(int index, const QString &aliasString)
Sets an alias (a display name) for attributes to display in dialogs.
friend class QgsVectorLayerFeatureSource
void minimumAndMaximumValue(int index, QVariant &minimum, QVariant &maximum) const
Calculates both the minimum and maximum value for an attribute column.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
QgsRectangle extent() const FINAL
Returns the extent of the layer.
Q_DECL_DEPRECATED void setExcludeAttributesWms(const QSet< QString > &att)
A set of attributes that are not advertised in WMS requests with QGIS server.
void setAttributeTableConfig(const QgsAttributeTableConfig &attributeTableConfig)
Sets the attribute table configuration object.
virtual bool setSubsetString(const QString &subset)
Sets the string (typically sql) used to define a subset of the layer.
bool readXml(const QDomNode &layer_node, QgsReadWriteContext &context) FINAL
Reads vector layer specific state from project file Dom node.
void afterRollBack()
Emitted after changes are rolled back.
QString decodedSource(const QString &source, const QString &provider, const QgsReadWriteContext &context) const FINAL
Called by readLayerXML(), used by derived classes to decode provider's specific data source from proj...
void setDiagramLayerSettings(const QgsDiagramLayerSettings &s)
QList< QgsWeakRelation > weakRelations() const
Returns the layer's weak relations as specified in the layer's style.
const QgsVectorSimplifyMethod & simplifyMethod() const
Returns the simplification settings for fast rendering of features.
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
void beforeAddingExpressionField(const QString &fieldName)
Will be emitted, when an expression field is going to be added to this vector layer.
bool deleteAttributes(const QList< int > &attrs)
Deletes a list of attribute fields (but does not commit it)
void updatedFields()
Emitted whenever the fields available from this layer have been changed.
QVariant defaultValue(int index, const QgsFeature &feature=QgsFeature(), QgsExpressionContext *context=nullptr) const
Returns the calculated default value for the specified field index.
void featureAdded(QgsFeatureId fid)
Emitted when a new feature has been added to the layer.
QString sourceName() const FINAL
Returns a friendly display name for the source.
QString attributeAlias(int index) const
Returns the alias of an attribute name or a null string if there is no alias.
void featureDeleted(QgsFeatureId fid)
Emitted when a feature has been deleted.
QgsBox3D extent3D() const FINAL
Returns the 3D extent of the layer.
Q_INVOKABLE void removeSelection()
Clear selection.
bool allowCommit() const
Controls, if the layer is allowed to commit changes.
QgsConditionalLayerStyles * conditionalStyles() const
Returns the conditional styles that are set for this layer.
void readCustomSymbology(const QDomElement &element, QString &errorMessage)
Signal emitted whenever the symbology (QML-file) for this layer is being read.
void reload() FINAL
Synchronises with changes in the datasource.
const QList< QgsVectorLayerJoinInfo > vectorJoins() const
bool renameAttribute(int index, const QString &newName)
Renames an attribute field (but does not commit it).
bool isSqlQuery() const
Returns true if the layer is a query (SQL) layer.
void beforeRollBack()
Emitted before changes are rolled back.
QgsAttributeList primaryKeyAttributes() const
Returns the list of attributes which make up the layer's primary keys.
bool writeXml(QDomNode &layer_node, QDomDocument &doc, const QgsReadWriteContext &context) const FINAL
Writes vector layer specific state to project file Dom node.
QString encodedSource(const QString &source, const QgsReadWriteContext &context) const FINAL
Called by writeLayerXML(), used by derived classes to encode provider's specific data source to proje...
void beginEditCommand(const QString &text)
Create edit command for undo/redo operations.
QString displayField() const
This is a shorthand for accessing the displayExpression if it is a simple field.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult addRing(const QVector< QgsPointXY > &ring, QgsFeatureId *featureId=nullptr)
Adds a ring to polygon/multipolygon features.
void setDiagramRenderer(QgsDiagramRenderer *r)
Sets diagram rendering object (takes ownership)
void geometryChanged(QgsFeatureId fid, const QgsGeometry &geometry)
Emitted whenever a geometry change is done in the edit buffer.
QgsEditFormConfig editFormConfig
QList< const QgsFeatureRendererGenerator * > featureRendererGenerators() const
Returns a list of the feature renderer generators owned by the layer.
Qgis::FeatureAvailability hasFeatures() const FINAL
Determines if this vector layer has features.
bool moveVertex(double x, double y, QgsFeatureId atFeatureId, int atVertex)
Moves the vertex at the given position number, ring and item (first number is index 0),...
QgsGeometry getGeometry(QgsFeatureId fid) const
Queries the layer for the geometry at the given id.
int addTopologicalPoints(const QgsGeometry &geom)
Adds topological points for every vertex of the geometry.
void beforeModifiedCheck() const
Emitted when the layer is checked for modifications. Use for last-minute additions.
Q_INVOKABLE QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
Q_INVOKABLE void invertSelection()
Selects not selected features and deselects selected ones.
const QgsDiagramRenderer * diagramRenderer() const
void setExtent3D(const QgsBox3D &rect) FINAL
Sets the extent.
Q_INVOKABLE bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues=QgsAttributeMap(), bool skipDefaultValues=false, QgsVectorLayerToolsContext *context=nullptr)
Changes attributes' values for a feature (but does not immediately commit the changes).
QgsMapLayerSelectionProperties * selectionProperties() override
Returns the layer's selection properties.
bool changeGeometry(QgsFeatureId fid, QgsGeometry &geometry, bool skipDefaultValue=false)
Changes a feature's geometry within the layer's edit buffer (but does not immediately commit the chan...
static const QgsSettingsEntryDouble * settingsSimplifyDrawingTol
Qgis::SpatialIndexPresence hasSpatialIndex() const override
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const FINAL
Calculates a list of unique values contained within an attribute in the layer.
void setFieldSplitPolicy(int index, Qgis::FieldDomainSplitPolicy policy)
Sets a split policy for the field with the specified index.
bool forceLocalOptimization() const
Gets where the simplification executes, after fetch the geometries from provider, or when supported,...
Qgis::VectorRenderingSimplificationFlags simplifyHints() const
Gets the simplification hints of the vector layer managed.
float maximumScale() const
Gets the maximum scale at which the layer should be simplified.
Qgis::VectorSimplificationAlgorithm simplifyAlgorithm() const
Gets the local simplification algorithm of the vector layer managed.
void setThreshold(float threshold)
Sets the simplification threshold of the vector layer managed.
void setForceLocalOptimization(bool localOptimization)
Sets where the simplification executes, after fetch the geometries from provider, or when supported,...
void setSimplifyHints(Qgis::VectorRenderingSimplificationFlags simplifyHints)
Sets the simplification hints of the vector layer managed.
float threshold() const
Gets the simplification threshold of the vector layer managed.
void setMaximumScale(float maximumScale)
Sets the maximum scale at which the layer should be simplified.
void setSimplifyAlgorithm(Qgis::VectorSimplificationAlgorithm simplifyAlgorithm)
Sets the local simplification algorithm of the vector layer managed.
@ Referencing
The layer is referencing (or the "child" / "right" layer in the relationship)
@ Referenced
The layer is referenced (or the "parent" / "left" left in the relationship)
static void writeXml(const QgsVectorLayer *layer, WeakRelationType type, const QgsRelation &relation, QDomNode &node, QDomDocument &doc)
Writes a weak relation infoto an XML structure.
static QgsWeakRelation readXml(const QgsVectorLayer *layer, WeakRelationType type, const QDomNode &node, const QgsPathResolver resolver)
Returns a weak relation for the given layer.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static Q_INVOKABLE QString displayString(Qgis::WkbType type)
Returns a non-translated display string type for a WKB type, e.g., the geometry name used in WKT geom...
static Q_INVOKABLE QString geometryDisplayString(Qgis::GeometryType type)
Returns a display string for a geometry type.
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
static QgsBox3D readBox3D(const QDomElement &element)
Decodes a DOM element to a 3D box.
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
static QgsRectangle readRectangle(const QDomElement &element)
@ UnknownCount
Provider returned an unknown feature count.
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsVariantEqual(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether they are equal, two NULL values are always treated a...
Definition qgis.cpp:351
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is less than the second.
Definition qgis.cpp:286
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is greater than the second.
Definition qgis.cpp:291
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
Definition qgis.h:6597
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6578
QString qgsFlagValueToKeys(const T &value, bool *returnOk=nullptr)
Returns the value for the given keys of a flag.
Definition qgis.h:6636
T qgsFlagKeysToValue(const QString &keys, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given keys of a flag.
Definition qgis.h:6658
QMap< QString, QString > QgsStringMap
Definition qgis.h:6901
QVector< QgsPoint > QgsPointSequence
QMap< int, QVariant > QgsAttributeMap
QList< QgsFeature > QgsFeatureList
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
QList< int > QgsAttributeList
Definition qgsfield.h:27
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:41
#define QgsDebugError(str)
Definition qgslogger.h:40
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
#define RENDERER_TAG_NAME
Definition qgsrenderer.h:54
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS_NON_FATAL
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS
bool saveStyle_t(const QString &uri, const QString &qmlStyle, const QString &sldStyle, const QString &styleName, const QString &styleDescription, const QString &uiFileContent, bool useAsDefault, QString &errCause)
int listStyles_t(const QString &uri, QStringList &ids, QStringList &names, QStringList &descriptions, QString &errCause)
QString getStyleById_t(const QString &uri, QString styleID, QString &errCause)
bool deleteStyleById_t(const QString &uri, QString styleID, QString &errCause)
QString loadStyle_t(const QString &uri, QString &errCause)
QList< int > QgsAttributeList
QMap< QgsFeatureId, QgsFeature > QgsFeatureMap
A bundle of parameters controlling aggregate calculation.
Setting options for creating vector data providers.
Context for cascade delete features.
QList< QgsVectorLayer * > handledLayers(bool includeAuxiliaryLayers=true) const
Returns a list of all layers affected by the delete operation.
QMap< QgsVectorLayer *, QgsFeatureIds > mHandledFeatures
QgsFeatureIds handledFeatures(QgsVectorLayer *layer) const
Returns a list of feature IDs from the specified layer affected by the delete operation.
Setting options for loading vector layers.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
bool forceReadOnly
Controls whether the layer is forced to be load as Read Only.
bool loadDefaultStyle
Set to true if the default layer style should be loaded.
QgsCoordinateTransformContext transformContext
Coordinate transform context.
QgsCoordinateReferenceSystem fallbackCrs
Fallback layer coordinate reference system.
Qgis::WkbType fallbackWkbType
Fallback geometry type.
bool loadAllStoredStyles
Controls whether the stored styles will be all loaded.