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