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