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