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