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