QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsvectorlayer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvectorlayer.cpp
3 --------------------
4 begin : Oct 29, 2003
5 copyright : (C) 2003 by Gary E.Sherman
6 email : sherman at mrcc.com
7
8 This class implements a generic means to display vector layers. The features
9 and attributes are read from the data store using a "data provider" plugin.
10 QgsVectorLayer can be used with any data store for which an appropriate
11 plugin is available.
12
13***************************************************************************/
14
15/***************************************************************************
16 * *
17 * This program is free software; you can redistribute it and/or modify *
18 * it under the terms of the GNU General Public License as published by *
19 * the Free Software Foundation; either version 2 of the License, or *
20 * (at your option) any later version. *
21 * *
22 ***************************************************************************/
23
24#include "qgis.h" //for globals
25#include "qgssettings.h"
26#include "qgsvectorlayer.h"
27#include "qgsactionmanager.h"
28#include "qgsapplication.h"
29#include "qgsconditionalstyle.h"
31#include "qgscurve.h"
32#include "qgsdatasourceuri.h"
35#include "qgsfeature.h"
36#include "qgsfeaturerequest.h"
37#include "qgsfields.h"
38#include "qgsmaplayerfactory.h"
39#include "qgsgeometry.h"
41#include "qgslogger.h"
42#include "qgsmaplayerlegend.h"
43#include "qgsmessagelog.h"
44#include "qgsogcutils.h"
45#include "qgspainting.h"
46#include "qgspointxy.h"
47#include "qgsproject.h"
48#include "qgsproviderregistry.h"
49#include "qgsrectangle.h"
50#include "qgsrelationmanager.h"
51#include "qgsweakrelation.h"
52#include "qgsrendercontext.h"
64#include "qgspoint.h"
65#include "qgsrenderer.h"
66#include "qgssymbollayer.h"
67#include "qgsdiagramrenderer.h"
68#include "qgspallabeling.h"
72#include "qgsfeedback.h"
73#include "qgsxmlutils.h"
74#include "qgsunittypes.h"
75#include "qgstaskmanager.h"
76#include "qgstransaction.h"
77#include "qgsauxiliarystorage.h"
78#include "qgsgeometryoptions.h"
80#include "qgsruntimeprofiler.h"
82#include "qgsvectorlayerutils.h"
84#include "qgsprofilerequest.h"
85#include "qgssymbollayerutils.h"
86
87#include <QDir>
88#include <QFile>
89#include <QImage>
90#include <QPainter>
91#include <QPainterPath>
92#include <QPolygonF>
93#include <QProgressDialog>
94#include <QString>
95#include <QDomNode>
96#include <QVector>
97#include <QStringBuilder>
98#include <QUrl>
99#include <QUndoCommand>
100#include <QUrlQuery>
101#include <QUuid>
102#include <QRegularExpression>
103#include <QTimer>
104
105#include <limits>
106#include <optional>
107
108#ifdef TESTPROVIDERLIB
109#include <dlfcn.h>
110#endif
111
112typedef bool saveStyle_t(
113 const QString &uri,
114 const QString &qmlStyle,
115 const QString &sldStyle,
116 const QString &styleName,
117 const QString &styleDescription,
118 const QString &uiFileContent,
119 bool useAsDefault,
120 QString &errCause
121);
122
123typedef QString loadStyle_t(
124 const QString &uri,
125 QString &errCause
126);
127
128typedef int listStyles_t(
129 const QString &uri,
130 QStringList &ids,
131 QStringList &names,
132 QStringList &descriptions,
133 QString &errCause
134);
135
136typedef QString getStyleById_t(
137 const QString &uri,
138 QString styleID,
139 QString &errCause
140);
141
142typedef bool deleteStyleById_t(
143 const QString &uri,
144 QString styleID,
145 QString &errCause
146);
147
148
149QgsVectorLayer::QgsVectorLayer( const QString &vectorLayerPath,
150 const QString &baseName,
151 const QString &providerKey,
152 const QgsVectorLayer::LayerOptions &options )
153 : QgsMapLayer( QgsMapLayerType::VectorLayer, baseName, vectorLayerPath )
154 , mTemporalProperties( new QgsVectorLayerTemporalProperties( this ) )
155 , mElevationProperties( new QgsVectorLayerElevationProperties( this ) )
156 , mAuxiliaryLayer( nullptr )
157 , mAuxiliaryLayerKey( QString() )
158 , mReadExtentFromXml( options.readExtentFromXml )
159 , mRefreshRendererTimer( new QTimer( this ) )
160{
162
163 if ( options.fallbackCrs.isValid() )
164 setCrs( options.fallbackCrs, false );
165 mWkbType = options.fallbackWkbType;
166
167 setProviderType( providerKey );
168
169 mGeometryOptions = std::make_unique<QgsGeometryOptions>();
170 mActions = new QgsActionManager( this );
171 mConditionalStyles = new QgsConditionalLayerStyles( this );
172 mStoredExpressionManager = new QgsStoredExpressionManager();
173 mStoredExpressionManager->setParent( this );
174
175 mJoinBuffer = new QgsVectorLayerJoinBuffer( this );
176 mJoinBuffer->setParent( this );
177 connect( mJoinBuffer, &QgsVectorLayerJoinBuffer::joinedFieldsChanged, this, &QgsVectorLayer::onJoinedFieldsChanged );
178
179 mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
180 // if we're given a provider type, try to create and bind one to this layer
181 if ( !vectorLayerPath.isEmpty() && !mProviderKey.isEmpty() )
182 {
183 QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
184 QgsDataProvider::ReadFlags providerFlags = QgsDataProvider::ReadFlags();
185 if ( options.loadDefaultStyle )
186 {
188 }
189 if ( options.forceReadOnly )
190 {
191 providerFlags |= QgsDataProvider::ForceReadOnly;
192 mDataSourceReadOnly = true;
193 }
194 setDataSource( vectorLayerPath, baseName, providerKey, providerOptions, providerFlags );
195 }
196
197 for ( const QgsField &field : std::as_const( mFields ) )
198 {
199 if ( !mAttributeAliasMap.contains( field.name() ) )
200 mAttributeAliasMap.insert( field.name(), QString() );
201 }
202
203 if ( isValid() )
204 {
205 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
206 if ( !mTemporalProperties->isActive() )
207 {
208 // didn't populate temporal properties from provider metadata, so at least try to setup some initially nice
209 // selections
210 mTemporalProperties->guessDefaultsFromFields( mFields );
211 }
212
213 mElevationProperties->setDefaultsFromLayer( this );
214 }
215
216 connect( this, &QgsVectorLayer::selectionChanged, this, [ = ] { triggerRepaint(); } );
217 connect( QgsProject::instance()->relationManager(), &QgsRelationManager::relationsLoaded, this, &QgsVectorLayer::onRelationsLoaded );
218
222
223 // Default simplify drawing settings
224 QgsSettings settings;
225 mSimplifyMethod.setSimplifyHints( settings.flagValue( QStringLiteral( "qgis/simplifyDrawingHints" ), mSimplifyMethod.simplifyHints(), QgsSettings::NoSection ) );
226 mSimplifyMethod.setSimplifyAlgorithm( settings.enumValue( QStringLiteral( "qgis/simplifyAlgorithm" ), mSimplifyMethod.simplifyAlgorithm() ) );
227 mSimplifyMethod.setThreshold( settings.value( QStringLiteral( "qgis/simplifyDrawingTol" ), mSimplifyMethod.threshold() ).toFloat() );
228 mSimplifyMethod.setForceLocalOptimization( settings.value( QStringLiteral( "qgis/simplifyLocal" ), mSimplifyMethod.forceLocalOptimization() ).toBool() );
229 mSimplifyMethod.setMaximumScale( settings.value( QStringLiteral( "qgis/simplifyMaxScale" ), mSimplifyMethod.maximumScale() ).toFloat() );
230
231 connect( mRefreshRendererTimer, &QTimer::timeout, this, [ = ] { triggerRepaint( true ); } );
232}
233
235{
236 emit willBeDeleted();
237
238 setValid( false );
239
240 delete mDataProvider;
241 delete mEditBuffer;
242 delete mJoinBuffer;
243 delete mExpressionFieldBuffer;
244 delete mLabeling;
245 delete mDiagramLayerSettings;
246 delete mDiagramRenderer;
247
248 delete mActions;
249
250 delete mRenderer;
251 delete mConditionalStyles;
252 delete mStoredExpressionManager;
253
254 if ( mFeatureCounter )
255 mFeatureCounter->cancel();
256
257 qDeleteAll( mRendererGenerators );
258}
259
261{
263 // We get the data source string from the provider when
264 // possible because some providers may have changed it
265 // directly (memory provider does that).
266 QString dataSource;
267 if ( mDataProvider )
268 {
269 dataSource = mDataProvider->dataSourceUri();
270 options.transformContext = mDataProvider->transformContext();
271 }
272 else
273 {
274 dataSource = source();
275 }
276 options.forceReadOnly = mDataSourceReadOnly;
277 QgsVectorLayer *layer = new QgsVectorLayer( dataSource, name(), mProviderKey, options );
278 if ( mDataProvider && layer->dataProvider() )
279 {
280 layer->dataProvider()->handlePostCloneOperations( mDataProvider );
281 }
282 QgsMapLayer::clone( layer );
283
284 QList<QgsVectorLayerJoinInfo> joins = vectorJoins();
285 const auto constJoins = joins;
286 for ( const QgsVectorLayerJoinInfo &join : constJoins )
287 {
288 // do not copy join information for auxiliary layer
289 if ( !auxiliaryLayer()
290 || ( auxiliaryLayer() && auxiliaryLayer()->id() != join.joinLayerId() ) )
291 layer->addJoin( join );
292 }
293
294 if ( mDataProvider )
295 layer->setProviderEncoding( mDataProvider->encoding() );
298 layer->setReadOnly( isReadOnly() );
303
304 const auto constActions = actions()->actions();
305 for ( const QgsAction &action : constActions )
306 {
307 layer->actions()->addAction( action );
308 }
309
310 if ( auto *lRenderer = renderer() )
311 {
312 layer->setRenderer( lRenderer->clone() );
313 }
314
315 if ( auto *lLabeling = labeling() )
316 {
317 layer->setLabeling( lLabeling->clone() );
318 }
320
322
323 if ( auto *lDiagramRenderer = diagramRenderer() )
324 {
325 layer->setDiagramRenderer( lDiagramRenderer->clone() );
326 }
327
328 if ( auto *lDiagramLayerSettings = diagramLayerSettings() )
329 {
330 layer->setDiagramLayerSettings( *lDiagramLayerSettings );
331 }
332
333 for ( int i = 0; i < fields().count(); i++ )
334 {
335 layer->setFieldAlias( i, attributeAlias( i ) );
337 layer->setEditorWidgetSetup( i, editorWidgetSetup( i ) );
340
341 QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength> constraints = fieldConstraintsAndStrength( i );
342 auto constraintIt = constraints.constBegin();
343 for ( ; constraintIt != constraints.constEnd(); ++ constraintIt )
344 {
345 layer->setFieldConstraint( i, constraintIt.key(), constraintIt.value() );
346 }
347
348 if ( fields().fieldOrigin( i ) == QgsFields::OriginExpression )
349 {
350 layer->addExpressionField( expressionField( i ), fields().at( i ) );
351 }
352 }
353
355
356 if ( auto *lAuxiliaryLayer = auxiliaryLayer() )
357 layer->setAuxiliaryLayer( lAuxiliaryLayer->clone( layer ) );
358
359 layer->mElevationProperties = mElevationProperties->clone();
360 layer->mElevationProperties->setParent( layer );
361
362 return layer;
363}
364
366{
367 if ( mDataProvider )
368 {
369 return mDataProvider->storageType();
370 }
371 return QString();
372}
373
374
376{
377 if ( mDataProvider )
378 {
379 return mDataProvider->capabilitiesString();
380 }
381 return QString();
382}
383
385{
386 return mDataProvider && mDataProvider->isSqlQuery();
387}
388
389Qgis::VectorLayerTypeFlags QgsVectorLayer::vectorLayerTypeFlags() const
390{
391 return mDataProvider ? mDataProvider->vectorLayerTypeFlags() : Qgis::VectorLayerTypeFlags();
392}
393
395{
396 if ( mDataProvider )
397 {
398 return mDataProvider->dataComment();
399 }
400 return QString();
401}
402
404{
405 return crs();
406}
407
409{
410 return name();
411}
412
414{
415 if ( mDataProvider )
416 {
417 mDataProvider->reloadData();
418 updateFields();
419 }
420}
421
423{
424 return new QgsVectorLayerRenderer( this, rendererContext );
425}
426
427
428void QgsVectorLayer::drawVertexMarker( double x, double y, QPainter &p, Qgis::VertexMarkerType type, int m )
429{
430 switch ( type )
431 {
433 p.setPen( QColor( 50, 100, 120, 200 ) );
434 p.setBrush( QColor( 200, 200, 210, 120 ) );
435 p.drawEllipse( x - m, y - m, m * 2 + 1, m * 2 + 1 );
436 break;
437
439 p.setPen( QColor( 255, 0, 0 ) );
440 p.drawLine( x - m, y + m, x + m, y - m );
441 p.drawLine( x - m, y - m, x + m, y + m );
442 break;
443
445 break;
446 }
447}
448
450{
451 mSelectedFeatureIds.insert( fid );
452 mPreviousSelectedFeatureIds.clear();
453
454 emit selectionChanged( QgsFeatureIds() << fid, QgsFeatureIds(), false );
455}
456
457void QgsVectorLayer::select( const QgsFeatureIds &featureIds )
458{
459 mSelectedFeatureIds.unite( featureIds );
460 mPreviousSelectedFeatureIds.clear();
461
462 emit selectionChanged( featureIds, QgsFeatureIds(), false );
463}
464
466{
467 mSelectedFeatureIds.remove( fid );
468 mPreviousSelectedFeatureIds.clear();
469
470 emit selectionChanged( QgsFeatureIds(), QgsFeatureIds() << fid, false );
471}
472
474{
475 mSelectedFeatureIds.subtract( featureIds );
476 mPreviousSelectedFeatureIds.clear();
477
478 emit selectionChanged( QgsFeatureIds(), featureIds, false );
479}
480
482{
483 // normalize the rectangle
484 rect.normalize();
485
486 QgsFeatureIds newSelection;
487
489 .setFilterRect( rect )
491 .setNoAttributes() );
492
493 QgsFeature feat;
494 while ( features.nextFeature( feat ) )
495 {
496 newSelection << feat.id();
497 }
498 features.close();
499
500 selectByIds( newSelection, behavior );
501}
502
503void QgsVectorLayer::selectByExpression( const QString &expression, Qgis::SelectBehavior behavior, QgsExpressionContext *context )
504{
505 QgsFeatureIds newSelection;
506
507 std::optional< QgsExpressionContext > defaultContext;
508 if ( !context )
509 {
510 defaultContext.emplace( QgsExpressionContextUtils::globalProjectLayerScopes( this ) );
511 context = &defaultContext.value();
512 }
513
515 {
517 .setExpressionContext( *context )
520
521 QgsFeatureIterator features = getFeatures( request );
522
523 if ( behavior == Qgis::SelectBehavior::AddToSelection )
524 {
525 newSelection = selectedFeatureIds();
526 }
527 QgsFeature feat;
528 while ( features.nextFeature( feat ) )
529 {
530 newSelection << feat.id();
531 }
532 features.close();
533 }
535 {
536 QgsExpression exp( expression );
537 exp.prepare( context );
538
539 QgsFeatureIds oldSelection = selectedFeatureIds();
540 QgsFeatureRequest request = QgsFeatureRequest().setFilterFids( oldSelection );
541
542 //refine request
543 if ( !exp.needsGeometry() )
546
547 QgsFeatureIterator features = getFeatures( request );
548 QgsFeature feat;
549 while ( features.nextFeature( feat ) )
550 {
551 context->setFeature( feat );
552 bool matches = exp.evaluate( context ).toBool();
553
554 if ( matches && behavior == Qgis::SelectBehavior::IntersectSelection )
555 {
556 newSelection << feat.id();
557 }
558 else if ( !matches && behavior == Qgis::SelectBehavior::RemoveFromSelection )
559 {
560 newSelection << feat.id();
561 }
562 }
563 }
564
565 selectByIds( newSelection );
566}
567
569{
570 QgsFeatureIds newSelection;
571
572 switch ( behavior )
573 {
575 newSelection = ids;
576 break;
577
579 newSelection = mSelectedFeatureIds + ids;
580 break;
581
583 newSelection = mSelectedFeatureIds - ids;
584 break;
585
587 newSelection = mSelectedFeatureIds.intersect( ids );
588 break;
589 }
590
591 QgsFeatureIds deselectedFeatures = mSelectedFeatureIds - newSelection;
592 mSelectedFeatureIds = newSelection;
593 mPreviousSelectedFeatureIds.clear();
594
595 emit selectionChanged( newSelection, deselectedFeatures, true );
596}
597
598void QgsVectorLayer::modifySelection( const QgsFeatureIds &selectIds, const QgsFeatureIds &deselectIds )
599{
600 QgsFeatureIds intersectingIds = selectIds & deselectIds;
601 if ( !intersectingIds.isEmpty() )
602 {
603 QgsDebugMsgLevel( QStringLiteral( "Trying to select and deselect the same item at the same time. Unsure what to do. Selecting dubious items." ), 3 );
604 }
605
606 mSelectedFeatureIds -= deselectIds;
607 mSelectedFeatureIds += selectIds;
608 mPreviousSelectedFeatureIds.clear();
609
610 emit selectionChanged( selectIds, deselectIds - intersectingIds, false );
611}
612
614{
616 ids.subtract( mSelectedFeatureIds );
617 selectByIds( ids );
618}
619
621{
623}
624
626{
627 // normalize the rectangle
628 rect.normalize();
629
631 .setFilterRect( rect )
633 .setNoAttributes() );
634
635 QgsFeatureIds selectIds;
636 QgsFeatureIds deselectIds;
637
638 QgsFeature fet;
639 while ( fit.nextFeature( fet ) )
640 {
641 if ( mSelectedFeatureIds.contains( fet.id() ) )
642 {
643 deselectIds << fet.id();
644 }
645 else
646 {
647 selectIds << fet.id();
648 }
649 }
650
651 modifySelection( selectIds, deselectIds );
652}
653
655{
656 if ( mSelectedFeatureIds.isEmpty() )
657 return;
658
659 const QgsFeatureIds previous = mSelectedFeatureIds;
661 mPreviousSelectedFeatureIds = previous;
662}
663
665{
666 if ( mPreviousSelectedFeatureIds.isEmpty() || !mSelectedFeatureIds.empty() )
667 return;
668
669 selectByIds( mPreviousSelectedFeatureIds );
670}
671
673{
674 return mDataProvider;
675}
676
678{
679 return mDataProvider;
680}
681
683{
684 return mTemporalProperties;
685}
686
688{
689 return mElevationProperties;
690}
691
693{
694 QgsProfileRequest modifiedRequest( request );
696 return new QgsVectorLayerProfileGenerator( this, modifiedRequest );
697}
698
699void QgsVectorLayer::setProviderEncoding( const QString &encoding )
700{
701 if ( isValid() && mDataProvider && mDataProvider->encoding() != encoding )
702 {
703 mDataProvider->setEncoding( encoding );
704 updateFields();
705 }
706}
707
709{
710 delete mDiagramRenderer;
711 mDiagramRenderer = r;
712 emit rendererChanged();
713 emit styleChanged();
714}
715
717{
718 return QgsWkbTypes::geometryType( mWkbType );
719}
720
722{
723 return mWkbType;
724}
725
727{
728 if ( !isValid() || !isSpatial() || mSelectedFeatureIds.isEmpty() || !mDataProvider ) //no selected features
729 {
730 return QgsRectangle( 0, 0, 0, 0 );
731 }
732
733 QgsRectangle r, retval;
734 retval.setMinimal();
735
736 QgsFeature fet;
737 if ( mDataProvider->capabilities() & QgsVectorDataProvider::SelectAtId )
738 {
740 .setFilterFids( mSelectedFeatureIds )
741 .setNoAttributes() );
742
743 while ( fit.nextFeature( fet ) )
744 {
745 if ( !fet.hasGeometry() )
746 continue;
747 r = fet.geometry().boundingBox();
748 retval.combineExtentWith( r );
749 }
750 }
751 else
752 {
754 .setNoAttributes() );
755
756 while ( fit.nextFeature( fet ) )
757 {
758 if ( mSelectedFeatureIds.contains( fet.id() ) )
759 {
760 if ( fet.hasGeometry() )
761 {
762 r = fet.geometry().boundingBox();
763 retval.combineExtentWith( r );
764 }
765 }
766 }
767 }
768
769 if ( retval.width() == 0.0 || retval.height() == 0.0 )
770 {
771 // If all of the features are at the one point, buffer the
772 // rectangle a bit. If they are all at zero, do something a bit
773 // more crude.
774
775 if ( retval.xMinimum() == 0.0 && retval.xMaximum() == 0.0 &&
776 retval.yMinimum() == 0.0 && retval.yMaximum() == 0.0 )
777 {
778 retval.set( -1.0, -1.0, 1.0, 1.0 );
779 }
780 }
781
782 return retval;
783}
784
786{
787 return mLabelsEnabled && static_cast< bool >( mLabeling );
788}
789
791{
792 mLabelsEnabled = enabled;
793}
794
796{
797 if ( !mDiagramRenderer || !mDiagramLayerSettings )
798 return false;
799
800 QList<QgsDiagramSettings> settingList = mDiagramRenderer->diagramSettings();
801 if ( !settingList.isEmpty() )
802 {
803 return settingList.at( 0 ).enabled;
804 }
805 return false;
806}
807
808long long QgsVectorLayer::featureCount( const QString &legendKey ) const
809{
810 if ( !mSymbolFeatureCounted )
811 return -1;
812
813 return mSymbolFeatureCountMap.value( legendKey, -1 );
814}
815
816QgsFeatureIds QgsVectorLayer::symbolFeatureIds( const QString &legendKey ) const
817{
818 if ( !mSymbolFeatureCounted )
819 return QgsFeatureIds();
820
821 return mSymbolFeatureIdMap.value( legendKey, QgsFeatureIds() );
822}
824{
825 if ( ( mSymbolFeatureCounted || mFeatureCounter ) && !( storeSymbolFids && mSymbolFeatureIdMap.isEmpty() ) )
826 return mFeatureCounter;
827
828 mSymbolFeatureCountMap.clear();
829 mSymbolFeatureIdMap.clear();
830
831 if ( !isValid() )
832 {
833 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer" ), 3 );
834 return mFeatureCounter;
835 }
836 if ( !mDataProvider )
837 {
838 QgsDebugMsgLevel( QStringLiteral( "invoked with null mDataProvider" ), 3 );
839 return mFeatureCounter;
840 }
841 if ( !mRenderer )
842 {
843 QgsDebugMsgLevel( QStringLiteral( "invoked with null mRenderer" ), 3 );
844 return mFeatureCounter;
845 }
846
847 if ( !mFeatureCounter || ( storeSymbolFids && mSymbolFeatureIdMap.isEmpty() ) )
848 {
849 mFeatureCounter = new QgsVectorLayerFeatureCounter( this, QgsExpressionContext(), storeSymbolFids );
850 connect( mFeatureCounter, &QgsTask::taskCompleted, this, &QgsVectorLayer::onFeatureCounterCompleted, Qt::UniqueConnection );
851 connect( mFeatureCounter, &QgsTask::taskTerminated, this, &QgsVectorLayer::onFeatureCounterTerminated, Qt::UniqueConnection );
852 QgsApplication::taskManager()->addTask( mFeatureCounter );
853 }
854
855 return mFeatureCounter;
856}
857
859{
860 // do not update extent by default when trust project option is activated
861 if ( force || !mReadExtentFromXml || ( mReadExtentFromXml && mXmlExtent.isNull() ) )
862 mValidExtent = false;
863}
864
866{
868 mValidExtent = true;
869}
870
871void QgsVectorLayer::updateDefaultValues( QgsFeatureId fid, QgsFeature feature )
872{
873 if ( !mDefaultValueOnUpdateFields.isEmpty() )
874 {
875 if ( !feature.isValid() )
876 feature = getFeature( fid );
877
878 int size = mFields.size();
879 for ( int idx : std::as_const( mDefaultValueOnUpdateFields ) )
880 {
881 if ( idx < 0 || idx >= size )
882 continue;
883
884 feature.setAttribute( idx, defaultValue( idx, feature ) );
885 updateFeature( feature, true );
886 }
887 }
888}
889
891{
892 QgsRectangle rect;
893 rect.setMinimal();
894
895 if ( !isSpatial() )
896 return rect;
897
898 if ( !mValidExtent && mLazyExtent && mReadExtentFromXml && !mXmlExtent.isNull() )
899 {
900 updateExtent( mXmlExtent );
901 mValidExtent = true;
902 mLazyExtent = false;
903 }
904
905 if ( !mValidExtent && mLazyExtent && mDataProvider && mDataProvider->isValid() )
906 {
907 // store the extent
908 updateExtent( mDataProvider->extent() );
909 mValidExtent = true;
910 mLazyExtent = false;
911
912 // show the extent
913 QgsDebugMsgLevel( QStringLiteral( "Extent of layer: %1" ).arg( mExtent.toString() ), 3 );
914 }
915
916 if ( mValidExtent )
917 return QgsMapLayer::extent();
918
919 if ( !isValid() || !mDataProvider )
920 {
921 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
922 return rect;
923 }
924
925 if ( !mEditBuffer ||
926 ( !mDataProvider->transaction() && ( mEditBuffer->deletedFeatureIds().isEmpty() && mEditBuffer->changedGeometries().isEmpty() ) ) ||
928 {
929 mDataProvider->updateExtents();
930
931 // get the extent of the layer from the provider
932 // but only when there are some features already
933 if ( mDataProvider->featureCount() != 0 )
934 {
935 const QgsRectangle r = mDataProvider->extent();
936 rect.combineExtentWith( r );
937 }
938
939 if ( mEditBuffer && !mDataProvider->transaction() )
940 {
941 const auto addedFeatures = mEditBuffer->addedFeatures();
942 for ( QgsFeatureMap::const_iterator it = addedFeatures.constBegin(); it != addedFeatures.constEnd(); ++it )
943 {
944 if ( it->hasGeometry() )
945 {
946 const QgsRectangle r = it->geometry().boundingBox();
947 rect.combineExtentWith( r );
948 }
949 }
950 }
951 }
952 else
953 {
955 .setNoAttributes() );
956
957 QgsFeature fet;
958 while ( fit.nextFeature( fet ) )
959 {
960 if ( fet.hasGeometry() && fet.geometry().type() != QgsWkbTypes::UnknownGeometry )
961 {
962 const QgsRectangle bb = fet.geometry().boundingBox();
963 rect.combineExtentWith( bb );
964 }
965 }
966 }
967
968 if ( rect.xMinimum() > rect.xMaximum() && rect.yMinimum() > rect.yMaximum() )
969 {
970 // special case when there are no features in provider nor any added
971 rect = QgsRectangle(); // use rectangle with zero coordinates
972 }
973
974 updateExtent( rect );
975 mValidExtent = true;
976
977 // Send this (hopefully) up the chain to the map canvas
978 emit recalculateExtents();
979
980 return rect;
981}
982
984{
985 return extent();
986}
987
989{
990 if ( !isValid() || !mDataProvider )
991 {
992 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
993 return customProperty( QStringLiteral( "storedSubsetString" ) ).toString();
994 }
995 return mDataProvider->subsetString();
996}
997
998bool QgsVectorLayer::setSubsetString( const QString &subset )
999{
1000 if ( !isValid() || !mDataProvider )
1001 {
1002 QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider or while editing" ), 3 );
1003 setCustomProperty( QStringLiteral( "storedSubsetString" ), subset );
1004 return false;
1005 }
1006 else if ( mEditBuffer )
1007 {
1008 QgsDebugMsgLevel( QStringLiteral( "invoked while editing" ), 3 );
1009 return false;
1010 }
1011
1012 if ( subset == mDataProvider->subsetString() )
1013 return true;
1014
1015 bool res = mDataProvider->setSubsetString( subset );
1016
1017 // get the updated data source string from the provider
1018 mDataSource = mDataProvider->dataSourceUri();
1019 updateExtents();
1020 updateFields();
1021
1022 if ( res )
1023 {
1024 emit subsetStringChanged();
1026 }
1027
1028 return res;
1029}
1030
1032{
1033 if ( isValid() && mDataProvider && !mEditBuffer && ( isSpatial() && geometryType() != QgsWkbTypes::PointGeometry ) && ( mSimplifyMethod.simplifyHints() & simplifyHint ) && renderContext.useRenderingOptimization() )
1034 {
1035 double maximumSimplificationScale = mSimplifyMethod.maximumScale();
1036
1037 // check maximum scale at which generalisation should be carried out
1038 return !( maximumSimplificationScale > 1 && renderContext.rendererScale() <= maximumSimplificationScale );
1039 }
1040 return false;
1041}
1042
1044{
1045 return mConditionalStyles;
1046}
1047
1049{
1050 if ( !isValid() || !mDataProvider )
1051 return QgsFeatureIterator();
1052
1053 return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( new QgsVectorLayerFeatureSource( this ), true, request ) );
1054}
1055
1057{
1058 QgsFeature feature;
1060 if ( feature.isValid() )
1061 return feature.geometry();
1062 else
1063 return QgsGeometry();
1064}
1065
1067{
1068 if ( !isValid() || !mEditBuffer || !mDataProvider )
1069 return false;
1070
1071
1072 if ( mGeometryOptions->isActive() )
1073 {
1074 QgsGeometry geom = feature.geometry();
1075 mGeometryOptions->apply( geom );
1076 feature.setGeometry( geom );
1077 }
1078
1079 bool success = mEditBuffer->addFeature( feature );
1080
1081 if ( success )
1082 {
1083 updateExtents();
1084
1085 if ( mJoinBuffer->containsJoins() )
1086 success = mJoinBuffer->addFeature( feature );
1087 }
1088
1089 return success;
1090}
1091
1092bool QgsVectorLayer::updateFeature( QgsFeature &updatedFeature, bool skipDefaultValues )
1093{
1094 if ( !mEditBuffer || !mDataProvider )
1095 {
1096 return false;
1097 }
1098
1099 QgsFeature currentFeature = getFeature( updatedFeature.id() );
1100 if ( currentFeature.isValid() )
1101 {
1102 bool hasChanged = false;
1103 bool hasError = false;
1104
1105 if ( ( updatedFeature.hasGeometry() || currentFeature.hasGeometry() ) && !updatedFeature.geometry().equals( currentFeature.geometry() ) )
1106 {
1107 QgsGeometry geometry = updatedFeature.geometry();
1108 if ( changeGeometry( updatedFeature.id(), geometry, true ) )
1109 {
1110 hasChanged = true;
1111 updatedFeature.setGeometry( geometry );
1112 }
1113 else
1114 {
1115 QgsDebugMsgLevel( QStringLiteral( "geometry of feature %1 could not be changed." ).arg( updatedFeature.id() ), 3 );
1116 }
1117 }
1118
1119 QgsAttributes fa = updatedFeature.attributes();
1120 QgsAttributes ca = currentFeature.attributes();
1121
1122 for ( int attr = 0; attr < fa.count(); ++attr )
1123 {
1124 if ( !qgsVariantEqual( fa.at( attr ), ca.at( attr ) ) )
1125 {
1126 if ( changeAttributeValue( updatedFeature.id(), attr, fa.at( attr ), ca.at( attr ), true ) )
1127 {
1128 hasChanged = true;
1129 }
1130 else
1131 {
1132 QgsDebugMsgLevel( QStringLiteral( "attribute %1 of feature %2 could not be changed." ).arg( attr ).arg( updatedFeature.id() ), 3 );
1133 hasError = true;
1134 }
1135 }
1136 }
1137 if ( hasChanged && !mDefaultValueOnUpdateFields.isEmpty() && !skipDefaultValues )
1138 updateDefaultValues( updatedFeature.id(), updatedFeature );
1139
1140 return !hasError;
1141 }
1142 else
1143 {
1144 QgsDebugMsgLevel( QStringLiteral( "feature %1 could not be retrieved" ).arg( updatedFeature.id() ), 3 );
1145 return false;
1146 }
1147}
1148
1149
1150bool QgsVectorLayer::insertVertex( double x, double y, QgsFeatureId atFeatureId, int beforeVertex )
1151{
1152 if ( !isValid() || !mEditBuffer || !mDataProvider )
1153 return false;
1154
1155 QgsVectorLayerEditUtils utils( this );
1156 bool result = utils.insertVertex( x, y, atFeatureId, beforeVertex );
1157 if ( result )
1158 updateExtents();
1159 return result;
1160}
1161
1162
1163bool QgsVectorLayer::insertVertex( const QgsPoint &point, QgsFeatureId atFeatureId, int beforeVertex )
1164{
1165 if ( !isValid() || !mEditBuffer || !mDataProvider )
1166 return false;
1167
1168 QgsVectorLayerEditUtils utils( this );
1169 bool result = utils.insertVertex( point, atFeatureId, beforeVertex );
1170 if ( result )
1171 updateExtents();
1172 return result;
1173}
1174
1175
1176bool QgsVectorLayer::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
1177{
1178 if ( !isValid() || !mEditBuffer || !mDataProvider )
1179 return false;
1180
1181 QgsVectorLayerEditUtils utils( this );
1182 bool result = utils.moveVertex( x, y, atFeatureId, atVertex );
1183
1184 if ( result )
1185 updateExtents();
1186 return result;
1187}
1188
1189bool QgsVectorLayer::moveVertex( const QgsPoint &p, QgsFeatureId atFeatureId, int atVertex )
1190{
1191 if ( !isValid() || !mEditBuffer || !mDataProvider )
1192 return false;
1193
1194 QgsVectorLayerEditUtils utils( this );
1195 bool result = utils.moveVertex( p, atFeatureId, atVertex );
1196
1197 if ( result )
1198 updateExtents();
1199 return result;
1200}
1201
1203{
1204 if ( !isValid() || !mEditBuffer || !mDataProvider )
1206
1207 QgsVectorLayerEditUtils utils( this );
1208 Qgis::VectorEditResult result = utils.deleteVertex( featureId, vertex );
1209
1210 if ( result == Qgis::VectorEditResult::Success )
1211 updateExtents();
1212 return result;
1213}
1214
1215
1217{
1218 if ( !isValid() || !mDataProvider || !( mDataProvider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) )
1219 {
1220 return false;
1221 }
1222
1223 if ( !isEditable() )
1224 {
1225 return false;
1226 }
1227
1228 int deleted = 0;
1229 int count = mSelectedFeatureIds.size();
1230 // Make a copy since deleteFeature modifies mSelectedFeatureIds
1231 QgsFeatureIds selectedFeatures( mSelectedFeatureIds );
1232 for ( QgsFeatureId fid : std::as_const( selectedFeatures ) )
1233 {
1234 deleted += deleteFeature( fid, context ); // removes from selection
1235 }
1236
1238 updateExtents();
1239
1240 if ( deletedCount )
1241 {
1242 *deletedCount = deleted;
1243 }
1244
1245 return deleted == count;
1246}
1247
1248static const QgsPointSequence vectorPointXY2pointSequence( const QVector<QgsPointXY> &points )
1249{
1250 QgsPointSequence pts;
1251 pts.reserve( points.size() );
1252 QVector<QgsPointXY>::const_iterator it = points.constBegin();
1253 while ( it != points.constEnd() )
1254 {
1255 pts.append( QgsPoint( *it ) );
1256 ++it;
1257 }
1258 return pts;
1259}
1260Qgis::GeometryOperationResult QgsVectorLayer::addRing( const QVector<QgsPointXY> &ring, QgsFeatureId *featureId )
1261{
1262 return addRing( vectorPointXY2pointSequence( ring ), featureId );
1263}
1264
1266{
1267 if ( !isValid() || !mEditBuffer || !mDataProvider )
1269
1270 QgsVectorLayerEditUtils utils( this );
1272
1273 //first try with selected features
1274 if ( !mSelectedFeatureIds.isEmpty() )
1275 {
1276 result = utils.addRing( ring, mSelectedFeatureIds, featureId );
1277 }
1278
1280 {
1281 //try with all intersecting features
1282 result = utils.addRing( ring, QgsFeatureIds(), featureId );
1283 }
1284
1285 return result;
1286}
1287
1289{
1290 if ( !isValid() || !mEditBuffer || !mDataProvider )
1291 {
1292 delete ring;
1294 }
1295
1296 if ( !ring )
1297 {
1299 }
1300
1301 if ( !ring->isClosed() )
1302 {
1303 delete ring;
1305 }
1306
1307 QgsVectorLayerEditUtils utils( this );
1309
1310 //first try with selected features
1311 if ( !mSelectedFeatureIds.isEmpty() )
1312 {
1313 result = utils.addRing( static_cast< QgsCurve * >( ring->clone() ), mSelectedFeatureIds, featureId );
1314 }
1315
1317 {
1318 //try with all intersecting features
1319 result = utils.addRing( static_cast< QgsCurve * >( ring->clone() ), QgsFeatureIds(), featureId );
1320 }
1321
1322 delete ring;
1323 return result;
1324}
1325
1327{
1328 QgsPointSequence pts;
1329 pts.reserve( points.size() );
1330 for ( QList<QgsPointXY>::const_iterator it = points.constBegin(); it != points.constEnd() ; ++it )
1331 {
1332 pts.append( QgsPoint( *it ) );
1333 }
1334 return addPart( pts );
1335}
1336
1337#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1338Qgis::GeometryOperationResult QgsVectorLayer::addPart( const QVector<QgsPointXY> &points )
1339{
1340 return addPart( vectorPointXY2pointSequence( points ) );
1341}
1342#endif
1343
1345{
1346 if ( !isValid() || !mEditBuffer || !mDataProvider )
1348
1349 //number of selected features must be 1
1350
1351 if ( mSelectedFeatureIds.empty() )
1352 {
1353 QgsDebugMsgLevel( QStringLiteral( "Number of selected features <1" ), 3 );
1355 }
1356 else if ( mSelectedFeatureIds.size() > 1 )
1357 {
1358 QgsDebugMsgLevel( QStringLiteral( "Number of selected features >1" ), 3 );
1360 }
1361
1362 QgsVectorLayerEditUtils utils( this );
1363 Qgis::GeometryOperationResult result = utils.addPart( points, *mSelectedFeatureIds.constBegin() );
1364
1366 updateExtents();
1367 return result;
1368}
1369
1371{
1372 if ( !isValid() || !mEditBuffer || !mDataProvider )
1374
1375 //number of selected features must be 1
1376
1377 if ( mSelectedFeatureIds.empty() )
1378 {
1379 QgsDebugMsgLevel( QStringLiteral( "Number of selected features <1" ), 3 );
1381 }
1382 else if ( mSelectedFeatureIds.size() > 1 )
1383 {
1384 QgsDebugMsgLevel( QStringLiteral( "Number of selected features >1" ), 3 );
1386 }
1387
1388 QgsVectorLayerEditUtils utils( this );
1389 Qgis::GeometryOperationResult result = utils.addPart( ring, *mSelectedFeatureIds.constBegin() );
1390
1392 updateExtents();
1393 return result;
1394}
1395
1396// TODO QGIS 4.0 -- this should return Qgis::GeometryOperationResult, not int
1397int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double dy )
1398{
1399 if ( !isValid() || !mEditBuffer || !mDataProvider )
1400 return static_cast< int >( Qgis::GeometryOperationResult::LayerNotEditable );
1401
1402 QgsVectorLayerEditUtils utils( this );
1403 int result = utils.translateFeature( featureId, dx, dy );
1404
1405 if ( result == static_cast< int >( Qgis::GeometryOperationResult::Success ) )
1406 updateExtents();
1407 return result;
1408}
1409
1410Qgis::GeometryOperationResult QgsVectorLayer::splitParts( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
1411{
1412 return splitParts( vectorPointXY2pointSequence( splitLine ), topologicalEditing );
1413}
1414
1416{
1417 if ( !isValid() || !mEditBuffer || !mDataProvider )
1419
1420 QgsVectorLayerEditUtils utils( this );
1421 return utils.splitParts( splitLine, topologicalEditing );
1422}
1423
1424Qgis::GeometryOperationResult QgsVectorLayer::splitFeatures( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
1425{
1426 return splitFeatures( vectorPointXY2pointSequence( splitLine ), topologicalEditing );
1427}
1428
1430{
1431 QgsLineString splitLineString( splitLine );
1432 QgsPointSequence topologyTestPoints;
1433 bool preserveCircular = false;
1434 return splitFeatures( &splitLineString, topologyTestPoints, preserveCircular, topologicalEditing );
1435}
1436
1437Qgis::GeometryOperationResult QgsVectorLayer::splitFeatures( const QgsCurve *curve, QgsPointSequence &topologyTestPoints, bool preserveCircular, bool topologicalEditing )
1438{
1439 if ( !isValid() || !mEditBuffer || !mDataProvider )
1441
1442 QgsVectorLayerEditUtils utils( this );
1443 return utils.splitFeatures( curve, topologyTestPoints, preserveCircular, topologicalEditing );
1444}
1445
1447{
1448 if ( !isValid() || !mEditBuffer || !mDataProvider )
1449 return -1;
1450
1451 QgsVectorLayerEditUtils utils( this );
1452 return utils.addTopologicalPoints( geom );
1453}
1454
1456{
1457 return addTopologicalPoints( QgsPoint( p ) );
1458}
1459
1461{
1462 if ( !isValid() || !mEditBuffer || !mDataProvider )
1463 return -1;
1464
1465 QgsVectorLayerEditUtils utils( this );
1466 return utils.addTopologicalPoints( p );
1467}
1468
1470{
1471 if ( !mValid || !mEditBuffer || !mDataProvider )
1472 return -1;
1473
1474 QgsVectorLayerEditUtils utils( this );
1475 return utils.addTopologicalPoints( ps );
1476}
1477
1479{
1480 if ( mLabeling == labeling )
1481 return;
1482
1483 delete mLabeling;
1484 mLabeling = labeling;
1485}
1486
1488{
1489 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
1490 return project()->startEditing( this );
1491
1492 if ( !isValid() || !mDataProvider )
1493 {
1494 return false;
1495 }
1496
1497 // allow editing if provider supports any of the capabilities
1498 if ( !supportsEditing() )
1499 {
1500 return false;
1501 }
1502
1503 if ( mEditBuffer )
1504 {
1505 // editing already underway
1506 return false;
1507 }
1508
1509 mDataProvider->enterUpdateMode();
1510
1511 emit beforeEditingStarted();
1512
1513 createEditBuffer();
1514
1515 updateFields();
1516
1517 emit editingStarted();
1518
1519 return true;
1520}
1521
1523{
1524 if ( mDataProvider )
1525 mDataProvider->setTransformContext( transformContext );
1526}
1527
1529{
1530 return mDataProvider ? mDataProvider->hasSpatialIndex() : QgsFeatureSource::SpatialIndexUnknown;
1531}
1532
1534{
1535 if ( mRenderer )
1536 if ( !mRenderer->accept( visitor ) )
1537 return false;
1538
1539 if ( mLabeling )
1540 if ( !mLabeling->accept( visitor ) )
1541 return false;
1542
1543 return true;
1544}
1545
1546bool QgsVectorLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1547{
1548 QgsDebugMsgLevel( QStringLiteral( "Datasource in QgsVectorLayer::readXml: %1" ).arg( mDataSource.toLocal8Bit().data() ), 3 );
1549
1550 //process provider key
1551 QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
1552
1553 if ( pkeyNode.isNull() )
1554 {
1555 mProviderKey.clear();
1556 }
1557 else
1558 {
1559 QDomElement pkeyElt = pkeyNode.toElement();
1560 mProviderKey = pkeyElt.text();
1561 }
1562
1563 // determine type of vector layer
1564 if ( !mProviderKey.isNull() )
1565 {
1566 // if the provider string isn't empty, then we successfully
1567 // got the stored provider
1568 }
1569 else if ( mDataSource.contains( QLatin1String( "dbname=" ) ) )
1570 {
1571 mProviderKey = QStringLiteral( "postgres" );
1572 }
1573 else
1574 {
1575 mProviderKey = QStringLiteral( "ogr" );
1576 }
1577
1578 const QDomElement elem = layer_node.toElement();
1580 QgsDataProvider::ReadFlags flags;
1582 {
1584 }
1585 if ( ( mReadFlags & QgsMapLayer::FlagDontResolveLayers ) || !setDataProvider( mProviderKey, options, flags ) )
1586 {
1588 {
1589 QgsDebugMsg( QStringLiteral( "Could not set data provider for layer %1" ).arg( publicSource() ) );
1590 }
1591
1592 // for invalid layer sources, we fallback to stored wkbType if available
1593 if ( elem.hasAttribute( QStringLiteral( "wkbType" ) ) )
1594 mWkbType = qgsEnumKeyToValue( elem.attribute( QStringLiteral( "wkbType" ) ), mWkbType );
1595 }
1597 {
1599 mDataSourceReadOnly = true;
1600 }
1601
1602 QDomElement pkeyElem = pkeyNode.toElement();
1603 if ( !pkeyElem.isNull() )
1604 {
1605 QString encodingString = pkeyElem.attribute( QStringLiteral( "encoding" ) );
1606 if ( mDataProvider && !encodingString.isEmpty() )
1607 {
1608 mDataProvider->setEncoding( encodingString );
1609 }
1610 }
1611
1612 // load vector joins - does not resolve references to layers yet
1613 mJoinBuffer->readXml( layer_node );
1614
1615 updateFields();
1616
1617 // If style doesn't include a legend, we'll need to make a default one later...
1618 mSetLegendFromStyle = false;
1619
1620 QString errorMsg;
1621 if ( !readSymbology( layer_node, errorMsg, context ) )
1622 {
1623 return false;
1624 }
1625
1626 readStyleManager( layer_node );
1627
1628 QDomNode depsNode = layer_node.namedItem( QStringLiteral( "dataDependencies" ) );
1629 QDomNodeList depsNodes = depsNode.childNodes();
1630 QSet<QgsMapLayerDependency> sources;
1631 for ( int i = 0; i < depsNodes.count(); i++ )
1632 {
1633 QString source = depsNodes.at( i ).toElement().attribute( QStringLiteral( "id" ) );
1634 sources << QgsMapLayerDependency( source );
1635 }
1636 setDependencies( sources );
1637
1638 if ( !mSetLegendFromStyle )
1640
1641 // read extent
1643 {
1644 mReadExtentFromXml = true;
1645 }
1646 if ( mReadExtentFromXml )
1647 {
1648 const QDomNode extentNode = layer_node.namedItem( QStringLiteral( "extent" ) );
1649 if ( !extentNode.isNull() )
1650 {
1651 mXmlExtent = QgsXmlUtils::readRectangle( extentNode.toElement() );
1652 }
1653 }
1654
1655 // auxiliary layer
1656 const QDomNode asNode = layer_node.namedItem( QStringLiteral( "auxiliaryLayer" ) );
1657 const QDomElement asElem = asNode.toElement();
1658 if ( !asElem.isNull() )
1659 {
1660 mAuxiliaryLayerKey = asElem.attribute( QStringLiteral( "key" ) );
1661 }
1662
1663 // QGIS Server WMS Dimensions
1664 mServerProperties->readXml( layer_node );
1665
1666 return isValid(); // should be true if read successfully
1667
1668} // void QgsVectorLayer::readXml
1669
1670
1671void QgsVectorLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider,
1672 const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1673{
1675
1676 mDataSource = dataSource;
1677 setName( baseName );
1678 setDataProvider( provider, options, flags );
1679
1680 if ( !isValid() )
1681 {
1682 return;
1683 }
1684
1685 // Always set crs
1687
1688 bool loadDefaultStyleFlag = false;
1690 {
1691 loadDefaultStyleFlag = true;
1692 }
1693
1694 // reset style if loading default style, style is missing, or geometry type is has changed (and layer is valid)
1695 if ( !renderer() || !legend() || ( isValid() && geomType != geometryType() ) || loadDefaultStyleFlag )
1696 {
1697 std::unique_ptr< QgsScopedRuntimeProfile > profile;
1698 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
1699 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Load layer style" ), QStringLiteral( "projectload" ) );
1700
1701 bool defaultLoadedFlag = false;
1702
1703 // defer style changed signal until we've set the renderer, labeling, everything.
1704 // we don't want multiple signals!
1705 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
1706
1707 // need to check whether the default style included a legend, and if not, we need to make a default legend
1708 // later...
1709 mSetLegendFromStyle = false;
1710
1711 // first check if there is a default style / propertysheet defined
1712 // for this layer and if so apply it
1713 // this should take precedence over all
1714 if ( !defaultLoadedFlag && loadDefaultStyleFlag )
1715 {
1716 loadDefaultStyle( defaultLoadedFlag );
1717 }
1718
1719 if ( loadDefaultStyleFlag && !defaultLoadedFlag && isSpatial() && mDataProvider->capabilities() & QgsVectorDataProvider::CreateRenderer )
1720 {
1721 // if we didn't load a default style for this layer, try to create a renderer directly from the data provider
1722 std::unique_ptr< QgsFeatureRenderer > defaultRenderer( mDataProvider->createRenderer() );
1723 if ( defaultRenderer )
1724 {
1725 defaultLoadedFlag = true;
1726 setRenderer( defaultRenderer.release() );
1727 }
1728 }
1729
1730 // if the default style failed to load or was disabled use some very basic defaults
1731 if ( !defaultLoadedFlag && isSpatial() )
1732 {
1733 // add single symbol renderer
1735 }
1736
1737 if ( !mSetLegendFromStyle )
1739
1740 if ( mDataProvider->capabilities() & QgsVectorDataProvider::CreateLabeling )
1741 {
1742 std::unique_ptr< QgsAbstractVectorLayerLabeling > defaultLabeling( mDataProvider->createLabeling() );
1743 if ( defaultLabeling )
1744 {
1745 setLabeling( defaultLabeling.release() );
1746 setLabelsEnabled( true );
1747 }
1748 }
1749
1750 styleChangedSignalBlocker.release();
1752 }
1753}
1754
1755QString QgsVectorLayer::loadDefaultStyle( bool &resultFlag )
1756{
1757 // first try to load a user-defined default style - this should always take precedence
1758 QString res = QgsMapLayer::loadDefaultStyle( resultFlag );
1759 if ( resultFlag )
1760 return res;
1761
1762 if ( isSpatial() && mDataProvider->capabilities() & QgsVectorDataProvider::CreateRenderer )
1763 {
1764 // otherwise try to create a renderer directly from the data provider
1765 std::unique_ptr< QgsFeatureRenderer > defaultRenderer( mDataProvider->createRenderer() );
1766 if ( defaultRenderer )
1767 {
1768 resultFlag = true;
1769 setRenderer( defaultRenderer.release() );
1770 return QString();
1771 }
1772 }
1773
1774 return QString();
1775}
1776
1777bool QgsVectorLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1778{
1779 mProviderKey = provider;
1780 delete mDataProvider;
1781
1782 // For Postgres provider primary key unicity is tested at construction time,
1783 // so it has to be set before initializing the provider,
1784 // this manipulation is necessary to preserve default behavior when
1785 // "trust layer metadata" project level option is set and checkPrimaryKeyUnicity
1786 // was not explicitly passed in the uri
1787 if ( provider.compare( QLatin1String( "postgres" ) ) == 0 )
1788 {
1789 const QString checkUnicityKey { QStringLiteral( "checkPrimaryKeyUnicity" ) };
1791 if ( ! uri.hasParam( checkUnicityKey ) )
1792 {
1793 uri.setParam( checkUnicityKey, mReadExtentFromXml ? "0" : "1" );
1794 mDataSource = uri.uri( false );
1795 }
1796 }
1797
1798 std::unique_ptr< QgsScopedRuntimeProfile > profile;
1799 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
1800 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), QStringLiteral( "projectload" ) );
1801
1802 mDataProvider = qobject_cast<QgsVectorDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, mDataSource, options, flags ) );
1803 if ( !mDataProvider )
1804 {
1805 setValid( false );
1806 QgsDebugMsgLevel( QStringLiteral( "Unable to get data provider" ), 2 );
1807 return false;
1808 }
1809
1810 mDataProvider->setParent( this );
1811 connect( mDataProvider, &QgsVectorDataProvider::raiseError, this, &QgsVectorLayer::raiseError );
1812
1813 QgsDebugMsgLevel( QStringLiteral( "Instantiated the data provider plugin" ), 2 );
1814
1815 setValid( mDataProvider->isValid() );
1816 if ( !isValid() )
1817 {
1818 QgsDebugMsgLevel( QStringLiteral( "Invalid provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
1819 return false;
1820 }
1821
1822 if ( profile )
1823 profile->switchTask( tr( "Read layer metadata" ) );
1825 {
1826 // we combine the provider metadata with the layer's existing metadata, so as not to reset any user customizations to the metadata
1827 // back to the default if a layer's data source is changed
1828 QgsLayerMetadata newMetadata = mDataProvider->layerMetadata();
1829 // this overwrites the provider metadata with any properties which are non-empty from the existing layer metadata
1830 newMetadata.combine( &mMetadata );
1831
1832 setMetadata( newMetadata );
1833 QgsDebugMsgLevel( QStringLiteral( "Set Data provider QgsLayerMetadata identifier[%1]" ).arg( metadata().identifier() ), 4 );
1834 }
1835
1836 // TODO: Check if the provider has the capability to send fullExtentCalculated
1837 connect( mDataProvider, &QgsVectorDataProvider::fullExtentCalculated, this, [ = ] { updateExtents(); } );
1838
1839 // get and store the feature type
1840 mWkbType = mDataProvider->wkbType();
1841
1842 // before we update the layer fields from the provider, we first copy any default set alias and
1843 // editor widget config from the data provider fields, if present
1844 const QgsFields providerFields = mDataProvider->fields();
1845 for ( const QgsField &field : providerFields )
1846 {
1847 // we only copy defaults from the provider if we aren't overriding any configuration made in the layer
1848 if ( !field.editorWidgetSetup().isNull() && mFieldWidgetSetups.value( field.name() ).isNull() )
1849 {
1850 mFieldWidgetSetups[ field.name() ] = field.editorWidgetSetup();
1851 }
1852 if ( !field.alias().isEmpty() && mAttributeAliasMap.value( field.name() ).isEmpty() )
1853 {
1854 mAttributeAliasMap[ field.name() ] = field.alias();
1855 }
1856 }
1857
1858 if ( profile )
1859 profile->switchTask( tr( "Read layer fields" ) );
1860 updateFields();
1861
1862 if ( mProviderKey == QLatin1String( "postgres" ) )
1863 {
1864 // update datasource from data provider computed one
1865 mDataSource = mDataProvider->dataSourceUri( false );
1866
1867 QgsDebugMsgLevel( QStringLiteral( "Beautifying layer name %1" ).arg( name() ), 3 );
1868
1869 // adjust the display name for postgres layers
1870 const QRegularExpression reg( R"lit("[^"]+"\."([^"] + )"( \‍([^)]+\))?)lit" );
1871 const QRegularExpressionMatch match = reg.match( name() );
1872 if ( match.hasMatch() )
1873 {
1874 QStringList stuff = match.capturedTexts();
1875 QString lName = stuff[1];
1876
1877 const QMap<QString, QgsMapLayer *> &layers = QgsProject::instance()->mapLayers();
1878
1879 QMap<QString, QgsMapLayer *>::const_iterator it;
1880 for ( it = layers.constBegin(); it != layers.constEnd() && ( *it )->name() != lName; ++it )
1881 ;
1882
1883 if ( it != layers.constEnd() && stuff.size() > 2 )
1884 {
1885 lName += '.' + stuff[2].mid( 2, stuff[2].length() - 3 );
1886 }
1887
1888 if ( !lName.isEmpty() )
1889 setName( lName );
1890 }
1891 QgsDebugMsgLevel( QStringLiteral( "Beautified layer name %1" ).arg( name() ), 3 );
1892 }
1893 else if ( mProviderKey == QLatin1String( "osm" ) )
1894 {
1895 // make sure that the "observer" has been removed from URI to avoid crashes
1896 mDataSource = mDataProvider->dataSourceUri();
1897 }
1898 else if ( provider == QLatin1String( "ogr" ) )
1899 {
1900 // make sure that the /vsigzip or /vsizip is added to uri, if applicable
1901 mDataSource = mDataProvider->dataSourceUri();
1902 if ( mDataSource.right( 10 ) == QLatin1String( "|layerid=0" ) )
1903 mDataSource.chop( 10 );
1904 }
1905 else if ( provider == QLatin1String( "memory" ) )
1906 {
1907 // required so that source differs between memory layers
1908 mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
1909 }
1910 else if ( provider == QLatin1String( "hana" ) )
1911 {
1912 // update datasource from data provider computed one
1913 mDataSource = mDataProvider->dataSourceUri( false );
1914 }
1915
1916 connect( mDataProvider, &QgsVectorDataProvider::dataChanged, this, &QgsVectorLayer::emitDataChanged );
1918
1919 return true;
1920} // QgsVectorLayer:: setDataProvider
1921
1922
1923
1924
1925/* virtual */
1926bool QgsVectorLayer::writeXml( QDomNode &layer_node,
1927 QDomDocument &document,
1928 const QgsReadWriteContext &context ) const
1929{
1930 // first get the layer element so that we can append the type attribute
1931
1932 QDomElement mapLayerNode = layer_node.toElement();
1933
1934 if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) )
1935 {
1936 QgsDebugMsgLevel( QStringLiteral( "can't find <maplayer>" ), 2 );
1937 return false;
1938 }
1939
1940 mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( QgsMapLayerType::VectorLayer ) );
1941
1942 // set the geometry type
1943 mapLayerNode.setAttribute( QStringLiteral( "geometry" ), QgsWkbTypes::geometryDisplayString( geometryType() ) );
1944 mapLayerNode.setAttribute( QStringLiteral( "wkbType" ), qgsEnumValueToKey( wkbType() ) );
1945
1946 // add provider node
1947 if ( mDataProvider )
1948 {
1949 QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
1950 provider.setAttribute( QStringLiteral( "encoding" ), mDataProvider->encoding() );
1951 QDomText providerText = document.createTextNode( providerType() );
1952 provider.appendChild( providerText );
1953 layer_node.appendChild( provider );
1954 }
1955
1956 //save joins
1957 mJoinBuffer->writeXml( layer_node, document );
1958
1959 // dependencies
1960 QDomElement dependenciesElement = document.createElement( QStringLiteral( "layerDependencies" ) );
1961 const auto constDependencies = dependencies();
1962 for ( const QgsMapLayerDependency &dep : constDependencies )
1963 {
1965 continue;
1966 QDomElement depElem = document.createElement( QStringLiteral( "layer" ) );
1967 depElem.setAttribute( QStringLiteral( "id" ), dep.layerId() );
1968 dependenciesElement.appendChild( depElem );
1969 }
1970 layer_node.appendChild( dependenciesElement );
1971
1972 // change dependencies
1973 QDomElement dataDependenciesElement = document.createElement( QStringLiteral( "dataDependencies" ) );
1974 for ( const QgsMapLayerDependency &dep : constDependencies )
1975 {
1976 if ( dep.type() != QgsMapLayerDependency::DataDependency )
1977 continue;
1978 QDomElement depElem = document.createElement( QStringLiteral( "layer" ) );
1979 depElem.setAttribute( QStringLiteral( "id" ), dep.layerId() );
1980 dataDependenciesElement.appendChild( depElem );
1981 }
1982 layer_node.appendChild( dataDependenciesElement );
1983
1984 // save expression fields
1985 mExpressionFieldBuffer->writeXml( layer_node, document );
1986
1987 writeStyleManager( layer_node, document );
1988
1989 // auxiliary layer
1990 QDomElement asElem = document.createElement( QStringLiteral( "auxiliaryLayer" ) );
1991 if ( mAuxiliaryLayer )
1992 {
1993 const QString pkField = mAuxiliaryLayer->joinInfo().targetFieldName();
1994 asElem.setAttribute( QStringLiteral( "key" ), pkField );
1995 }
1996 layer_node.appendChild( asElem );
1997
1998 // save QGIS Server properties (WMS Dimension, metadata URLS...)
1999 mServerProperties->writeXml( layer_node, document );
2000
2001 // renderer specific settings
2002 QString errorMsg;
2003 return writeSymbology( layer_node, document, errorMsg, context );
2004}
2005
2006QString QgsVectorLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
2007{
2008 QString src( source );
2009
2010 // TODO: what about postgres, mysql and others, they should not go through writePath()
2011 if ( providerType() == QLatin1String( "spatialite" ) )
2012 {
2013 QgsDataSourceUri uri( src );
2014 QString database = context.pathResolver().writePath( uri.database() );
2015 uri.setConnection( uri.host(), uri.port(), database, uri.username(), uri.password() );
2016 src = uri.uri();
2017 }
2018 else if ( providerType() == QLatin1String( "ogr" ) )
2019 {
2020 QStringList theURIParts = src.split( '|' );
2021 theURIParts[0] = context.pathResolver().writePath( theURIParts[0] );
2022 src = theURIParts.join( QLatin1Char( '|' ) );
2023 }
2024 else if ( providerType() == QLatin1String( "gpx" ) )
2025 {
2026 QStringList theURIParts = src.split( '?' );
2027 theURIParts[0] = context.pathResolver().writePath( theURIParts[0] );
2028 src = theURIParts.join( QLatin1Char( '?' ) );
2029 }
2030 else if ( providerType() == QLatin1String( "delimitedtext" ) )
2031 {
2032 QUrl urlSource = QUrl::fromEncoded( src.toLatin1() );
2033 QUrl urlDest = QUrl::fromLocalFile( context.pathResolver().writePath( urlSource.toLocalFile() ) );
2034 urlDest.setQuery( urlSource.query() );
2035 src = QString::fromLatin1( urlDest.toEncoded() );
2036 }
2037 else if ( providerType() == QLatin1String( "memory" ) )
2038 {
2039 // Refetch the source from the provider, because adding fields actually changes the source for this provider.
2040 src = dataProvider()->dataSourceUri();
2041 }
2042 else if ( providerType() == QLatin1String( "virtual" ) )
2043 {
2044 QUrl urlSource = QUrl::fromEncoded( src.toLatin1() );
2045 QStringList theURIParts;
2046
2047 QUrlQuery query = QUrlQuery( urlSource.query() );
2048 QList<QPair<QString, QString> > queryItems = query.queryItems();
2049
2050 for ( int i = 0; i < queryItems.size(); i++ )
2051 {
2052 QString key = queryItems.at( i ).first;
2053 QString value = queryItems.at( i ).second;
2054 if ( key == QLatin1String( "layer" ) )
2055 {
2056 // syntax: provider:url_encoded_source_URI(:name(:encoding)?)?
2057 theURIParts = value.split( ':' );
2058 theURIParts[1] = QUrl::fromPercentEncoding( theURIParts[1].toUtf8() );
2059
2060 if ( theURIParts[0] == QLatin1String( "delimitedtext" ) )
2061 {
2062 QUrl urlSource = QUrl( theURIParts[1] );
2063 QUrl urlDest = QUrl::fromLocalFile( context.pathResolver().writePath( urlSource.toLocalFile() ) );
2064 urlDest.setQuery( urlSource.query() );
2065 theURIParts[1] = QUrl::toPercentEncoding( urlDest.toString(), QByteArray( "" ), QByteArray( ":" ) );
2066 }
2067 else
2068 {
2069 theURIParts[1] = context.pathResolver().writePath( theURIParts[1] );
2070 theURIParts[1] = QUrl::toPercentEncoding( theURIParts[1] );
2071 }
2072
2073 queryItems[i].second = theURIParts.join( QLatin1Char( ':' ) ) ;
2074 }
2075 }
2076
2077 query.setQueryItems( queryItems );
2078
2079 QUrl urlDest = QUrl( urlSource );
2080 urlDest.setQuery( query.query() );
2081 src = QString::fromLatin1( urlDest.toEncoded() );
2082 }
2083 else
2084 {
2085 src = context.pathResolver().writePath( src );
2086 }
2087
2088 return src;
2089}
2090
2091QString QgsVectorLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
2092{
2093 QString src( source );
2094
2095 if ( provider == QLatin1String( "spatialite" ) )
2096 {
2097 QgsDataSourceUri uri( src );
2098 uri.setDatabase( context.pathResolver().readPath( uri.database() ) );
2099 src = uri.uri();
2100 }
2101 else if ( provider == QLatin1String( "ogr" ) )
2102 {
2103 QStringList theURIParts = src.split( '|' );
2104 theURIParts[0] = context.pathResolver().readPath( theURIParts[0] );
2105 src = theURIParts.join( QLatin1Char( '|' ) );
2106 }
2107 else if ( provider == QLatin1String( "gpx" ) )
2108 {
2109 QStringList theURIParts = src.split( '?' );
2110 theURIParts[0] = context.pathResolver().readPath( theURIParts[0] );
2111 src = theURIParts.join( QLatin1Char( '?' ) );
2112 }
2113 else if ( provider == QLatin1String( "delimitedtext" ) )
2114 {
2115 QUrl urlSource = QUrl::fromEncoded( src.toLatin1() );
2116
2117 if ( !src.startsWith( QLatin1String( "file:" ) ) )
2118 {
2119 QUrl file = QUrl::fromLocalFile( src.left( src.indexOf( '?' ) ) );
2120 urlSource.setScheme( QStringLiteral( "file" ) );
2121 urlSource.setPath( file.path() );
2122 }
2123
2124 QUrl urlDest = QUrl::fromLocalFile( context.pathResolver().readPath( urlSource.toLocalFile() ) );
2125 urlDest.setQuery( urlSource.query() );
2126 src = QString::fromLatin1( urlDest.toEncoded() );
2127 }
2128 else if ( provider == QLatin1String( "virtual" ) )
2129 {
2130 QUrl urlSource = QUrl::fromEncoded( src.toLatin1() );
2131 QStringList theURIParts;
2132
2133 QUrlQuery query = QUrlQuery( urlSource.query() );
2134 QList<QPair<QString, QString> > queryItems = query.queryItems();
2135
2136 for ( int i = 0; i < queryItems.size(); i++ )
2137 {
2138 QString key = queryItems.at( i ).first;
2139 QString value = queryItems.at( i ).second;
2140 if ( key == QLatin1String( "layer" ) )
2141 {
2142 // syntax: provider:url_encoded_source_URI(:name(:encoding)?)?
2143 theURIParts = value.split( ':' );
2144 theURIParts[1] = QUrl::fromPercentEncoding( theURIParts[1].toUtf8() );
2145
2146 if ( theURIParts[0] == QLatin1String( "delimitedtext" ) )
2147 {
2148 QUrl urlSource = QUrl( theURIParts[1] );
2149
2150 if ( !theURIParts[1].startsWith( QLatin1String( "file:" ) ) )
2151 {
2152 QUrl file = QUrl::fromLocalFile( theURIParts[1].left( theURIParts[1].indexOf( '?' ) ) );
2153 urlSource.setScheme( QStringLiteral( "file" ) );
2154 urlSource.setPath( file.path() );
2155 }
2156
2157 QUrl urlDest = QUrl::fromLocalFile( context.pathResolver().readPath( urlSource.toLocalFile() ) );
2158 urlDest.setQuery( urlSource.query() );
2159
2160 theURIParts[1] = urlDest.toString();
2161 }
2162 else
2163 {
2164 theURIParts[1] = context.pathResolver().readPath( theURIParts[1] );
2165 }
2166
2167 theURIParts[1] = QUrl::toPercentEncoding( theURIParts[1] );
2168 queryItems[i].second = theURIParts.join( QLatin1Char( ':' ) ) ;
2169 }
2170 }
2171
2172 query.setQueryItems( queryItems );
2173
2174 QUrl urlDest = QUrl( urlSource );
2175 urlDest.setQuery( query.query() );
2176 src = QString::fromLatin1( urlDest.toEncoded() );
2177 }
2178 else
2179 {
2180 src = context.pathResolver().readPath( src );
2181 }
2182
2183 return src;
2184}
2185
2186
2187
2189{
2191 mJoinBuffer->resolveReferences( project );
2192}
2193
2194
2195bool QgsVectorLayer::readSymbology( const QDomNode &layerNode, QString &errorMessage,
2196 QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
2197{
2198 if ( categories.testFlag( Fields ) )
2199 {
2200 if ( !mExpressionFieldBuffer )
2201 mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
2202 mExpressionFieldBuffer->readXml( layerNode );
2203
2204 updateFields();
2205 }
2206
2207 if ( categories.testFlag( Relations ) )
2208 {
2209 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Relations" ) );
2210
2211 const QgsPathResolver resolver { QgsProject::instance()->pathResolver() };
2212
2213 // Restore referenced layers: relations where "this" is the child layer (the referencing part, that holds the FK)
2214 QDomNodeList referencedLayersNodeList = layerNode.toElement().elementsByTagName( QStringLiteral( "referencedLayers" ) );
2215 if ( referencedLayersNodeList.size() > 0 )
2216 {
2217 const QDomNodeList relationNodes { referencedLayersNodeList.at( 0 ).childNodes() };
2218 for ( int i = 0; i < relationNodes.length(); ++i )
2219 {
2220 const QDomElement relationElement = relationNodes.at( i ).toElement();
2221
2222 mWeakRelations.push_back( QgsWeakRelation::readXml( this, QgsWeakRelation::Referencing, relationElement, resolver ) );
2223 }
2224 }
2225
2226 // Restore referencing layers: relations where "this" is the parent layer (the referenced part where the FK points to)
2227 QDomNodeList referencingLayersNodeList = layerNode.toElement().elementsByTagName( QStringLiteral( "referencingLayers" ) );
2228 if ( referencingLayersNodeList.size() > 0 )
2229 {
2230 const QDomNodeList relationNodes { referencingLayersNodeList.at( 0 ).childNodes() };
2231 for ( int i = 0; i < relationNodes.length(); ++i )
2232 {
2233 const QDomElement relationElement = relationNodes.at( i ).toElement();
2234 mWeakRelations.push_back( QgsWeakRelation::readXml( this, QgsWeakRelation::Referenced, relationElement, resolver ) );
2235 }
2236 }
2237 }
2238
2239 QDomElement layerElement = layerNode.toElement();
2240
2241 readCommonStyle( layerElement, context, categories );
2242
2243 readStyle( layerNode, errorMessage, context, categories );
2244
2245 if ( categories.testFlag( MapTips ) )
2246 mMapTipTemplate = layerNode.namedItem( QStringLiteral( "mapTip" ) ).toElement().text();
2247
2248 if ( categories.testFlag( LayerConfiguration ) )
2249 mDisplayExpression = layerNode.namedItem( QStringLiteral( "previewExpression" ) ).toElement().text();
2250
2251 // Try to migrate pre QGIS 3.0 display field property
2252 QString displayField = layerNode.namedItem( QStringLiteral( "displayfield" ) ).toElement().text();
2253 if ( mFields.lookupField( displayField ) < 0 )
2254 {
2255 // if it's not a field, it's a maptip
2256 if ( mMapTipTemplate.isEmpty() && categories.testFlag( MapTips ) )
2257 mMapTipTemplate = displayField;
2258 }
2259 else
2260 {
2261 if ( mDisplayExpression.isEmpty() && categories.testFlag( LayerConfiguration ) )
2262 mDisplayExpression = QgsExpression::quotedColumnRef( displayField );
2263 }
2264
2265 // process the attribute actions
2266 if ( categories.testFlag( Actions ) )
2267 mActions->readXml( layerNode );
2268
2269 if ( categories.testFlag( Fields ) )
2270 {
2271 // IMPORTANT - we don't clear mAttributeAliasMap here, as it may contain aliases which are coming direct
2272 // from the data provider. Instead we leave any existing aliases and only overwrite them if the style
2273 // has a specific value for that field's alias
2274 QDomNode aliasesNode = layerNode.namedItem( QStringLiteral( "aliases" ) );
2275 if ( !aliasesNode.isNull() )
2276 {
2277 QDomElement aliasElem;
2278
2279 QDomNodeList aliasNodeList = aliasesNode.toElement().elementsByTagName( QStringLiteral( "alias" ) );
2280 for ( int i = 0; i < aliasNodeList.size(); ++i )
2281 {
2282 aliasElem = aliasNodeList.at( i ).toElement();
2283
2284 QString field;
2285 if ( aliasElem.hasAttribute( QStringLiteral( "field" ) ) )
2286 {
2287 field = aliasElem.attribute( QStringLiteral( "field" ) );
2288 }
2289 else
2290 {
2291 int index = aliasElem.attribute( QStringLiteral( "index" ) ).toInt();
2292
2293 if ( index >= 0 && index < fields().count() )
2294 field = fields().at( index ).name();
2295 }
2296
2297 QString alias;
2298
2299 if ( !aliasElem.attribute( QStringLiteral( "name" ) ).isEmpty() )
2300 {
2301 //if it has alias
2302 alias = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ), aliasElem.attribute( QStringLiteral( "name" ) ) );
2303 QgsDebugMsgLevel( "context" + QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ) + " source " + aliasElem.attribute( QStringLiteral( "name" ) ), 3 );
2304 }
2305 else
2306 {
2307 //if it has no alias, it should be the fields translation
2308 alias = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ), field );
2309 QgsDebugMsgLevel( "context" + QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ) + " source " + field, 3 );
2310 //if it gets the exact field value, there has been no translation (or not even translation loaded) - so no alias should be generated;
2311 if ( alias == aliasElem.attribute( QStringLiteral( "field" ) ) )
2312 alias.clear();
2313 }
2314
2315 QgsDebugMsgLevel( "field " + field + " origalias " + aliasElem.attribute( QStringLiteral( "name" ) ) + " trans " + alias, 3 );
2316 mAttributeAliasMap.insert( field, alias );
2317 }
2318 }
2319
2320 // default expressions
2321 mDefaultExpressionMap.clear();
2322 QDomNode defaultsNode = layerNode.namedItem( QStringLiteral( "defaults" ) );
2323 if ( !defaultsNode.isNull() )
2324 {
2325 QDomNodeList defaultNodeList = defaultsNode.toElement().elementsByTagName( QStringLiteral( "default" ) );
2326 for ( int i = 0; i < defaultNodeList.size(); ++i )
2327 {
2328 QDomElement defaultElem = defaultNodeList.at( i ).toElement();
2329
2330 QString field = defaultElem.attribute( QStringLiteral( "field" ), QString() );
2331 QString expression = defaultElem.attribute( QStringLiteral( "expression" ), QString() );
2332 bool applyOnUpdate = defaultElem.attribute( QStringLiteral( "applyOnUpdate" ), QStringLiteral( "0" ) ) == QLatin1String( "1" );
2333 if ( field.isEmpty() || expression.isEmpty() )
2334 continue;
2335
2336 mDefaultExpressionMap.insert( field, QgsDefaultValue( expression, applyOnUpdate ) );
2337 }
2338 }
2339
2340 // constraints
2341 mFieldConstraints.clear();
2342 mFieldConstraintStrength.clear();
2343 QDomNode constraintsNode = layerNode.namedItem( QStringLiteral( "constraints" ) );
2344 if ( !constraintsNode.isNull() )
2345 {
2346 QDomNodeList constraintNodeList = constraintsNode.toElement().elementsByTagName( QStringLiteral( "constraint" ) );
2347 for ( int i = 0; i < constraintNodeList.size(); ++i )
2348 {
2349 QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2350
2351 QString field = constraintElem.attribute( QStringLiteral( "field" ), QString() );
2352 int constraints = constraintElem.attribute( QStringLiteral( "constraints" ), QStringLiteral( "0" ) ).toInt();
2353 if ( field.isEmpty() || constraints == 0 )
2354 continue;
2355
2356 mFieldConstraints.insert( field, static_cast< QgsFieldConstraints::Constraints >( constraints ) );
2357
2358 int uniqueStrength = constraintElem.attribute( QStringLiteral( "unique_strength" ), QStringLiteral( "1" ) ).toInt();
2359 int notNullStrength = constraintElem.attribute( QStringLiteral( "notnull_strength" ), QStringLiteral( "1" ) ).toInt();
2360 int expStrength = constraintElem.attribute( QStringLiteral( "exp_strength" ), QStringLiteral( "1" ) ).toInt();
2361
2362 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintUnique ), static_cast< QgsFieldConstraints::ConstraintStrength >( uniqueStrength ) );
2363 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintNotNull ), static_cast< QgsFieldConstraints::ConstraintStrength >( notNullStrength ) );
2364 mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintExpression ), static_cast< QgsFieldConstraints::ConstraintStrength >( expStrength ) );
2365 }
2366 }
2367 mFieldConstraintExpressions.clear();
2368 QDomNode constraintExpressionsNode = layerNode.namedItem( QStringLiteral( "constraintExpressions" ) );
2369 if ( !constraintExpressionsNode.isNull() )
2370 {
2371 QDomNodeList constraintNodeList = constraintExpressionsNode.toElement().elementsByTagName( QStringLiteral( "constraint" ) );
2372 for ( int i = 0; i < constraintNodeList.size(); ++i )
2373 {
2374 QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2375
2376 QString field = constraintElem.attribute( QStringLiteral( "field" ), QString() );
2377 QString exp = constraintElem.attribute( QStringLiteral( "exp" ), QString() );
2378 QString desc = constraintElem.attribute( QStringLiteral( "desc" ), QString() );
2379 if ( field.isEmpty() || exp.isEmpty() )
2380 continue;
2381
2382 mFieldConstraintExpressions.insert( field, qMakePair( exp, desc ) );
2383 }
2384 }
2385
2386 updateFields();
2387 }
2388
2389 // load field configuration
2390 if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
2391 {
2392 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Forms" ) );
2393
2394 QDomElement widgetsElem = layerNode.namedItem( QStringLiteral( "fieldConfiguration" ) ).toElement();
2395 QDomNodeList fieldConfigurationElementList = widgetsElem.elementsByTagName( QStringLiteral( "field" ) );
2396 for ( int i = 0; i < fieldConfigurationElementList.size(); ++i )
2397 {
2398 const QDomElement fieldConfigElement = fieldConfigurationElementList.at( i ).toElement();
2399 const QDomElement fieldWidgetElement = fieldConfigElement.elementsByTagName( QStringLiteral( "editWidget" ) ).at( 0 ).toElement();
2400
2401 QString fieldName = fieldConfigElement.attribute( QStringLiteral( "name" ) );
2402
2403 if ( categories.testFlag( Fields ) )
2404 mFieldConfigurationFlags[fieldName] = qgsFlagKeysToValue( fieldConfigElement.attribute( QStringLiteral( "configurationFlags" ) ), QgsField::ConfigurationFlag::None );
2405
2406 // Load editor widget configuration
2407 if ( categories.testFlag( Forms ) )
2408 {
2409 const QString widgetType = fieldWidgetElement.attribute( QStringLiteral( "type" ) );
2410 const QDomElement cfgElem = fieldConfigElement.elementsByTagName( QStringLiteral( "config" ) ).at( 0 ).toElement();
2411 const QDomElement optionsElem = cfgElem.childNodes().at( 0 ).toElement();
2412 QVariantMap optionsMap = QgsXmlUtils::readVariant( optionsElem ).toMap();
2413 if ( widgetType == QLatin1String( "ValueRelation" ) )
2414 {
2415 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() );
2416 }
2417 QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( widgetType, optionsMap );
2418 mFieldWidgetSetups[fieldName] = setup;
2419 }
2420 }
2421 }
2422
2423 // Legacy reading for QGIS 3.14 and older projects
2424 // Attributes excluded from WMS and WFS
2425 if ( categories.testFlag( Fields ) )
2426 {
2427 const QList<QPair<QString, QgsField::ConfigurationFlag>> legacyConfig
2428 {
2429 qMakePair( QStringLiteral( "excludeAttributesWMS" ), QgsField::ConfigurationFlag::HideFromWms ),
2430 qMakePair( QStringLiteral( "excludeAttributesWFS" ), QgsField::ConfigurationFlag::HideFromWfs )
2431 };
2432 for ( const auto &config : legacyConfig )
2433 {
2434 QDomNode excludeNode = layerNode.namedItem( config.first );
2435 if ( !excludeNode.isNull() )
2436 {
2437 QDomNodeList attributeNodeList = excludeNode.toElement().elementsByTagName( QStringLiteral( "attribute" ) );
2438 for ( int i = 0; i < attributeNodeList.size(); ++i )
2439 {
2440 QString fieldName = attributeNodeList.at( i ).toElement().text();
2441 if ( !mFieldConfigurationFlags.contains( fieldName ) )
2442 mFieldConfigurationFlags[fieldName] = config.second;
2443 else
2444 mFieldConfigurationFlags[fieldName].setFlag( config.second, true );
2445 }
2446 }
2447 }
2448 }
2449
2450 if ( categories.testFlag( GeometryOptions ) )
2451 mGeometryOptions->readXml( layerNode.namedItem( QStringLiteral( "geometryOptions" ) ) );
2452
2453 if ( categories.testFlag( Forms ) )
2454 mEditFormConfig.readXml( layerNode, context );
2455
2456 if ( categories.testFlag( AttributeTable ) )
2457 {
2458 mAttributeTableConfig.readXml( layerNode );
2459 mConditionalStyles->readXml( layerNode, context );
2460 mStoredExpressionManager->readXml( layerNode );
2461 }
2462
2463 if ( categories.testFlag( CustomProperties ) )
2464 readCustomProperties( layerNode, QStringLiteral( "variable" ) );
2465
2466 QDomElement mapLayerNode = layerNode.toElement();
2467 if ( categories.testFlag( LayerConfiguration )
2468 && mapLayerNode.attribute( QStringLiteral( "readOnly" ), QStringLiteral( "0" ) ).toInt() == 1 )
2469 mReadOnly = true;
2470
2471 updateFields();
2472
2473 if ( categories.testFlag( Legend ) )
2474 {
2475 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Legend" ) );
2476
2477 const QDomElement legendElem = layerNode.firstChildElement( QStringLiteral( "legend" ) );
2478 if ( !legendElem.isNull() )
2479 {
2480 std::unique_ptr< QgsMapLayerLegend > legend( QgsMapLayerLegend::defaultVectorLegend( this ) );
2481 legend->readXml( legendElem, context );
2482 setLegend( legend.release() );
2483 mSetLegendFromStyle = true;
2484 }
2485 }
2486
2487 return true;
2488}
2489
2490bool QgsVectorLayer::readStyle( const QDomNode &node, QString &errorMessage,
2491 QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
2492{
2493 bool result = true;
2494 emit readCustomSymbology( node.toElement(), errorMessage );
2495
2496 // we must try to restore a renderer if our geometry type is unknown
2497 // as this allows the renderer to be correctly restored even for layers
2498 // with broken sources
2499 if ( isSpatial() || mWkbType == QgsWkbTypes::Unknown )
2500 {
2501 // defer style changed signal until we've set the renderer, labeling, everything.
2502 // we don't want multiple signals!
2503 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
2504
2505 // try renderer v2 first
2506 if ( categories.testFlag( Symbology ) )
2507 {
2508 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Symbology" ) );
2509
2510 QDomElement rendererElement = node.firstChildElement( RENDERER_TAG_NAME );
2511 if ( !rendererElement.isNull() )
2512 {
2513 QgsFeatureRenderer *r = QgsFeatureRenderer::load( rendererElement, context );
2514 if ( r )
2515 {
2516 setRenderer( r );
2517 }
2518 else
2519 {
2520 result = false;
2521 }
2522 }
2523 // make sure layer has a renderer - if none exists, fallback to a default renderer
2524 if ( isSpatial() && !renderer() )
2525 {
2527 }
2528 }
2529
2530 // read labeling definition
2531 if ( categories.testFlag( Labeling ) )
2532 {
2533 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Labeling" ) );
2534
2535 QDomElement labelingElement = node.firstChildElement( QStringLiteral( "labeling" ) );
2537 if ( labelingElement.isNull() ||
2538 ( labelingElement.attribute( QStringLiteral( "type" ) ) == QLatin1String( "simple" ) && labelingElement.firstChildElement( QStringLiteral( "settings" ) ).isNull() ) )
2539 {
2540 // make sure we have custom properties for labeling for 2.x projects
2541 // (custom properties should be already loaded when reading the whole layer from XML,
2542 // but when reading style, custom properties are not read)
2543 readCustomProperties( node, QStringLiteral( "labeling" ) );
2544
2545 // support for pre-QGIS 3 labeling configurations written in custom properties
2546 labeling = readLabelingFromCustomProperties();
2547 }
2548 else
2549 {
2550 labeling = QgsAbstractVectorLayerLabeling::create( labelingElement, context );
2551 }
2553
2554 if ( node.toElement().hasAttribute( QStringLiteral( "labelsEnabled" ) ) )
2555 mLabelsEnabled = node.toElement().attribute( QStringLiteral( "labelsEnabled" ) ).toInt();
2556 else
2557 mLabelsEnabled = true;
2558 }
2559
2560 if ( categories.testFlag( Symbology ) )
2561 {
2562 // get and set the blend mode if it exists
2563 QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
2564 if ( !blendModeNode.isNull() )
2565 {
2566 QDomElement e = blendModeNode.toElement();
2567 setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
2568 }
2569
2570 // get and set the feature blend mode if it exists
2571 QDomNode featureBlendModeNode = node.namedItem( QStringLiteral( "featureBlendMode" ) );
2572 if ( !featureBlendModeNode.isNull() )
2573 {
2574 QDomElement e = featureBlendModeNode.toElement();
2575 setFeatureBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
2576 }
2577 }
2578
2579 // get and set the layer transparency and scale visibility if they exists
2580 if ( categories.testFlag( Rendering ) )
2581 {
2582 QDomNode layerTransparencyNode = node.namedItem( QStringLiteral( "layerTransparency" ) );
2583 if ( !layerTransparencyNode.isNull() )
2584 {
2585 QDomElement e = layerTransparencyNode.toElement();
2586 setOpacity( 1.0 - e.text().toInt() / 100.0 );
2587 }
2588 QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
2589 if ( !layerOpacityNode.isNull() )
2590 {
2591 QDomElement e = layerOpacityNode.toElement();
2592 setOpacity( e.text().toDouble() );
2593 }
2594
2595 const bool hasScaleBasedVisibiliy { node.attributes().namedItem( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).nodeValue() == '1' };
2596 setScaleBasedVisibility( hasScaleBasedVisibiliy );
2597 bool ok;
2598 const double maxScale { node.attributes().namedItem( QStringLiteral( "maxScale" ) ).nodeValue().toDouble( &ok ) };
2599 if ( ok )
2600 {
2601 setMaximumScale( maxScale );
2602 }
2603 const double minScale { node.attributes().namedItem( QStringLiteral( "minScale" ) ).nodeValue().toDouble( &ok ) };
2604 if ( ok )
2605 {
2606 setMinimumScale( minScale );
2607 }
2608
2609 QDomElement e = node.toElement();
2610
2611 // get the simplification drawing settings
2612 mSimplifyMethod.setSimplifyHints( static_cast< QgsVectorSimplifyMethod::SimplifyHints >( e.attribute( QStringLiteral( "simplifyDrawingHints" ), QStringLiteral( "1" ) ).toInt() ) );
2613 mSimplifyMethod.setSimplifyAlgorithm( static_cast< QgsVectorSimplifyMethod::SimplifyAlgorithm >( e.attribute( QStringLiteral( "simplifyAlgorithm" ), QStringLiteral( "0" ) ).toInt() ) );
2614 mSimplifyMethod.setThreshold( e.attribute( QStringLiteral( "simplifyDrawingTol" ), QStringLiteral( "1" ) ).toFloat() );
2615 mSimplifyMethod.setForceLocalOptimization( e.attribute( QStringLiteral( "simplifyLocal" ), QStringLiteral( "1" ) ).toInt() );
2616 mSimplifyMethod.setMaximumScale( e.attribute( QStringLiteral( "simplifyMaxScale" ), QStringLiteral( "1" ) ).toFloat() );
2617
2618 if ( mRenderer )
2619 mRenderer->setReferenceScale( e.attribute( QStringLiteral( "symbologyReferenceScale" ), QStringLiteral( "-1" ) ).toDouble() );
2620 }
2621
2622 //diagram renderer and diagram layer settings
2623 if ( categories.testFlag( Diagrams ) )
2624 {
2625 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Diagrams" ) );
2626
2627 delete mDiagramRenderer;
2628 mDiagramRenderer = nullptr;
2629 QDomElement singleCatDiagramElem = node.firstChildElement( QStringLiteral( "SingleCategoryDiagramRenderer" ) );
2630 if ( !singleCatDiagramElem.isNull() )
2631 {
2632 mDiagramRenderer = new QgsSingleCategoryDiagramRenderer();
2633 mDiagramRenderer->readXml( singleCatDiagramElem, context );
2634 }
2635 QDomElement linearDiagramElem = node.firstChildElement( QStringLiteral( "LinearlyInterpolatedDiagramRenderer" ) );
2636 if ( !linearDiagramElem.isNull() )
2637 {
2638 if ( linearDiagramElem.hasAttribute( QStringLiteral( "classificationAttribute" ) ) )
2639 {
2640 // fix project from before QGIS 3.0
2641 int idx = linearDiagramElem.attribute( QStringLiteral( "classificationAttribute" ) ).toInt();
2642 if ( idx >= 0 && idx < mFields.count() )
2643 linearDiagramElem.setAttribute( QStringLiteral( "classificationField" ), mFields.at( idx ).name() );
2644 }
2645
2646 mDiagramRenderer = new QgsLinearlyInterpolatedDiagramRenderer();
2647 mDiagramRenderer->readXml( linearDiagramElem, context );
2648 }
2649
2650 if ( mDiagramRenderer )
2651 {
2652 QDomElement diagramSettingsElem = node.firstChildElement( QStringLiteral( "DiagramLayerSettings" ) );
2653 if ( !diagramSettingsElem.isNull() )
2654 {
2655 bool oldXPos = diagramSettingsElem.hasAttribute( QStringLiteral( "xPosColumn" ) );
2656 bool oldYPos = diagramSettingsElem.hasAttribute( QStringLiteral( "yPosColumn" ) );
2657 bool oldShow = diagramSettingsElem.hasAttribute( QStringLiteral( "showColumn" ) );
2658 if ( oldXPos || oldYPos || oldShow )
2659 {
2660 // fix project from before QGIS 3.0
2662 if ( oldXPos )
2663 {
2664 int xPosColumn = diagramSettingsElem.attribute( QStringLiteral( "xPosColumn" ) ).toInt();
2665 if ( xPosColumn >= 0 && xPosColumn < mFields.count() )
2666 ddp.setProperty( QgsDiagramLayerSettings::PositionX, QgsProperty::fromField( mFields.at( xPosColumn ).name(), true ) );
2667 }
2668 if ( oldYPos )
2669 {
2670 int yPosColumn = diagramSettingsElem.attribute( QStringLiteral( "yPosColumn" ) ).toInt();
2671 if ( yPosColumn >= 0 && yPosColumn < mFields.count() )
2672 ddp.setProperty( QgsDiagramLayerSettings::PositionY, QgsProperty::fromField( mFields.at( yPosColumn ).name(), true ) );
2673 }
2674 if ( oldShow )
2675 {
2676 int showColumn = diagramSettingsElem.attribute( QStringLiteral( "showColumn" ) ).toInt();
2677 if ( showColumn >= 0 && showColumn < mFields.count() )
2678 ddp.setProperty( QgsDiagramLayerSettings::Show, QgsProperty::fromField( mFields.at( showColumn ).name(), true ) );
2679 }
2680 QDomElement propertiesElem = diagramSettingsElem.ownerDocument().createElement( QStringLiteral( "properties" ) );
2682 {
2683 { QgsDiagramLayerSettings::PositionX, QgsPropertyDefinition( "positionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double ) },
2684 { QgsDiagramLayerSettings::PositionY, QgsPropertyDefinition( "positionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double ) },
2685 { QgsDiagramLayerSettings::Show, QgsPropertyDefinition( "show", QObject::tr( "Show diagram" ), QgsPropertyDefinition::Boolean ) },
2686 };
2687 ddp.writeXml( propertiesElem, defs );
2688 diagramSettingsElem.appendChild( propertiesElem );
2689 }
2690
2691 delete mDiagramLayerSettings;
2692 mDiagramLayerSettings = new QgsDiagramLayerSettings();
2693 mDiagramLayerSettings->readXml( diagramSettingsElem );
2694 }
2695 }
2696 }
2697 // end diagram
2698
2699 styleChangedSignalBlocker.release();
2701 }
2702 return result;
2703}
2704
2705
2706bool QgsVectorLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
2707 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
2708{
2709 QDomElement layerElement = node.toElement();
2710 writeCommonStyle( layerElement, doc, context, categories );
2711
2712 ( void )writeStyle( node, doc, errorMessage, context, categories );
2713
2714 if ( categories.testFlag( GeometryOptions ) )
2715 mGeometryOptions->writeXml( node );
2716
2717 if ( categories.testFlag( Legend ) && legend() )
2718 {
2719 QDomElement legendElement = legend()->writeXml( doc, context );
2720 if ( !legendElement.isNull() )
2721 node.appendChild( legendElement );
2722 }
2723
2724 // Relation information for both referenced and referencing sides
2725 if ( categories.testFlag( Relations ) )
2726 {
2727 // Store referenced layers: relations where "this" is the child layer (the referencing part, that holds the FK)
2728 QDomElement referencedLayersElement = doc.createElement( QStringLiteral( "referencedLayers" ) );
2729 node.appendChild( referencedLayersElement );
2730
2731 const QList<QgsRelation> referencingRelations { QgsProject::instance()->relationManager()->referencingRelations( this ) };
2732 for ( const QgsRelation &rel : referencingRelations )
2733 {
2734 switch ( rel.type() )
2735 {
2737 QgsWeakRelation::writeXml( this, QgsWeakRelation::Referencing, rel, referencedLayersElement, doc );
2738 break;
2740 break;
2741 }
2742 }
2743
2744 // Store referencing layers: relations where "this" is the parent layer (the referenced part, that holds the FK)
2745 QDomElement referencingLayersElement = doc.createElement( QStringLiteral( "referencingLayers" ) );
2746 node.appendChild( referencedLayersElement );
2747
2748 const QList<QgsRelation> referencedRelations { QgsProject::instance()->relationManager()->referencedRelations( this ) };
2749 for ( const QgsRelation &rel : referencedRelations )
2750 {
2751 switch ( rel.type() )
2752 {
2754 QgsWeakRelation::writeXml( this, QgsWeakRelation::Referenced, rel, referencingLayersElement, doc );
2755 break;
2757 break;
2758 }
2759 }
2760 }
2761
2762 // write field configurations
2763 if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
2764 {
2765 QDomElement fieldConfigurationElement;
2766 // field configuration flag
2767 fieldConfigurationElement = doc.createElement( QStringLiteral( "fieldConfiguration" ) );
2768 node.appendChild( fieldConfigurationElement );
2769
2770 for ( const QgsField &field : std::as_const( mFields ) )
2771 {
2772 QDomElement fieldElement = doc.createElement( QStringLiteral( "field" ) );
2773 fieldElement.setAttribute( QStringLiteral( "name" ), field.name() );
2774 fieldConfigurationElement.appendChild( fieldElement );
2775
2776 if ( categories.testFlag( Fields ) )
2777 {
2778 fieldElement.setAttribute( QStringLiteral( "configurationFlags" ), qgsFlagValueToKeys( field.configurationFlags() ) );
2779 }
2780
2781 if ( categories.testFlag( Forms ) )
2782 {
2784
2785 // TODO : wrap this part in an if to only save if it was user-modified
2786 QDomElement editWidgetElement = doc.createElement( QStringLiteral( "editWidget" ) );
2787 fieldElement.appendChild( editWidgetElement );
2788 editWidgetElement.setAttribute( QStringLiteral( "type" ), field.editorWidgetSetup().type() );
2789 QDomElement editWidgetConfigElement = doc.createElement( QStringLiteral( "config" ) );
2790
2791 editWidgetConfigElement.appendChild( QgsXmlUtils::writeVariant( widgetSetup.config(), doc ) );
2792 editWidgetElement.appendChild( editWidgetConfigElement );
2793 // END TODO : wrap this part in an if to only save if it was user-modified
2794 }
2795 }
2796 }
2797
2798 if ( categories.testFlag( Fields ) )
2799 {
2800 //attribute aliases
2801 QDomElement aliasElem = doc.createElement( QStringLiteral( "aliases" ) );
2802 for ( const QgsField &field : std::as_const( mFields ) )
2803 {
2804 QDomElement aliasEntryElem = doc.createElement( QStringLiteral( "alias" ) );
2805 aliasEntryElem.setAttribute( QStringLiteral( "field" ), field.name() );
2806 aliasEntryElem.setAttribute( QStringLiteral( "index" ), mFields.indexFromName( field.name() ) );
2807 aliasEntryElem.setAttribute( QStringLiteral( "name" ), field.alias() );
2808 aliasElem.appendChild( aliasEntryElem );
2809 }
2810 node.appendChild( aliasElem );
2811
2812 //default expressions
2813 QDomElement defaultsElem = doc.createElement( QStringLiteral( "defaults" ) );
2814 for ( const QgsField &field : std::as_const( mFields ) )
2815 {
2816 QDomElement defaultElem = doc.createElement( QStringLiteral( "default" ) );
2817 defaultElem.setAttribute( QStringLiteral( "field" ), field.name() );
2818 defaultElem.setAttribute( QStringLiteral( "expression" ), field.defaultValueDefinition().expression() );
2819 defaultElem.setAttribute( QStringLiteral( "applyOnUpdate" ), field.defaultValueDefinition().applyOnUpdate() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
2820 defaultsElem.appendChild( defaultElem );
2821 }
2822 node.appendChild( defaultsElem );
2823
2824 // constraints
2825 QDomElement constraintsElem = doc.createElement( QStringLiteral( "constraints" ) );
2826 for ( const QgsField &field : std::as_const( mFields ) )
2827 {
2828 QDomElement constraintElem = doc.createElement( QStringLiteral( "constraint" ) );
2829 constraintElem.setAttribute( QStringLiteral( "field" ), field.name() );
2830 constraintElem.setAttribute( QStringLiteral( "constraints" ), field.constraints().constraints() );
2831 constraintElem.setAttribute( QStringLiteral( "unique_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintUnique ) );
2832 constraintElem.setAttribute( QStringLiteral( "notnull_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintNotNull ) );
2833 constraintElem.setAttribute( QStringLiteral( "exp_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintExpression ) );
2834 constraintsElem.appendChild( constraintElem );
2835 }
2836 node.appendChild( constraintsElem );
2837
2838 // constraint expressions
2839 QDomElement constraintExpressionsElem = doc.createElement( QStringLiteral( "constraintExpressions" ) );
2840 for ( const QgsField &field : std::as_const( mFields ) )
2841 {
2842 QDomElement constraintExpressionElem = doc.createElement( QStringLiteral( "constraint" ) );
2843 constraintExpressionElem.setAttribute( QStringLiteral( "field" ), field.name() );
2844 constraintExpressionElem.setAttribute( QStringLiteral( "exp" ), field.constraints().constraintExpression() );
2845 constraintExpressionElem.setAttribute( QStringLiteral( "desc" ), field.constraints().constraintDescription() );
2846 constraintExpressionsElem.appendChild( constraintExpressionElem );
2847 }
2848 node.appendChild( constraintExpressionsElem );
2849
2850 // save expression fields
2851 if ( !mExpressionFieldBuffer )
2852 {
2853 // can happen when saving style on a invalid layer
2855 dummy.writeXml( node, doc );
2856 }
2857 else
2858 {
2859 mExpressionFieldBuffer->writeXml( node, doc );
2860 }
2861 }
2862
2863 // add attribute actions
2864 if ( categories.testFlag( Actions ) )
2865 mActions->writeXml( node );
2866
2867 if ( categories.testFlag( AttributeTable ) )
2868 {
2869 mAttributeTableConfig.writeXml( node );
2870 mConditionalStyles->writeXml( node, doc, context );
2871 mStoredExpressionManager->writeXml( node );
2872 }
2873
2874 if ( categories.testFlag( Forms ) )
2875 mEditFormConfig.writeXml( node, context );
2876
2877 // save readonly state
2878 if ( categories.testFlag( LayerConfiguration ) )
2879 node.toElement().setAttribute( QStringLiteral( "readOnly" ), mReadOnly );
2880
2881 // save preview expression
2882 if ( categories.testFlag( LayerConfiguration ) )
2883 {
2884 QDomElement prevExpElem = doc.createElement( QStringLiteral( "previewExpression" ) );
2885 QDomText prevExpText = doc.createTextNode( mDisplayExpression );
2886 prevExpElem.appendChild( prevExpText );
2887 node.appendChild( prevExpElem );
2888 }
2889
2890 // save map tip
2891 if ( categories.testFlag( MapTips ) )
2892 {
2893 QDomElement mapTipElem = doc.createElement( QStringLiteral( "mapTip" ) );
2894 QDomText mapTipText = doc.createTextNode( mMapTipTemplate );
2895 mapTipElem.appendChild( mapTipText );
2896 node.toElement().appendChild( mapTipElem );
2897 }
2898
2899 return true;
2900}
2901
2902bool QgsVectorLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
2903 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
2904{
2905 QDomElement mapLayerNode = node.toElement();
2906
2907 emit writeCustomSymbology( mapLayerNode, doc, errorMessage );
2908
2909 // we must try to write the renderer if our geometry type is unknown
2910 // as this allows the renderer to be correctly restored even for layers
2911 // with broken sources
2912 if ( isSpatial() || mWkbType == QgsWkbTypes::Unknown )
2913 {
2914 if ( categories.testFlag( Symbology ) )
2915 {
2916 if ( mRenderer )
2917 {
2918 QDomElement rendererElement = mRenderer->save( doc, context );
2919 node.appendChild( rendererElement );
2920 }
2921 }
2922
2923 if ( categories.testFlag( Labeling ) )
2924 {
2925 if ( mLabeling )
2926 {
2927 QDomElement labelingElement = mLabeling->save( doc, context );
2928 node.appendChild( labelingElement );
2929 }
2930 mapLayerNode.setAttribute( QStringLiteral( "labelsEnabled" ), mLabelsEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
2931 }
2932
2933 // save the simplification drawing settings
2934 if ( categories.testFlag( Rendering ) )
2935 {
2936 mapLayerNode.setAttribute( QStringLiteral( "simplifyDrawingHints" ), QString::number( mSimplifyMethod.simplifyHints() ) );
2937 mapLayerNode.setAttribute( QStringLiteral( "simplifyAlgorithm" ), QString::number( mSimplifyMethod.simplifyAlgorithm() ) );
2938 mapLayerNode.setAttribute( QStringLiteral( "simplifyDrawingTol" ), QString::number( mSimplifyMethod.threshold() ) );
2939 mapLayerNode.setAttribute( QStringLiteral( "simplifyLocal" ), mSimplifyMethod.forceLocalOptimization() ? 1 : 0 );
2940 mapLayerNode.setAttribute( QStringLiteral( "simplifyMaxScale" ), QString::number( mSimplifyMethod.maximumScale() ) );
2941 }
2942
2943 //save customproperties
2944 if ( categories.testFlag( CustomProperties ) )
2945 {
2946 writeCustomProperties( node, doc );
2947 }
2948
2949 if ( categories.testFlag( Symbology ) )
2950 {
2951 // add the blend mode field
2952 QDomElement blendModeElem = doc.createElement( QStringLiteral( "blendMode" ) );
2953 QDomText blendModeText = doc.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
2954 blendModeElem.appendChild( blendModeText );
2955 node.appendChild( blendModeElem );
2956
2957 // add the feature blend mode field
2958 QDomElement featureBlendModeElem = doc.createElement( QStringLiteral( "featureBlendMode" ) );
2959 QDomText featureBlendModeText = doc.createTextNode( QString::number( QgsPainting::getBlendModeEnum( featureBlendMode() ) ) );
2960 featureBlendModeElem.appendChild( featureBlendModeText );
2961 node.appendChild( featureBlendModeElem );
2962 }
2963
2964 // add the layer opacity and scale visibility
2965 if ( categories.testFlag( Rendering ) )
2966 {
2967 QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
2968 QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
2969 layerOpacityElem.appendChild( layerOpacityText );
2970 node.appendChild( layerOpacityElem );
2971 mapLayerNode.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
2972 mapLayerNode.setAttribute( QStringLiteral( "maxScale" ), maximumScale() );
2973 mapLayerNode.setAttribute( QStringLiteral( "minScale" ), minimumScale() );
2974
2975 mapLayerNode.setAttribute( QStringLiteral( "symbologyReferenceScale" ), mRenderer ? mRenderer->referenceScale() : -1 );
2976 }
2977
2978 if ( categories.testFlag( Diagrams ) && mDiagramRenderer )
2979 {
2980 mDiagramRenderer->writeXml( mapLayerNode, doc, context );
2981 if ( mDiagramLayerSettings )
2982 mDiagramLayerSettings->writeXml( mapLayerNode, doc );
2983 }
2984 }
2985 return true;
2986}
2987
2988bool QgsVectorLayer::readSld( const QDomNode &node, QString &errorMessage )
2989{
2990 // get the Name element
2991 QDomElement nameElem = node.firstChildElement( QStringLiteral( "Name" ) );
2992 if ( nameElem.isNull() )
2993 {
2994 errorMessage = QStringLiteral( "Warning: Name element not found within NamedLayer while it's required." );
2995 }
2996
2997 if ( isSpatial() )
2998 {
2999 QgsFeatureRenderer *r = QgsFeatureRenderer::loadSld( node, geometryType(), errorMessage );
3000 if ( !r )
3001 return false;
3002
3003 // defer style changed signal until we've set the renderer, labeling, everything.
3004 // we don't want multiple signals!
3005 ScopedIntIncrementor styleChangedSignalBlocker( &mBlockStyleChangedSignal );
3006
3007 setRenderer( r );
3008
3009 // labeling
3010 readSldLabeling( node );
3011
3012 styleChangedSignalBlocker.release();
3014 }
3015 return true;
3016}
3017
3018bool QgsVectorLayer::writeSld( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QVariantMap &props ) const
3019{
3020 Q_UNUSED( errorMessage )
3021
3022 QVariantMap localProps = QVariantMap( props );
3024 {
3026 }
3027
3028 if ( isSpatial() )
3029 {
3030 // store the Name element
3031 QDomElement nameNode = doc.createElement( QStringLiteral( "se:Name" ) );
3032 nameNode.appendChild( doc.createTextNode( name() ) );
3033 node.appendChild( nameNode );
3034
3035 QDomElement userStyleElem = doc.createElement( QStringLiteral( "UserStyle" ) );
3036 node.appendChild( userStyleElem );
3037
3038 QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
3039 nameElem.appendChild( doc.createTextNode( name() ) );
3040
3041 userStyleElem.appendChild( nameElem );
3042
3043 QDomElement featureTypeStyleElem = doc.createElement( QStringLiteral( "se:FeatureTypeStyle" ) );
3044 userStyleElem.appendChild( featureTypeStyleElem );
3045
3046 mRenderer->toSld( doc, featureTypeStyleElem, localProps );
3047 if ( labelsEnabled() )
3048 {
3049 mLabeling->toSld( featureTypeStyleElem, localProps );
3050 }
3051 }
3052 return true;
3053}
3054
3055
3056bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, QgsGeometry &geom, bool skipDefaultValue )
3057{
3058 if ( !mEditBuffer || !mDataProvider )
3059 {
3060 return false;
3061 }
3062
3063 if ( mGeometryOptions->isActive() )
3064 mGeometryOptions->apply( geom );
3065
3066 updateExtents();
3067
3068 bool result = mEditBuffer->changeGeometry( fid, geom );
3069
3070 if ( result )
3071 {
3072 updateExtents();
3073 if ( !skipDefaultValue && !mDefaultValueOnUpdateFields.isEmpty() )
3074 updateDefaultValues( fid );
3075 }
3076 return result;
3077}
3078
3079
3080bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue, bool skipDefaultValues )
3081{
3082 bool result = false;
3083
3084 switch ( fields().fieldOrigin( field ) )
3085 {
3087 result = mJoinBuffer->changeAttributeValue( fid, field, newValue, oldValue );
3088 if ( result )
3089 emit attributeValueChanged( fid, field, newValue );
3090 break;
3091
3095 {
3096 if ( mEditBuffer && mDataProvider )
3097 result = mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
3098 break;
3099 }
3100
3102 break;
3103 }
3104
3105 if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
3106 updateDefaultValues( fid );
3107
3108 return result;
3109}
3110
3111bool QgsVectorLayer::changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues, bool skipDefaultValues )
3112{
3113 bool result = true;
3114
3115 QgsAttributeMap newValuesJoin;
3116 QgsAttributeMap oldValuesJoin;
3117
3118 QgsAttributeMap newValuesNotJoin;
3119 QgsAttributeMap oldValuesNotJoin;
3120
3121 for ( auto it = newValues.constBegin(); it != newValues.constEnd(); ++it )
3122 {
3123 const int field = it.key();
3124 const QVariant newValue = it.value();
3125 QVariant oldValue;
3126
3127 if ( oldValues.contains( field ) )
3128 oldValue = oldValues[field];
3129
3130 switch ( fields().fieldOrigin( field ) )
3131 {
3133 newValuesJoin[field] = newValue;
3134 oldValuesJoin[field] = oldValue;
3135 break;
3136
3140 {
3141 newValuesNotJoin[field] = newValue;
3142 oldValuesNotJoin[field] = oldValue;
3143 break;
3144 }
3145
3147 break;
3148 }
3149 }
3150
3151 if ( ! newValuesJoin.isEmpty() && mJoinBuffer )
3152 {
3153 result = mJoinBuffer->changeAttributeValues( fid, newValuesJoin, oldValuesJoin );
3154 }
3155
3156 if ( ! newValuesNotJoin.isEmpty() && mEditBuffer && mDataProvider )
3157 {
3158 result &= mEditBuffer->changeAttributeValues( fid, newValuesNotJoin, oldValues );
3159 }
3160
3161 if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
3162 {
3163 updateDefaultValues( fid );
3164 }
3165
3166 return result;
3167}
3168
3170{
3171 if ( !mEditBuffer || !mDataProvider )
3172 return false;
3173
3174 return mEditBuffer->addAttribute( field );
3175}
3176
3178{
3179 if ( attIndex < 0 || attIndex >= fields().count() )
3180 return;
3181
3182 QString name = fields().at( attIndex ).name();
3183 mFields[ attIndex ].setAlias( QString() );
3184 if ( mAttributeAliasMap.contains( name ) )
3185 {
3186 mAttributeAliasMap.remove( name );
3187 updateFields();
3188 mEditFormConfig.setFields( mFields );
3189 emit layerModified();
3190 }
3191}
3192
3193bool QgsVectorLayer::renameAttribute( int index, const QString &newName )
3194{
3195 if ( index < 0 || index >= fields().count() )
3196 return false;
3197
3198 switch ( mFields.fieldOrigin( index ) )
3199 {
3201 {
3202 if ( mExpressionFieldBuffer )
3203 {
3204 int oi = mFields.fieldOriginIndex( index );
3205 mExpressionFieldBuffer->renameExpression( oi, newName );
3206 updateFields();
3207 return true;
3208 }
3209 else
3210 {
3211 return false;
3212 }
3213 }
3214
3217
3218 if ( !mEditBuffer || !mDataProvider )
3219 return false;
3220
3221 return mEditBuffer->renameAttribute( index, newName );
3222
3225 return false;
3226
3227 }
3228
3229 return false; // avoid warning
3230}
3231
3232void QgsVectorLayer::setFieldAlias( int attIndex, const QString &aliasString )
3233{
3234 if ( attIndex < 0 || attIndex >= fields().count() )
3235 return;
3236
3237 QString name = fields().at( attIndex ).name();
3238
3239 mAttributeAliasMap.insert( name, aliasString );
3240 mFields[ attIndex ].setAlias( aliasString );
3241 mEditFormConfig.setFields( mFields );
3242 emit layerModified(); // TODO[MD]: should have a different signal?
3243}
3244
3245QString QgsVectorLayer::attributeAlias( int index ) const
3246{
3247 if ( index < 0 || index >= fields().count() )
3248 return QString();
3249
3250 return fields().at( index ).alias();
3251}
3252
3254{
3255 if ( index >= 0 && index < mFields.count() )
3256 return mFields.at( index ).displayName();
3257 else
3258 return QString();
3259}
3260
3262{
3263 return mAttributeAliasMap;
3264}
3265
3267{
3268 QSet<QString> excludeList;
3269 QMap< QString, QgsField::ConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
3270 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
3271 {
3272 if ( flagsIt->testFlag( QgsField::ConfigurationFlag::HideFromWms ) )
3273 {
3274 excludeList << flagsIt.key();
3275 }
3276 }
3277 return excludeList;
3278}
3279
3280void QgsVectorLayer::setExcludeAttributesWms( const QSet<QString> &att )
3281{
3282 QMap< QString, QgsField::ConfigurationFlags >::iterator flagsIt = mFieldConfigurationFlags.begin();
3283 for ( ; flagsIt != mFieldConfigurationFlags.end(); ++flagsIt )
3284 {
3285 flagsIt->setFlag( QgsField::ConfigurationFlag::HideFromWms, att.contains( flagsIt.key() ) );
3286 }
3287 updateFields();
3288}
3289
3291{
3292 QSet<QString> excludeList;
3293 QMap< QString, QgsField::ConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
3294 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
3295 {
3296 if ( flagsIt->testFlag( QgsField::ConfigurationFlag::HideFromWfs ) )
3297 {
3298 excludeList << flagsIt.key();
3299 }
3300 }
3301 return excludeList;
3302}
3303
3304void QgsVectorLayer::setExcludeAttributesWfs( const QSet<QString> &att )
3305{
3306 QMap< QString, QgsField::ConfigurationFlags >::iterator flagsIt = mFieldConfigurationFlags.begin();
3307 for ( ; flagsIt != mFieldConfigurationFlags.end(); ++flagsIt )
3308 {
3309 flagsIt->setFlag( QgsField::ConfigurationFlag::HideFromWfs, att.contains( flagsIt.key() ) );
3310 }
3311 updateFields();
3312}
3313
3315{
3316 if ( index < 0 || index >= fields().count() )
3317 return false;
3318
3319 if ( mFields.fieldOrigin( index ) == QgsFields::OriginExpression )
3320 {
3321 removeExpressionField( index );
3322 return true;
3323 }
3324
3325 if ( !mEditBuffer || !mDataProvider )
3326 return false;
3327
3328 return mEditBuffer->deleteAttribute( index );
3329}
3330
3331bool QgsVectorLayer::deleteAttributes( const QList<int> &attrs )
3332{
3333 bool deleted = false;
3334
3335 // Remove multiple occurrences of same attribute
3336 QList<int> attrList = qgis::setToList( qgis::listToSet( attrs ) );
3337
3338 std::sort( attrList.begin(), attrList.end(), std::greater<int>() );
3339
3340 for ( int attr : std::as_const( attrList ) )
3341 {
3342 if ( deleteAttribute( attr ) )
3343 {
3344 deleted = true;
3345 }
3346 }
3347
3348 return deleted;
3349}
3350
3351bool QgsVectorLayer::deleteFeatureCascade( QgsFeatureId fid, QgsVectorLayer::DeleteContext *context )
3352{
3353 if ( !mEditBuffer )
3354 return false;
3355
3356 if ( context && context->cascade )
3357 {
3358 const QList<QgsRelation> relations = context->project->relationManager()->referencedRelations( this );
3359 const bool hasRelationsOrJoins = !relations.empty() || mJoinBuffer->containsJoins();
3360 if ( hasRelationsOrJoins )
3361 {
3362 if ( context->mHandledFeatures.contains( this ) )
3363 {
3364 QgsFeatureIds &handledFeatureIds = context->mHandledFeatures[ this ];
3365 if ( handledFeatureIds.contains( fid ) )
3366 {
3367 // avoid endless recursion
3368 return false;
3369 }
3370 else
3371 {
3372 // add feature id
3373 handledFeatureIds << fid;
3374 }
3375 }
3376 else
3377 {
3378 // add layer and feature id
3379 context->mHandledFeatures.insert( this, QgsFeatureIds() << fid );
3380 }
3381
3382 for ( const QgsRelation &relation : relations )
3383 {
3384 //check if composition (and not association)
3385 switch ( relation.strength() )
3386 {
3388 {
3389 //get features connected over this relation
3390 QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( getFeature( fid ) );
3391 QgsFeatureIds childFeatureIds;
3392 QgsFeature childFeature;
3393 while ( relatedFeaturesIt.nextFeature( childFeature ) )
3394 {
3395 childFeatureIds.insert( childFeature.id() );
3396 }
3397 if ( childFeatureIds.count() > 0 )
3398 {
3399 relation.referencingLayer()->startEditing();
3400 relation.referencingLayer()->deleteFeatures( childFeatureIds, context );
3401 }
3402 break;
3403 }
3404
3406 break;
3407 }
3408 }
3409 }
3410 }
3411
3412 if ( mJoinBuffer->containsJoins() )
3413 mJoinBuffer->deleteFeature( fid, context );
3414
3415 bool res = mEditBuffer->deleteFeature( fid );
3416
3417 return res;
3418}
3419
3421{
3422 if ( !mEditBuffer )
3423 return false;
3424
3425 bool res = deleteFeatureCascade( fid, context );
3426
3427 if ( res )
3428 {
3429 updateExtents();
3430 }
3431
3432 return res;
3433}
3434
3436{
3437 bool res = true;
3438 const auto constFids = fids;
3439 for ( QgsFeatureId fid : constFids )
3440 res = deleteFeatureCascade( fid, context ) && res;
3441
3442 if ( res )
3443 {
3444 mSelectedFeatureIds.subtract( fids ); // remove it from selection
3445 updateExtents();
3446 }
3447
3448 return res;
3449}
3450
3452{
3453 return mFields;
3454}
3455
3457{
3458 QgsAttributeList pkAttributesList;
3459 if ( !mDataProvider )
3460 return pkAttributesList;
3461
3462 QgsAttributeList providerIndexes = mDataProvider->pkAttributeIndexes();
3463 for ( int i = 0; i < mFields.count(); ++i )
3464 {
3465 if ( mFields.fieldOrigin( i ) == QgsFields::OriginProvider &&
3466 providerIndexes.contains( mFields.fieldOriginIndex( i ) ) )
3467 pkAttributesList << i;
3468 }
3469
3470 return pkAttributesList;
3471}
3472
3474{
3475 if ( !mDataProvider )
3476 return static_cast< long long >( Qgis::FeatureCountState::UnknownCount );
3477 return mDataProvider->featureCount() +
3478 ( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->addedFeatures().size() - mEditBuffer->deletedFeatureIds().size() : 0 );
3479}
3480
3482{
3483 const QgsFeatureIds deletedFeatures( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->deletedFeatureIds() : QgsFeatureIds() );
3484 const QgsFeatureMap addedFeatures( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->addedFeatures() : QgsFeatureMap() );
3485
3486 if ( mEditBuffer && !deletedFeatures.empty() )
3487 {
3488 if ( addedFeatures.size() > deletedFeatures.size() )
3489 return QgsFeatureSource::FeatureAvailability::FeaturesAvailable;
3490 else
3491 return QgsFeatureSource::FeatureAvailability::FeaturesMaybeAvailable;
3492 }
3493
3494 if ( ( !mEditBuffer || addedFeatures.empty() ) && mDataProvider && mDataProvider->empty() )
3495 return QgsFeatureSource::FeatureAvailability::NoFeaturesAvailable;
3496 else
3497 return QgsFeatureSource::FeatureAvailability::FeaturesAvailable;
3498}
3499
3500bool QgsVectorLayer::commitChanges( bool stopEditing )
3501{
3502 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
3503 return project()->commitChanges( mCommitErrors, stopEditing, this );
3504
3505 mCommitErrors.clear();
3506
3507 if ( !mDataProvider )
3508 {
3509 mCommitErrors << tr( "ERROR: no provider" );
3510 return false;
3511 }
3512
3513 if ( !mEditBuffer )
3514 {
3515 mCommitErrors << tr( "ERROR: layer not editable" );
3516 return false;
3517 }
3518
3519 emit beforeCommitChanges( stopEditing );
3520
3521 if ( !mAllowCommit )
3522 return false;
3523
3524 mCommitChangesActive = true;
3525
3526 bool success = false;
3527 if ( mEditBuffer->editBufferGroup() )
3528 success = mEditBuffer->editBufferGroup()->commitChanges( mCommitErrors, stopEditing );
3529 else
3530 success = mEditBuffer->commitChanges( mCommitErrors );
3531
3532 mCommitChangesActive = false;
3533
3534 if ( !mDeletedFids.empty() )
3535 {
3536 emit featuresDeleted( mDeletedFids );
3537 mDeletedFids.clear();
3538 }
3539
3540 if ( success )
3541 {
3542 if ( stopEditing )
3543 {
3544 clearEditBuffer();
3545 }
3546 undoStack()->clear();
3547 emit afterCommitChanges();
3548 if ( stopEditing )
3549 emit editingStopped();
3550 }
3551 else
3552 {
3553 QgsMessageLog::logMessage( tr( "Commit errors:\n %1" ).arg( mCommitErrors.join( QLatin1String( "\n " ) ) ) );
3554 }
3555
3556 updateFields();
3557
3558 mDataProvider->updateExtents();
3559 mDataProvider->leaveUpdateMode();
3560
3561 // This second call is required because OGR provider with JSON
3562 // driver might have changed fields order after the call to
3563 // leaveUpdateMode
3564 if ( mFields.names() != mDataProvider->fields().names() )
3565 {
3566 updateFields();
3567 }
3568
3570
3571 return success;
3572}
3573
3575{
3576 return mCommitErrors;
3577}
3578
3579bool QgsVectorLayer::rollBack( bool deleteBuffer )
3580{
3581 if ( project() && project()->transactionMode() == Qgis::TransactionMode::BufferedGroups )
3582 return project()->rollBack( mCommitErrors, deleteBuffer, this );
3583
3584 if ( !mEditBuffer )
3585 {
3586 return false;
3587 }
3588
3589 if ( !mDataProvider )
3590 {
3591 mCommitErrors << tr( "ERROR: no provider" );
3592 return false;
3593 }
3594
3595 bool rollbackExtent = !mDataProvider->transaction() && ( !mEditBuffer->deletedFeatureIds().isEmpty() ||
3596 !mEditBuffer->addedFeatures().isEmpty() ||
3597 !mEditBuffer->changedGeometries().isEmpty() );
3598
3599 emit beforeRollBack();
3600
3601 mEditBuffer->rollBack();
3602
3603 emit afterRollBack();
3604
3605 if ( isModified() )
3606 {
3607 // new undo stack roll back method
3608 // old method of calling every undo could cause many canvas refreshes
3609 undoStack()->setIndex( 0 );
3610 }
3611
3612 updateFields();
3613
3614 if ( deleteBuffer )
3615 {
3616 delete mEditBuffer;
3617 mEditBuffer = nullptr;
3618 undoStack()->clear();
3619 }
3620 emit editingStopped();
3621
3622 if ( rollbackExtent )
3623 updateExtents();
3624
3625 mDataProvider->leaveUpdateMode();
3626
3628 return true;
3629}
3630
3632{
3633 return mSelectedFeatureIds.size();
3634}
3635
3637{
3638 return mSelectedFeatureIds;
3639}
3640
3642{
3643 QgsFeatureList features;
3644 features.reserve( mSelectedFeatureIds.count() );
3645 QgsFeature f;
3646
3648
3649 while ( it.nextFeature( f ) )
3650 {
3651 features.push_back( f );
3652 }
3653
3654 return features;
3655}
3656
3658{
3659 if ( mSelectedFeatureIds.isEmpty() )
3660 return QgsFeatureIterator();
3661
3664
3665 if ( mSelectedFeatureIds.count() == 1 )
3666 request.setFilterFid( *mSelectedFeatureIds.constBegin() );
3667 else
3668 request.setFilterFids( mSelectedFeatureIds );
3669
3670 return getFeatures( request );
3671}
3672
3674{
3675 if ( !mEditBuffer || !mDataProvider )
3676 return false;
3677
3678 if ( mGeometryOptions->isActive() )
3679 {
3680 for ( auto feature = features.begin(); feature != features.end(); ++feature )
3681 {
3682 QgsGeometry geom = feature->geometry();
3683 mGeometryOptions->apply( geom );
3684 feature->setGeometry( geom );
3685 }
3686 }
3687
3688 bool res = mEditBuffer->addFeatures( features );
3689 updateExtents();
3690
3691 if ( res && mJoinBuffer->containsJoins() )
3692 res = mJoinBuffer->addFeatures( features );
3693
3694 return res;
3695}
3696
3698{
3699 // if layer is not spatial, it has not CRS!
3700 setCrs( ( isSpatial() && mDataProvider ) ? mDataProvider->crs() : QgsCoordinateReferenceSystem() );
3701}
3702
3704{
3706 if ( exp.isField() )
3707 {
3708 return static_cast<const QgsExpressionNodeColumnRef *>( exp.rootNode() )->name();
3709 }
3710
3711 return QString();
3712}
3713
3714void QgsVectorLayer::setDisplayExpression( const QString &displayExpression )
3715{
3716 if ( mDisplayExpression == displayExpression )
3717 return;
3718
3719 mDisplayExpression = displayExpression;
3721}
3722
3724{
3725 if ( !mDisplayExpression.isEmpty() || mFields.isEmpty() )
3726 {
3727 return mDisplayExpression;
3728 }
3729 else
3730 {
3731 const QString candidateName = QgsVectorLayerUtils::guessFriendlyIdentifierField( mFields );
3732 if ( !candidateName.isEmpty() )
3733 {
3734 return QgsExpression::quotedColumnRef( candidateName );
3735 }
3736 else
3737 {
3738 return QString();
3739 }
3740 }
3741}
3742
3744{
3745 return ( mEditBuffer && mDataProvider );
3746}
3747
3749{
3752}
3753
3754bool QgsVectorLayer::isReadOnly() const
3755{
3756 return mDataSourceReadOnly || mReadOnly;
3757}
3758
3759bool QgsVectorLayer::setReadOnly( bool readonly )
3760{
3761 // exit if the layer is in editing mode
3762 if ( readonly && mEditBuffer )
3763 return false;
3764
3765 // exit if the data source is in read-only mode
3766 if ( !readonly && mDataSourceReadOnly )
3767 return false;
3768
3769 mReadOnly = readonly;
3770 emit readOnlyChanged();
3771 return true;
3772}
3773
3775{
3776 if ( ! mDataProvider )
3777 return false;
3778
3779 if ( mDataSourceReadOnly )
3780 return false;
3781
3782 return mDataProvider->capabilities() & QgsVectorDataProvider::EditingCapabilities && ! mReadOnly;
3783}
3784
3786{
3787 emit beforeModifiedCheck();
3788 return mEditBuffer && mEditBuffer->isModified();
3789}
3790
3791bool QgsVectorLayer::isAuxiliaryField( int index, int &srcIndex ) const
3792{
3793 bool auxiliaryField = false;
3794 srcIndex = -1;
3795
3796 if ( !auxiliaryLayer() )
3797 return auxiliaryField;
3798
3799 if ( index >= 0 && fields().fieldOrigin( index ) == QgsFields::OriginJoin )
3800 {
3801 const QgsVectorLayerJoinInfo *info = mJoinBuffer->joinForFieldIndex( index, fields(), srcIndex );
3802
3803 if ( info && info->joinLayerId() == auxiliaryLayer()->id() )
3804 auxiliaryField = true;
3805 }
3806
3807 return auxiliaryField;
3808}
3809
3811{
3812 // we must allow setting a renderer if our geometry type is unknown
3813 // as this allows the renderer to be correctly set even for layers
3814 // with broken sources
3815 if ( !isSpatial() && mWkbType != QgsWkbTypes::Unknown )
3816 return;
3817
3818 if ( r != mRenderer )
3819 {
3820 delete mRenderer;
3821 mRenderer = r;
3822 mSymbolFeatureCounted = false;
3823 mSymbolFeatureCountMap.clear();
3824 mSymbolFeatureIdMap.clear();
3825
3826 if ( mRenderer )
3827 {
3828 const double refreshRate = QgsSymbolLayerUtils::rendererFrameRate( mRenderer );
3829 if ( refreshRate <= 0 )
3830 {
3831 mRefreshRendererTimer->stop();
3832 mRefreshRendererTimer->setInterval( 0 );
3833 }
3834 else
3835 {
3836 mRefreshRendererTimer->setInterval( 1000 / refreshRate );
3837 mRefreshRendererTimer->start();
3838 }
3839 }
3840
3841 emit rendererChanged();
3843 }
3844}
3845
3847{
3848 if ( generator )
3849 {
3850 mRendererGenerators << generator;
3851 }
3852}
3853
3855{
3856 for ( int i = mRendererGenerators.count() - 1; i >= 0; --i )
3857 {
3858 if ( mRendererGenerators.at( i )->id() == id )
3859 {
3860 delete mRendererGenerators.at( i );
3861 mRendererGenerators.removeAt( i );
3862 }
3863 }
3864}
3865
3866QList<const QgsFeatureRendererGenerator *> QgsVectorLayer::featureRendererGenerators() const
3867{
3868 QList< const QgsFeatureRendererGenerator * > res;
3869 for ( const QgsFeatureRendererGenerator *generator : mRendererGenerators )
3870 res << generator;
3871 return res;
3872}
3873
3874void QgsVectorLayer::beginEditCommand( const QString &text )
3875{
3876 if ( !mDataProvider )
3877 {
3878 return;
3879 }
3880 if ( mDataProvider->transaction() )
3881 {
3882 QString ignoredError;
3883 mDataProvider->transaction()->createSavepoint( ignoredError );
3884 }
3885 undoStack()->beginMacro( text );
3886 mEditCommandActive = true;
3887 emit editCommandStarted( text );
3888}
3889
3891{
3892 if ( !mDataProvider )
3893 {
3894 return;
3895 }
3896 undoStack()->endMacro();
3897 mEditCommandActive = false;
3898 if ( !mDeletedFids.isEmpty() )
3899 {
3900 if ( selectedFeatureCount() > 0 )
3901 {
3902 mSelectedFeatureIds.subtract( mDeletedFids );
3903 }
3904 emit featuresDeleted( mDeletedFids );
3905 mDeletedFids.clear();
3906 }
3907 emit editCommandEnded();
3908}
3909
3911{
3912 if ( !mDataProvider )
3913 {
3914 return;
3915 }
3916 undoStack()->endMacro();
3917 undoStack()->undo();
3918
3919 // it's not directly possible to pop the last command off the stack (the destroyed one)
3920 // and delete, so we add a dummy obsolete command to force this to occur.
3921 // Pushing the new command deletes the destroyed one, and since the new
3922 // command is obsolete it's automatically deleted by the undo stack.
3923 std::unique_ptr< QUndoCommand > command = std::make_unique< QUndoCommand >();
3924 command->setObsolete( true );
3925 undoStack()->push( command.release() );
3926
3927 mEditCommandActive = false;
3928 mDeletedFids.clear();
3929 emit editCommandDestroyed();
3930}
3931
3933{
3934 return mJoinBuffer->addJoin( joinInfo );
3935}
3936
3937
3938bool QgsVectorLayer::removeJoin( const QString &joinLayerId )
3939{
3940 return mJoinBuffer->removeJoin( joinLayerId );
3941}
3942
3943const QList< QgsVectorLayerJoinInfo > QgsVectorLayer::vectorJoins() const
3944{
3945 return mJoinBuffer->vectorJoins();
3946}
3947
3948int QgsVectorLayer::addExpressionField( const QString &exp, const QgsField &fld )
3949{
3950 emit beforeAddingExpressionField( fld.name() );
3951 mExpressionFieldBuffer->addExpression( exp, fld );
3952 updateFields();
3953 int idx = mFields.indexFromName( fld.name() );
3954 emit attributeAdded( idx );
3955 return idx;
3956}
3957
3959{
3960 emit beforeRemovingExpressionField( index );
3961 int oi = mFields.fieldOriginIndex( index );
3962 mExpressionFieldBuffer->removeExpression( oi );
3963 updateFields();
3964 emit attributeDeleted( index );
3965}
3966
3967QString QgsVectorLayer::expressionField( int index ) const
3968{
3969 if ( mFields.fieldOrigin( index ) != QgsFields::OriginExpression )
3970 return QString();
3971
3972 int oi = mFields.fieldOriginIndex( index );
3973 if ( oi < 0 || oi >= mExpressionFieldBuffer->expressions().size() )
3974 return QString();
3975
3976 return mExpressionFieldBuffer->expressions().at( oi ).cachedExpression.expression();
3977}
3978
3979void QgsVectorLayer::updateExpressionField( int index, const QString &exp )
3980{
3981 int oi = mFields.fieldOriginIndex( index );
3982 mExpressionFieldBuffer->updateExpression( oi, exp );
3983}
3984
3986{
3987 if ( !mDataProvider )
3988 return;
3989
3990 QgsFields oldFields = mFields;
3991
3992 mFields = mDataProvider->fields();
3993
3994 // added / removed fields
3995 if ( mEditBuffer )
3996 mEditBuffer->updateFields( mFields );
3997
3998 // joined fields
3999 if ( mJoinBuffer->containsJoins() )
4000 mJoinBuffer->updateFields( mFields );
4001
4002 if ( mExpressionFieldBuffer )
4003 mExpressionFieldBuffer->updateFields( mFields );
4004
4005 // set aliases and default values
4006 QMap< QString, QString >::const_iterator aliasIt = mAttributeAliasMap.constBegin();
4007 for ( ; aliasIt != mAttributeAliasMap.constEnd(); ++aliasIt )
4008 {
4009 int index = mFields.lookupField( aliasIt.key() );
4010 if ( index < 0 )
4011 continue;
4012
4013 mFields[ index ].setAlias( aliasIt.value() );
4014 }
4015
4016 // Update configuration flags
4017 QMap< QString, QgsField::ConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
4018 for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
4019 {
4020 int index = mFields.lookupField( flagsIt.key() );
4021 if ( index < 0 )
4022 continue;
4023
4024 mFields[index].setConfigurationFlags( flagsIt.value() );
4025 }
4026
4027 // Update default values
4028 mDefaultValueOnUpdateFields.clear();
4029 QMap< QString, QgsDefaultValue >::const_iterator defaultIt = mDefaultExpressionMap.constBegin();
4030 for ( ; defaultIt != mDefaultExpressionMap.constEnd(); ++defaultIt )
4031 {
4032 int index = mFields.lookupField( defaultIt.key() );
4033 if ( index < 0 )
4034 continue;
4035
4036 mFields[ index ].setDefaultValueDefinition( defaultIt.value() );
4037 if ( defaultIt.value().applyOnUpdate() )
4038 mDefaultValueOnUpdateFields.insert( index );
4039 }
4040
4041 QMap< QString, QgsFieldConstraints::Constraints >::const_iterator constraintIt = mFieldConstraints.constBegin();
4042 for ( ; constraintIt != mFieldConstraints.constEnd(); ++constraintIt )
4043 {
4044 int index = mFields.lookupField( constraintIt.key() );
4045 if ( index < 0 )
4046 continue;
4047
4048 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4049
4050 // always keep provider constraints intact
4051 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintNotNull ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintNotNull ) )
4053 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintUnique ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintUnique ) )
4055 if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintExpression ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintExpression ) )
4057 mFields[ index ].setConstraints( constraints );
4058 }
4059
4060 QMap< QString, QPair< QString, QString > >::const_iterator constraintExpIt = mFieldConstraintExpressions.constBegin();
4061 for ( ; constraintExpIt != mFieldConstraintExpressions.constEnd(); ++constraintExpIt )
4062 {
4063 int index = mFields.lookupField( constraintExpIt.key() );
4064 if ( index < 0 )
4065 continue;
4066
4067 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4068
4069 // always keep provider constraints intact
4071 continue;
4072
4073 constraints.setConstraintExpression( constraintExpIt.value().first, constraintExpIt.value().second );
4074 mFields[ index ].setConstraints( constraints );
4075 }
4076
4077 QMap< QPair< QString, QgsFieldConstraints::Constraint >, QgsFieldConstraints::ConstraintStrength >::const_iterator constraintStrengthIt = mFieldConstraintStrength.constBegin();
4078 for ( ; constraintStrengthIt != mFieldConstraintStrength.constEnd(); ++constraintStrengthIt )
4079 {
4080 int index = mFields.lookupField( constraintStrengthIt.key().first );
4081 if ( index < 0 )
4082 continue;
4083
4084 QgsFieldConstraints constraints = mFields.at( index ).constraints();
4085
4086 // always keep provider constraints intact
4088 continue;
4089
4090 constraints.setConstraintStrength( constraintStrengthIt.key().second, constraintStrengthIt.value() );
4091 mFields[ index ].setConstraints( constraints );
4092 }
4093
4094 auto fieldWidgetIterator = mFieldWidgetSetups.constBegin();
4095 for ( ; fieldWidgetIterator != mFieldWidgetSetups.constEnd(); ++ fieldWidgetIterator )
4096 {
4097 int index = mFields.indexOf( fieldWidgetIterator.key() );
4098 if ( index < 0 )
4099 continue;
4100
4101 mFields[index].setEditorWidgetSetup( fieldWidgetIterator.value() );
4102 }
4103
4104 if ( oldFields != mFields )
4105 {
4106 emit updatedFields();
4107 mEditFormConfig.setFields( mFields );
4108 }
4109
4110}
4111
4112
4113QVariant QgsVectorLayer::defaultValue( int index, const QgsFeature &feature, QgsExpressionContext *context ) const
4114{
4115 if ( index < 0 || index >= mFields.count() || !mDataProvider )
4116 return QVariant();
4117
4118 QString expression = mFields.at( index ).defaultValueDefinition().expression();
4119 if ( expression.isEmpty() )
4120 return mDataProvider->defaultValue( index );
4121
4122 QgsExpressionContext *evalContext = context;
4123 std::unique_ptr< QgsExpressionContext > tempContext;
4124 if ( !evalContext )
4125 {
4126 // no context passed, so we create a default one
4128 evalContext = tempContext.get();
4129 }
4130
4131 if ( feature.isValid() )
4132 {
4134 featScope->setFeature( feature );
4135 featScope->setFields( feature.fields() );
4136 evalContext->appendScope( featScope );
4137 }
4138
4139 QVariant val;
4140 QgsExpression exp( expression );
4141 exp.prepare( evalContext );
4142 if ( exp.hasEvalError() )
4143 {
4144 QgsLogger::warning( "Error evaluating default value: " + exp.evalErrorString() );
4145 }
4146 else
4147 {
4148 val = exp.evaluate( evalContext );
4149 }
4150
4151 if ( feature.isValid() )
4152 {
4153 delete evalContext->popScope();
4154 }
4155
4156 return val;
4157}
4158
4160{
4161 if ( index < 0 || index >= mFields.count() )
4162 return;
4163
4164 if ( definition.isValid() )
4165 {
4166 mDefaultExpressionMap.insert( mFields.at( index ).name(), definition );
4167 }
4168 else
4169 {
4170 mDefaultExpressionMap.remove( mFields.at( index ).name() );
4171 }
4172 updateFields();
4173}
4174
4176{
4177 if ( index < 0 || index >= mFields.count() )
4178 return QgsDefaultValue();
4179 else
4180 return mFields.at( index ).defaultValueDefinition();
4181}
4182
4183QSet<QVariant> QgsVectorLayer::uniqueValues( int index, int limit ) const
4184{
4185 QSet<QVariant> uniqueValues;
4186 if ( !mDataProvider )
4187 {
4188 return uniqueValues;
4189 }
4190
4191 QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
4192 switch ( origin )
4193 {
4195 return uniqueValues;
4196
4197 case QgsFields::OriginProvider: //a provider field
4198 {
4199 uniqueValues = mDataProvider->uniqueValues( index, limit );
4200
4201 if ( mEditBuffer && ! mDataProvider->transaction() )
4202 {
4203 QSet<QString> vals;
4204 const auto constUniqueValues = uniqueValues;
4205 for ( const QVariant &v : constUniqueValues )
4206 {
4207 vals << v.toString();
4208 }
4209
4210 QgsFeatureMap added = mEditBuffer->addedFeatures();
4211 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4212 while ( addedIt.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
4213 {
4214 addedIt.next();
4215 QVariant v = addedIt.value().attribute( index );
4216 if ( v.isValid() )
4217 {
4218 QString vs = v.toString();
4219 if ( !vals.contains( vs ) )
4220 {
4221 vals << vs;
4222 uniqueValues << v;
4223 }
4224 }
4225 }
4226
4227 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4228 while ( it.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
4229 {
4230 it.next();
4231 QVariant v = it.value().value( index );
4232 if ( v.isValid() )
4233 {
4234 QString vs = v.toString();
4235 if ( !vals.contains( vs ) )
4236 {
4237 vals << vs;
4238 uniqueValues << v;
4239 }
4240 }
4241 }
4242 }
4243
4244 return uniqueValues;
4245 }
4246
4248 // the layer is editable, but in certain cases it can still be avoided going through all features
4249 if ( mDataProvider->transaction() || (
4250 mEditBuffer->deletedFeatureIds().isEmpty() &&
4251 mEditBuffer->addedFeatures().isEmpty() &&
4252 !mEditBuffer->deletedAttributeIds().contains( index ) &&
4253 mEditBuffer->changedAttributeValues().isEmpty() ) )
4254 {
4255 uniqueValues = mDataProvider->uniqueValues( index, limit );
4256 return uniqueValues;
4257 }
4259 //we need to go through each feature
4262 {
4263 QgsAttributeList attList;
4264 attList << index;
4265
4268 .setSubsetOfAttributes( attList ) );
4269
4270 QgsFeature f;
4271 QVariant currentValue;
4272 QHash<QString, QVariant> val;
4273 while ( fit.nextFeature( f ) )
4274 {
4275 currentValue = f.attribute( index );
4276 val.insert( currentValue.toString(), currentValue );
4277 if ( limit >= 0 && val.size() >= limit )
4278 {
4279 break;
4280 }
4281 }
4282
4283 return qgis::listToSet( val.values() );
4284 }
4285 }
4286
4287 Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
4288 return uniqueValues;
4289}
4290
4291QStringList QgsVectorLayer::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
4292{
4293 QStringList results;
4294 if ( !mDataProvider )
4295 {
4296 return results;
4297 }
4298
4299 QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
4300 switch ( origin )
4301 {
4303 return results;
4304
4305 case QgsFields::OriginProvider: //a provider field
4306 {
4307 results = mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
4308
4309 if ( mEditBuffer && ! mDataProvider->transaction() )
4310 {
4311 QgsFeatureMap added = mEditBuffer->addedFeatures();
4312 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4313 while ( addedIt.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
4314 {
4315 addedIt.next();
4316 QVariant v = addedIt.value().attribute( index );
4317 if ( v.isValid() )
4318 {
4319 QString vs = v.toString();
4320 if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
4321 {
4322 results << vs;
4323 }
4324 }
4325 }
4326
4327 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4328 while ( it.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
4329 {
4330 it.next();
4331 QVariant v = it.value().value( index );
4332 if ( v.isValid() )
4333 {
4334 QString vs = v.toString();
4335 if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
4336 {
4337 results << vs;
4338 }
4339 }
4340 }
4341 }
4342
4343 return results;
4344 }
4345
4347 // the layer is editable, but in certain cases it can still be avoided going through all features
4348 if ( mDataProvider->transaction() || ( mEditBuffer->deletedFeatureIds().isEmpty() &&
4349 mEditBuffer->addedFeatures().isEmpty() &&
4350 !mEditBuffer->deletedAttributeIds().contains( index ) &&
4351 mEditBuffer->changedAttributeValues().isEmpty() ) )
4352 {
4353 return mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
4354 }
4356 //we need to go through each feature
4359 {
4360 QgsAttributeList attList;
4361 attList << index;
4362
4363 QgsFeatureRequest request;
4364 request.setSubsetOfAttributes( attList );
4366 QString fieldName = mFields.at( index ).name();
4367 request.setFilterExpression( QStringLiteral( "\"%1\" ILIKE '%%2%'" ).arg( fieldName, substring ) );
4368 QgsFeatureIterator fit = getFeatures( request );
4369
4370 QgsFeature f;
4371 QString currentValue;
4372 while ( fit.nextFeature( f ) )
4373 {
4374 currentValue = f.attribute( index ).toString();
4375 if ( !results.contains( currentValue ) )
4376 results << currentValue;
4377
4378 if ( ( limit >= 0 && results.size() >= limit ) || ( feedback && feedback->isCanceled() ) )
4379 {
4380 break;
4381 }
4382 }
4383
4384 return results;
4385 }
4386 }
4387
4388 Q_ASSERT_X( false, "QgsVectorLayer::uniqueStringsMatching()", "Unknown source of the field!" );
4389 return results;
4390}
4391
4392QVariant QgsVectorLayer::minimumValue( int index ) const
4393{
4394 QVariant minimum;
4395 minimumOrMaximumValue( index, &minimum, nullptr );
4396 return minimum;
4397}
4398
4399QVariant QgsVectorLayer::maximumValue( int index ) const
4400{
4401 QVariant maximum;
4402 minimumOrMaximumValue( index, nullptr, &maximum );
4403 return maximum;
4404}
4405
4406void QgsVectorLayer::minimumAndMaximumValue( int index, QVariant &minimum, QVariant &maximum ) const
4407{
4408 minimumOrMaximumValue( index, &minimum, &maximum );
4409}
4410
4411void QgsVectorLayer::minimumOrMaximumValue( int index, QVariant *minimum, QVariant *maximum ) const
4412{
4413 if ( minimum )
4414 *minimum = QVariant();
4415 if ( maximum )
4416 *maximum = QVariant();
4417
4418 if ( !mDataProvider )
4419 {
4420 return;
4421 }
4422
4423 QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
4424
4425 switch ( origin )
4426 {
4428 {
4429 return;
4430 }
4431
4432 case QgsFields::OriginProvider: //a provider field
4433 {
4434 if ( minimum )
4435 *minimum = mDataProvider->minimumValue( index );
4436 if ( maximum )
4437 *maximum = mDataProvider->maximumValue( index );
4438 if ( mEditBuffer && ! mDataProvider->transaction() )
4439 {
4440 const QgsFeatureMap added = mEditBuffer->addedFeatures();
4441 QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4442 while ( addedIt.hasNext() )
4443 {
4444 addedIt.next();
4445 const QVariant v = addedIt.value().attribute( index );
4446 if ( minimum && v.isValid() && qgsVariantLessThan( v, *minimum ) )
4447 *minimum = v;
4448 if ( maximum && v.isValid() && qgsVariantGreaterThan( v, *maximum ) )
4449 *maximum = v;
4450 }
4451
4452 QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4453 while ( it.hasNext() )
4454 {
4455 it.next();
4456 const QVariant v = it.value().value( index );
4457 if ( minimum && v.isValid() && qgsVariantLessThan( v, *minimum ) )
4458 *minimum = v;
4459 if ( maximum && v.isValid() && qgsVariantGreaterThan( v, *maximum ) )
4460 *maximum = v;
4461 }
4462 }
4463 return;
4464 }
4465
4467 {
4468 // the layer is editable, but in certain cases it can still be avoided going through all features
4469 if ( mDataProvider->transaction() || ( mEditBuffer->deletedFeatureIds().isEmpty() &&
4470 mEditBuffer->addedFeatures().isEmpty() &&
4471 !mEditBuffer->deletedAttributeIds().contains( index ) &&
4472 mEditBuffer->changedAttributeValues().isEmpty() ) )
4473 {
4474 if ( minimum )
4475 *minimum = mDataProvider->minimumValue( index );
4476 if ( maximum )
4477 *maximum = mDataProvider->maximumValue( index );
4478 return;
4479 }
4480 }
4482 // no choice but to go through all features
4485 {
4486 // we need to go through each feature
4487 QgsAttributeList attList;
4488 attList << index;
4489
4492 .setSubsetOfAttributes( attList ) );
4493
4494 QgsFeature f;
4495 bool firstValue = true;
4496 while ( fit.nextFeature( f ) )
4497 {
4498 const QVariant currentValue = f.attribute( index );
4499 if ( QgsVariantUtils::isNull( currentValue ) )
4500 continue;
4501
4502 if ( firstValue )
4503 {
4504 if ( minimum )
4505 *minimum = currentValue;
4506 if ( maximum )
4507 *maximum = currentValue;
4508 firstValue = false;
4509 }
4510 else
4511 {
4512 if ( minimum && currentValue.isValid() && qgsVariantLessThan( currentValue, *minimum ) )
4513 *minimum = currentValue;
4514 if ( maximum && currentValue.isValid() && qgsVariantGreaterThan( currentValue, *maximum ) )
4515 *maximum = currentValue;
4516 }
4517 }
4518 return;
4519 }
4520 }
4521
4522 Q_ASSERT_X( false, "QgsVectorLayer::minimumOrMaximumValue()", "Unknown source of the field!" );
4523}
4524
4525void QgsVectorLayer::createEditBuffer()
4526{
4527 if ( mEditBuffer )
4528 clearEditBuffer();
4529
4530 if ( mDataProvider->transaction() )
4531 {
4532 mEditBuffer = new QgsVectorLayerEditPassthrough( this );
4533
4534 connect( mDataProvider->transaction(), &QgsTransaction::dirtied, this, &QgsVectorLayer::onDirtyTransaction, Qt::UniqueConnection );
4535 }
4536 else
4537 {
4538 mEditBuffer = new QgsVectorLayerEditBuffer( this );
4539 }
4540 // forward signals
4541 connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::invalidateSymbolCountedFlag );
4542 connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::layerModified ); // TODO[MD]: necessary?
4543 //connect( mEditBuffer, SIGNAL( layerModified() ), this, SLOT( triggerRepaint() ) ); // TODO[MD]: works well?
4545 connect( mEditBuffer, &QgsVectorLayerEditBuffer::featureDeleted, this, &QgsVectorLayer::onFeatureDeleted );
4556
4557}
4558
4559void QgsVectorLayer::clearEditBuffer()
4560{
4561 delete mEditBuffer;
4562 mEditBuffer = nullptr;
4563}
4564
4565QVariant QgsVectorLayer::aggregate( QgsAggregateCalculator::Aggregate aggregate, const QString &fieldOrExpression,
4567 bool *ok, QgsFeatureIds *fids, QgsFeedback *feedback, QString *error ) const
4568{
4569 if ( ok )
4570 *ok = false;
4571 if ( error )
4572 error->clear();
4573
4574 if ( !mDataProvider )
4575 {
4576 if ( error )
4577 *error = tr( "Layer is invalid" );
4578 return QVariant();
4579 }
4580
4581 // test if we are calculating based on a field
4582 const int attrIndex = QgsExpression::expressionToLayerFieldIndex( fieldOrExpression, this );
4583 if ( attrIndex >= 0 )
4584 {
4585 // aggregate is based on a field - if it's a provider field, we could possibly hand over the calculation
4586 // to the provider itself
4587 QgsFields::FieldOrigin origin = mFields.fieldOrigin( attrIndex );
4588 if ( origin == QgsFields::OriginProvider )
4589 {
4590 bool providerOk = false;
4591 QVariant val = mDataProvider->aggregate( aggregate, attrIndex, parameters, context, providerOk, fids );
4592 if ( providerOk )
4593 {
4594 // provider handled calculation
4595 if ( ok )
4596 *ok = true;
4597 return val;
4598 }
4599 }
4600 }
4601
4602 // fallback to using aggregate calculator to determine aggregate
4603 QgsAggregateCalculator c( this );
4604 if ( fids )
4605 c.setFidsFilter( *fids );
4606 c.setParameters( parameters );
4607 bool aggregateOk = false;
4608 const QVariant result = c.calculate( aggregate, fieldOrExpression, context, &aggregateOk, feedback );
4609 if ( ok )
4610 *ok = aggregateOk;
4611 if ( !aggregateOk && error )
4612 *error = c.lastError();
4613
4614 return result;
4615}
4616
4617void QgsVectorLayer::setFeatureBlendMode( QPainter::CompositionMode featureBlendMode )
4618{
4619 if ( mFeatureBlendMode == featureBlendMode )
4620 return;
4621
4622 mFeatureBlendMode = featureBlendMode;
4625}
4626
4627QPainter::CompositionMode QgsVectorLayer::featureBlendMode() const
4628{
4629 return mFeatureBlendMode;
4630}
4631
4632void QgsVectorLayer::readSldLabeling( const QDomNode &node )
4633{
4634 setLabeling( nullptr ); // start with no labeling
4635 setLabelsEnabled( false );
4636
4637 QDomElement element = node.toElement();
4638 if ( element.isNull() )
4639 return;
4640
4641 QDomElement userStyleElem = element.firstChildElement( QStringLiteral( "UserStyle" ) );
4642 if ( userStyleElem.isNull() )
4643 {
4644 QgsDebugMsgLevel( QStringLiteral( "Info: UserStyle element not found." ), 4 );
4645 return;
4646 }
4647
4648 QDomElement featTypeStyleElem = userStyleElem.firstChildElement( QStringLiteral( "FeatureTypeStyle" ) );
4649 if ( featTypeStyleElem.isNull() )
4650 {
4651 QgsDebugMsgLevel( QStringLiteral( "Info: FeatureTypeStyle element not found." ), 4 );
4652 return;
4653 }
4654
4655 // create empty FeatureTypeStyle element to merge TextSymbolizer's Rule's from all FeatureTypeStyle's
4656 QDomElement mergedFeatTypeStyle = featTypeStyleElem.cloneNode( false ).toElement();
4657
4658 // use the RuleRenderer when more rules are present or the rule
4659 // has filters or min/max scale denominators set,
4660 // otherwise use the Simple labeling
4661 bool needRuleBasedLabeling = false;
4662 int ruleCount = 0;
4663
4664 while ( !featTypeStyleElem.isNull() )
4665 {
4666 QDomElement ruleElem = featTypeStyleElem.firstChildElement( QStringLiteral( "Rule" ) );
4667 while ( !ruleElem.isNull() )
4668 {
4669 // test rule children element to check if we need to create RuleRenderer
4670 // and if the rule has a symbolizer
4671 bool hasTextSymbolizer = false;
4672 bool hasRuleBased = false;
4673 QDomElement ruleChildElem = ruleElem.firstChildElement();
4674 while ( !ruleChildElem.isNull() )
4675 {
4676 // rule has filter or min/max scale denominator, use the RuleRenderer
4677 if ( ruleChildElem.localName() == QLatin1String( "Filter" ) ||
4678 ruleChildElem.localName() == QLatin1String( "MinScaleDenominator" ) ||
4679 ruleChildElem.localName() == QLatin1String( "MaxScaleDenominator" ) )
4680 {
4681 hasRuleBased = true;
4682 }
4683 // rule has a renderer symbolizer, not a text symbolizer
4684 else if ( ruleChildElem.localName() == QLatin1String( "TextSymbolizer" ) )
4685 {
4686 QgsDebugMsgLevel( QStringLiteral( "Info: TextSymbolizer element found" ), 4 );
4687 hasTextSymbolizer = true;
4688 }
4689
4690 ruleChildElem = ruleChildElem.nextSiblingElement();
4691 }
4692
4693 if ( hasTextSymbolizer )
4694 {
4695 ruleCount++;
4696
4697 // append a clone of all Rules to the merged FeatureTypeStyle element
4698 mergedFeatTypeStyle.appendChild( ruleElem.cloneNode().toElement() );
4699
4700 if ( hasRuleBased )
4701 {
4702 QgsDebugMsgLevel( QStringLiteral( "Info: Filter or Min/MaxScaleDenominator element found: need a RuleBasedLabeling" ), 4 );
4703 needRuleBasedLabeling = true;
4704 }
4705 }
4706
4707 // more rules present, use the RuleRenderer
4708 if ( ruleCount > 1 )
4709 {
4710 QgsDebugMsgLevel( QStringLiteral( "Info: More Rule elements found: need a RuleBasedLabeling" ), 4 );
4711 needRuleBasedLabeling = true;
4712 }
4713
4714 // not use the rule based labeling if no rules with textSymbolizer
4715 if ( ruleCount == 0 )
4716 {
4717 needRuleBasedLabeling = false;
4718 }
4719
4720 ruleElem = ruleElem.nextSiblingElement( QStringLiteral( "Rule" ) );
4721 }
4722 featTypeStyleElem = featTypeStyleElem.nextSiblingElement( QStringLiteral( "FeatureTypeStyle" ) );
4723 }
4724
4725 if ( ruleCount == 0 )
4726 {
4727 QgsDebugMsgLevel( QStringLiteral( "Info: No TextSymbolizer element." ), 4 );
4728 return;
4729 }
4730
4731 QDomElement ruleElem = mergedFeatTypeStyle.firstChildElement( QStringLiteral( "Rule" ) );
4732
4733 if ( needRuleBasedLabeling )
4734 {
4735 QgsDebugMsgLevel( QStringLiteral( "Info: rule based labeling" ), 4 );
4736 QgsRuleBasedLabeling::Rule *rootRule = new QgsRuleBasedLabeling::Rule( nullptr );
4737 while ( !ruleElem.isNull() )
4738 {
4739
4740 QString label, description, filterExp;
4741 int scaleMinDenom = 0, scaleMaxDenom = 0;
4742 QgsPalLayerSettings settings;
4743
4744 // retrieve the Rule element child nodes
4745 QDomElement childElem = ruleElem.firstChildElement();
4746 while ( !childElem.isNull() )
4747 {
4748 if ( childElem.localName() == QLatin1String( "Name" ) )
4749 {
4750 // <se:Name> tag contains the rule identifier,
4751 // so prefer title tag for the label property value
4752 if ( label.isEmpty() )
4753 label = childElem.firstChild().nodeValue();
4754 }
4755 else if ( childElem.localName() == QLatin1String( "Description" ) )
4756 {
4757 // <se:Description> can contains a title and an abstract
4758 QDomElement titleElem = childElem.firstChildElement( QStringLiteral( "Title" ) );
4759 if ( !titleElem.isNull() )
4760 {
4761 label = titleElem.firstChild().nodeValue();
4762 }
4763
4764 QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( "Abstract" ) );
4765 if ( !abstractElem.isNull() )
4766 {
4767 description = abstractElem.firstChild().nodeValue();
4768 }
4769 }
4770 else if ( childElem.localName() == QLatin1String( "Abstract" ) )
4771 {
4772 // <sld:Abstract> (v1.0)
4773 description = childElem.firstChild().nodeValue();
4774 }
4775 else if ( childElem.localName() == QLatin1String( "Title" ) )
4776 {
4777 // <sld:Title> (v1.0)
4778 label = childElem.firstChild().nodeValue();
4779 }
4780 else if ( childElem.localName() == QLatin1String( "Filter" ) )
4781 {
4783 if ( filter )
4784 {
4785 if ( filter->hasParserError() )
4786 {
4787 QgsDebugMsgLevel( QStringLiteral( "SLD Filter parsing error: %1" ).arg( filter->parserErrorString() ), 3 );
4788 }
4789 else
4790 {
4791 filterExp = filter->expression();
4792 }
4793 delete filter;
4794 }
4795 }
4796 else if ( childElem.localName() == QLatin1String( "MinScaleDenominator" ) )
4797 {
4798 bool ok;
4799 int v = childElem.firstChild().nodeValue().toInt( &ok );
4800 if ( ok )
4801 scaleMinDenom = v;
4802 }
4803 else if ( childElem.localName() == QLatin1String( "MaxScaleDenominator" ) )
4804 {
4805 bool ok;
4806 int v = childElem.firstChild().nodeValue().toInt( &ok );
4807 if ( ok )
4808 scaleMaxDenom = v;
4809 }
4810 else if ( childElem.localName() == QLatin1String( "TextSymbolizer" ) )
4811 {
4812 readSldTextSymbolizer( childElem, settings );
4813 }
4814
4815 childElem = childElem.nextSiblingElement();
4816 }
4817
4818 QgsRuleBasedLabeling::Rule *ruleLabeling = new QgsRuleBasedLabeling::Rule( new QgsPalLayerSettings( settings ), scaleMinDenom, scaleMaxDenom, filterExp, label );
4819 rootRule->appendChild( ruleLabeling );
4820
4821 ruleElem = ruleElem.nextSiblingElement();
4822 }
4823
4824 setLabeling( new QgsRuleBasedLabeling( rootRule ) );
4825 setLabelsEnabled( true );
4826 }
4827 else
4828 {
4829 QgsDebugMsgLevel( QStringLiteral( "Info: simple labeling" ), 4 );
4830 // retrieve the TextSymbolizer element child node
4831 QDomElement textSymbolizerElem = ruleElem.firstChildElement( QStringLiteral( "TextSymbolizer" ) );
4833 if ( readSldTextSymbolizer( textSymbolizerElem, s ) )
4834 {
4836 setLabelsEnabled( true );
4837 }
4838 }
4839}
4840
4841bool QgsVectorLayer::readSldTextSymbolizer( const QDomNode &node, QgsPalLayerSettings &settings ) const
4842{
4843 if ( node.localName() != QLatin1String( "TextSymbolizer" ) )
4844 {
4845 QgsDebugMsgLevel( QStringLiteral( "Not a TextSymbolizer element: %1" ).arg( node.localName() ), 3 );
4846 return false;
4847 }
4848 QDomElement textSymbolizerElem = node.toElement();
4849 // Label
4850 QDomElement labelElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Label" ) );
4851 if ( !labelElem.isNull() )
4852 {
4853 QDomElement propertyNameElem = labelElem.firstChildElement( QStringLiteral( "PropertyName" ) );
4854 if ( !propertyNameElem.isNull() )
4855 {
4856 // set labeling defaults
4857
4858 // label attribute
4859 QString labelAttribute = propertyNameElem.text();
4860 settings.fieldName = labelAttribute;
4861 settings.isExpression = false;
4862
4863 int fieldIndex = mFields.lookupField( labelAttribute );
4864 if ( fieldIndex == -1 )
4865 {
4866 // label attribute is not in columns, check if it is an expression
4867 QgsExpression exp( labelAttribute );
4868 if ( !exp.hasEvalError() )
4869 {
4870 settings.isExpression = true;
4871 }
4872 else
4873 {
4874 QgsDebugMsgLevel( QStringLiteral( "SLD label attribute error: %1" ).arg( exp.evalErrorString() ), 3 );
4875 }
4876 }
4877 }
4878 else
4879 {
4880 QgsDebugMsgLevel( QStringLiteral( "Info: PropertyName element not found." ), 4 );
4881 return false;
4882 }
4883 }
4884 else
4885 {
4886 QgsDebugMsgLevel( QStringLiteral( "Info: Label element not found." ), 4 );
4887 return false;
4888 }
4889
4891 if ( textSymbolizerElem.hasAttribute( QStringLiteral( "uom" ) ) )
4892 {
4893 sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( textSymbolizerElem.attribute( QStringLiteral( "uom" ) ) );
4894 }
4895
4896 QString fontFamily = QStringLiteral( "Sans-Serif" );
4897 int fontPointSize = 10;
4899 int fontWeight = -1;
4900 bool fontItalic = false;
4901 bool fontUnderline = false;
4902
4903 // Font
4904 QDomElement fontElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Font" ) );
4905 if ( !fontElem.isNull() )
4906 {
4907 QgsStringMap fontSvgParams = QgsSymbolLayerUtils::getSvgParameterList( fontElem );
4908 for ( QgsStringMap::iterator it = fontSvgParams.begin(); it != fontSvgParams.end(); ++it )
4909 {
4910 QgsDebugMsgLevel( QStringLiteral( "found fontSvgParams %1: %2" ).arg( it.key(), it.value() ), 4 );
4911
4912 if ( it.key() == QLatin1String( "font-family" ) )
4913 {
4914 fontFamily = it.value();
4915 }
4916 else if ( it.key() == QLatin1String( "font-style" ) )
4917 {
4918 fontItalic = ( it.value() == QLatin1String( "italic" ) ) || ( it.value() == QLatin1String( "Italic" ) );
4919 }
4920 else if ( it.key() == QLatin1String( "font-size" ) )
4921 {
4922 bool ok;
4923 int fontSize = it.value().toInt( &ok );
4924 if ( ok )
4925 {
4926 fontPointSize = fontSize;
4927 fontUnitSize = sldUnitSize;
4928 }
4929 }
4930 else if ( it.key() == QLatin1String( "font-weight" ) )
4931 {
4932 if ( ( it.value() == QLatin1String( "bold" ) ) || ( it.value() == QLatin1String( "Bold" ) ) )
4933 fontWeight = QFont::Bold;
4934 }
4935 else if ( it.key() == QLatin1String( "font-underline" ) )
4936 {
4937 fontUnderline = ( it.value() == QLatin1String( "underline" ) ) || ( it.value() == QLatin1String( "Underline" ) );
4938 }
4939 }
4940 }
4941
4942 QgsTextFormat format;
4943 QFont font( fontFamily, fontPointSize, fontWeight, fontItalic );
4944 font.setUnderline( fontUnderline );
4945 format.setFont( font );
4946 format.setSize( fontPointSize );
4947 format.setSizeUnit( fontUnitSize );
4948
4949 // Fill
4950 QDomElement fillElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Fill" ) );
4951 QColor textColor;
4952 Qt::BrushStyle textBrush = Qt::SolidPattern;
4953 QgsSymbolLayerUtils::fillFromSld( fillElem, textBrush, textColor );
4954 if ( textColor.isValid() )
4955 {
4956 QgsDebugMsgLevel( QStringLiteral( "Info: textColor %1." ).arg( QVariant( textColor ).toString() ), 4 );
4957 format.setColor( textColor );
4958 }
4959
4960 QgsTextBufferSettings bufferSettings;
4961
4962 // Halo
4963 QDomElement haloElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Halo" ) );
4964 if ( !haloElem.isNull() )
4965 {
4966 bufferSettings.setEnabled( true );
4967 bufferSettings.setSize( 1 );
4968
4969 QDomElement radiusElem = haloElem.firstChildElement( QStringLiteral( "Radius" ) );
4970 if ( !radiusElem.isNull() )
4971 {
4972 bool ok;
4973 double bufferSize = radiusElem.text().toDouble( &ok );
4974 if ( ok )
4975 {
4976 bufferSettings.setSize( bufferSize );
4977 bufferSettings.setSizeUnit( sldUnitSize );
4978 }
4979 }
4980
4981 QDomElement haloFillElem = haloElem.firstChildElement( QStringLiteral( "Fill" ) );
4982 QColor bufferColor;
4983 Qt::BrushStyle bufferBrush = Qt::SolidPattern;
4984 QgsSymbolLayerUtils::fillFromSld( haloFillElem, bufferBrush, bufferColor );
4985 if ( bufferColor.isValid() )
4986 {
4987 QgsDebugMsgLevel( QStringLiteral( "Info: bufferColor %1." ).arg( QVariant( bufferColor ).toString() ), 4 );
4988 bufferSettings.setColor( bufferColor );
4989 }
4990 }
4991
4992 // LabelPlacement
4993 QDomElement labelPlacementElem = textSymbolizerElem.firstChildElement( QStringLiteral( "LabelPlacement" ) );
4994 if ( !labelPlacementElem.isNull() )
4995 {
4996 // PointPlacement
4997 QDomElement pointPlacementElem = labelPlacementElem.firstChildElement( QStringLiteral( "PointPlacement" ) );
4998 if ( !pointPlacementElem.isNull() )
4999 {
5002 {
5004 }
5005
5006 QDomElement displacementElem = pointPlacementElem.firstChildElement( QStringLiteral( "Displacement" ) );
5007 if ( !displacementElem.isNull() )
5008 {
5009 QDomElement displacementXElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementX" ) );
5010 if ( !displacementXElem.isNull() )
5011 {
5012 bool ok;
5013 double xOffset = displacementXElem.text().toDouble( &ok );
5014 if ( ok )
5015 {
5016 settings.xOffset = xOffset;
5017 settings.offsetUnits = sldUnitSize;
5018 }
5019 }
5020 QDomElement displacementYElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementY" ) );
5021 if ( !displacementYElem.isNull() )
5022 {
5023 bool ok;
5024 double yOffset = displacementYElem.text().toDouble( &ok );
5025 if ( ok )
5026 {
5027 settings.yOffset = yOffset;
5028 settings.offsetUnits = sldUnitSize;
5029 }
5030 }
5031 }
5032 QDomElement anchorPointElem = pointPlacementElem.firstChildElement( QStringLiteral( "AnchorPoint" ) );
5033 if ( !anchorPointElem.isNull() )
5034 {
5035 QDomElement anchorPointXElem = anchorPointElem.firstChildElement( QStringLiteral( "AnchorPointX" ) );
5036 if ( !anchorPointXElem.isNull() )
5037 {
5038 bool ok;
5039 double xOffset = anchorPointXElem.text().toDouble( &ok );
5040 if ( ok )
5041 {
5042 settings.xOffset = xOffset;
5043 settings.offsetUnits = sldUnitSize;
5044 }
5045 }
5046 QDomElement anchorPointYElem = anchorPointElem.firstChildElement( QStringLiteral( "AnchorPointY" ) );
5047 if ( !anchorPointYElem.isNull() )
5048 {
5049 bool ok;
5050 double yOffset = anchorPointYElem.text().toDouble( &ok );
5051 if ( ok )
5052 {
5053 settings.yOffset = yOffset;
5054 settings.offsetUnits = sldUnitSize;
5055 }
5056 }
5057 }
5058
5059 QDomElement rotationElem = pointPlacementElem.firstChildElement( QStringLiteral( "Rotation" ) );
5060 if ( !rotationElem.isNull() )
5061 {
5062 bool ok;
5063 double rotation = rotationElem.text().toDouble( &ok );
5064 if ( ok )
5065 {
5066 settings.angleOffset = 360 - rotation;
5067 }
5068 }
5069 }
5070 else
5071 {
5072 // PointPlacement
5073 QDomElement linePlacementElem = labelPlacementElem.firstChildElement( QStringLiteral( "LinePlacement" ) );
5074 if ( !linePlacementElem.isNull() )
5075 {
5077 }
5078 }
5079 }
5080
5081 // read vendor options
5082 QgsStringMap vendorOptions;
5083 QDomElement vendorOptionElem = textSymbolizerElem.firstChildElement( QStringLiteral( "VendorOption" ) );
5084 while ( !vendorOptionElem.isNull() && vendorOptionElem.localName() == QLatin1String( "VendorOption" ) )
5085 {
5086 QString optionName = vendorOptionElem.attribute( QStringLiteral( "name" ) );
5087 QString optionValue;
5088 if ( vendorOptionElem.firstChild().nodeType() == QDomNode::TextNode )
5089 {
5090 optionValue = vendorOptionElem.firstChild().nodeValue();
5091 }
5092 else
5093 {
5094 if ( vendorOptionElem.firstChild().nodeType() == QDomNode::ElementNode &&
5095 vendorOptionElem.firstChild().localName() == QLatin1String( "Literal" ) )
5096 {
5097 QgsDebugMsg( vendorOptionElem.firstChild().localName() );
5098 optionValue = vendorOptionElem.firstChild().firstChild().nodeValue();
5099 }
5100 else
5101 {
5102 QgsDebugMsg( QStringLiteral( "unexpected child of %1 named %2" ).arg( vendorOptionElem.localName(), optionName ) );
5103 }
5104 }
5105
5106 if ( !optionName.isEmpty() && !optionValue.isEmpty() )
5107 {
5108 vendorOptions[ optionName ] = optionValue;
5109 }
5110
5111 vendorOptionElem = vendorOptionElem.nextSiblingElement();
5112 }
5113 if ( !vendorOptions.isEmpty() )
5114 {
5115 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
5116 {
5117 if ( it.key() == QLatin1String( "underlineText" ) && it.value() == QLatin1String( "true" ) )
5118 {
5119 font.setUnderline( true );
5120 format.setFont( font );
5121 }
5122 else if ( it.key() == QLatin1String( "strikethroughText" ) && it.value() == QLatin1String( "true" ) )
5123 {
5124 font.setStrikeOut( true );
5125 format.setFont( font );
5126 }
5127 else if ( it.key() == QLatin1String( "maxDisplacement" ) )
5128 {
5130 }
5131 else if ( it.key() == QLatin1String( "followLine" ) && it.value() == QLatin1String( "true" ) )
5132 {
5134 {
5136 }
5137 else
5138 {
5140 }
5141 }
5142 else if ( it.key() == QLatin1String( "maxAngleDelta" ) )
5143 {
5144 bool ok;
5145 double angle = it.value().toDouble( &ok );
5146 if ( ok )
5147 {
5148 settings.maxCurvedCharAngleIn = angle;
5149 settings.maxCurvedCharAngleOut = angle;
5150 }
5151 }
5152 // miscellaneous options
5153 else if ( it.key() == QLatin1String( "conflictResolution" ) && it.value() == QLatin1String( "false" ) )
5154 {
5156 }
5157 else if ( it.key() == QLatin1String( "forceLeftToRight" ) && it.value() == QLatin1String( "false" ) )
5158 {
5159 settings.upsidedownLabels = Qgis::UpsideDownLabelHandling::AlwaysAllowUpsideDown;
5160 }
5161 else if ( it.key() == QLatin1String( "group" ) && it.value() == QLatin1String( "yes" ) )
5162 {
5163 settings.lineSettings().setMergeLines( true );
5164 }
5165 else if ( it.key() == QLatin1String( "labelAllGroup" ) && it.value() == QLatin1String( "true" ) )
5166 {
5167 settings.lineSettings().setMergeLines( true );
5168 }
5169 }
5170 }
5171
5172 format.setBuffer( bufferSettings );
5173 settings.setFormat( format );
5174 return true;
5175}
5176
5178{
5179 return mEditFormConfig;
5180}
5181
5183{
5184 if ( mEditFormConfig == editFormConfig )
5185 return;
5186
5187 mEditFormConfig = editFormConfig;
5188 mEditFormConfig.onRelationsLoaded();
5189 emit editFormConfigChanged();
5190}
5191
5193{
5194 return mMapTipTemplate;
5195}
5196
5197void QgsVectorLayer::setMapTipTemplate( const QString &mapTip )
5198{
5199 if ( mMapTipTemplate == mapTip )
5200 return;
5201
5202 mMapTipTemplate = mapTip;
5203 emit mapTipTemplateChanged();
5204}
5205
5207{
5208 QgsAttributeTableConfig config = mAttributeTableConfig;
5209
5210 if ( config.isEmpty() )
5211 config.update( fields() );
5212
5213 return config;
5214}
5215
5217{
5218 if ( mAttributeTableConfig != attributeTableConfig )
5219 {
5220 mAttributeTableConfig = attributeTableConfig;
5221 emit configChanged();
5222 }
5223}
5224
5226{
5228}
5229
5231{
5233}
5234
5236{
5237 if ( !mDiagramLayerSettings )
5238 mDiagramLayerSettings = new QgsDiagramLayerSettings();
5239 *mDiagramLayerSettings = s;
5240}
5241
5243{
5244 QgsLayerMetadataFormatter htmlFormatter( metadata() );
5245 QString myMetadata = QStringLiteral( "<html><head></head>\n<body>\n" );
5246
5247 myMetadata += generalHtmlMetadata();
5248
5249 // Begin Provider section
5250 myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
5251 myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
5252
5253 // storage type
5254 if ( !storageType().isEmpty() )
5255 {
5256 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Storage" ) + QStringLiteral( "</td><td>" ) + storageType() + QStringLiteral( "</td></tr>\n" );
5257 }
5258
5259 // comment
5260 if ( !dataComment().isEmpty() )
5261 {
5262 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Comment" ) + QStringLiteral( "</td><td>" ) + dataComment() + QStringLiteral( "</td></tr>\n" );
5263 }
5264
5265 // encoding
5266 const QgsVectorDataProvider *provider = dataProvider();
5267 if ( provider )
5268 {
5269 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Encoding" ) + QStringLiteral( "</td><td>" ) + provider->encoding() + QStringLiteral( "</td></tr>\n" );
5270 }
5271
5272 if ( isSpatial() )
5273 {
5274 // geom type
5276 if ( type < 0 || type > QgsWkbTypes::NullGeometry )
5277 {
5278 QgsDebugMsgLevel( QStringLiteral( "Invalid vector type" ), 2 );
5279 }
5280 else
5281 {
5282 QString typeString( QStringLiteral( "%1 (%2)" ).arg( QgsWkbTypes::geometryDisplayString( geometryType() ),
5284 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Geometry" ) + QStringLiteral( "</td><td>" ) + typeString + QStringLiteral( "</td></tr>\n" );
5285 }
5286
5287 // Extent
5288 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
5289 }
5290
5291 // feature count
5292 QLocale locale = QLocale();
5293 locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
5294 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
5295 + tr( "Feature count" ) + QStringLiteral( "</td><td>" )
5296 + ( featureCount() == -1 ? tr( "unknown" ) : locale.toString( static_cast<qlonglong>( featureCount() ) ) )
5297 + QStringLiteral( "</td></tr>\n" );
5298
5299 // End Provider section
5300 myMetadata += QLatin1String( "</table>\n<br><br>" );
5301
5302 if ( isSpatial() )
5303 {
5304 // CRS
5305 myMetadata += crsHtmlMetadata();
5306 }
5307
5308 // identification section
5309 myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
5310 myMetadata += htmlFormatter.identificationSectionHtml( );
5311 myMetadata += QLatin1String( "<br><br>\n" );
5312
5313 // extent section
5314 myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
5315 myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
5316 myMetadata += QLatin1String( "<br><br>\n" );
5317
5318 // Start the Access section
5319 myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
5320 myMetadata += htmlFormatter.accessSectionHtml( );
5321 myMetadata += QLatin1String( "<br><br>\n" );
5322
5323 // Fields section
5324 myMetadata += QStringLiteral( "<h1>" ) + tr( "Fields" ) + QStringLiteral( "</h1>\n<hr>\n<table class=\"list-view\">\n" );
5325
5326 // primary key
5328 if ( !pkAttrList.isEmpty() )
5329 {
5330 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Primary key attributes" ) + QStringLiteral( "</td><td>" );
5331 const auto constPkAttrList = pkAttrList;
5332 for ( int idx : constPkAttrList )
5333 {
5334 myMetadata += fields().at( idx ).name() + ' ';
5335 }
5336 myMetadata += QLatin1String( "</td></tr>\n" );
5337 }
5338
5339 const QgsFields myFields = fields();
5340
5341 // count fields
5342 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Count" ) + QStringLiteral( "</td><td>" ) + QString::number( myFields.size() ) + QStringLiteral( "</td></tr>\n" );
5343
5344 myMetadata += QLatin1String( "</table>\n<br><table width=\"100%\" class=\"tabular-view\">\n" );
5345 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" );
5346
5347 for ( int i = 0; i < myFields.size(); ++i )
5348 {
5349 QgsField myField = myFields.at( i );
5350 QString rowClass;
5351 if ( i % 2 )
5352 rowClass = QStringLiteral( "class=\"odd-row\"" );
5353 myMetadata += QLatin1String( "<tr " ) + rowClass + QLatin1String( "><td>" ) + myField.name() + QLatin1String( "</td><td>" ) + myField.typeName() + QLatin1String( "</td><td>" ) + QString::number( myField.length() ) + QLatin1String( "</td><td>" ) + QString::number( myField.precision() ) + QLatin1String( "</td><td>" ) + myField.comment() + QLatin1String( "</td></tr>\n" );
5354 }
5355
5356 //close field list
5357 myMetadata += QLatin1String( "</table>\n<br><br>" );
5358
5359 // Start the contacts section
5360 myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
5361 myMetadata += htmlFormatter.contactsSectionHtml( );
5362 myMetadata += QLatin1String( "<br><br>\n" );
5363
5364 // Start the links section
5365 myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
5366 myMetadata += htmlFormatter.linksSectionHtml( );
5367 myMetadata += QLatin1String( "<br><br>\n" );
5368
5369 // Start the history section
5370 myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
5371 myMetadata += htmlFormatter.historySectionHtml( );
5372 myMetadata += QLatin1String( "<br><br>\n" );
5373
5374 myMetadata += QLatin1String( "\n</body>\n</html>\n" );
5375 return myMetadata;
5376}
5377
5378void QgsVectorLayer::invalidateSymbolCountedFlag()
5379{
5380 mSymbolFeatureCounted = false;
5381}
5382
5383void QgsVectorLayer::onFeatureCounterCompleted()
5384{
5385 onSymbolsCounted();
5386 mFeatureCounter = nullptr;
5387}
5388
5389void QgsVectorLayer::onFeatureCounterTerminated()
5390{
5391 mFeatureCounter = nullptr;
5392}
5393
5394void QgsVectorLayer::onJoinedFieldsChanged()
5395{
5396 // some of the fields of joined layers have changed -> we need to update this layer's fields too
5397 updateFields();
5398}
5399
5400void QgsVectorLayer::onFeatureDeleted( QgsFeatureId fid )
5401{
5402 if ( mEditCommandActive || mCommitChangesActive )
5403 {
5404 mDeletedFids << fid;
5405 }
5406 else
5407 {
5408 mSelectedFeatureIds.remove( fid );
5409 emit featuresDeleted( QgsFeatureIds() << fid );
5410 }
5411
5412 emit featureDeleted( fid );
5413}
5414
5415void QgsVectorLayer::onRelationsLoaded()
5416{
5417 mEditFormConfig.onRelationsLoaded();
5418}
5419
5420void QgsVectorLayer::onSymbolsCounted()
5421{
5422 if ( mFeatureCounter )
5423 {
5424 mSymbolFeatureCounted = true;
5425 mSymbolFeatureCountMap = mFeatureCounter->symbolFeatureCountMap();
5426 mSymbolFeatureIdMap = mFeatureCounter->symbolFeatureIdMap();
5428 }
5429}
5430
5431QList<QgsRelation> QgsVectorLayer::referencingRelations( int idx ) const
5432{
5434}
5435
5436QList<QgsWeakRelation> QgsVectorLayer::weakRelations() const
5437{
5438 return mWeakRelations;
5439}
5440
5441void QgsVectorLayer::setWeakRelations( const QList<QgsWeakRelation> &relations )
5442{
5443 mWeakRelations = relations;
5444}
5445
5446int QgsVectorLayer::listStylesInDatabase( QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError )
5447{
5448 return QgsProviderRegistry::instance()->listStyles( mProviderKey, mDataSource, ids, names, descriptions, msgError );
5449}
5450
5451QString QgsVectorLayer::getStyleFromDatabase( const QString &styleId, QString &msgError )
5452{
5453 return QgsProviderRegistry::instance()->getStyleById( mProviderKey, mDataSource, styleId, msgError );
5454}
5455
5456bool QgsVectorLayer::deleteStyleFromDatabase( const QString &styleId, QString &msgError )
5457{
5459}
5460
5461
5462void QgsVectorLayer::saveStyleToDatabase( const QString &name, const QString &description,
5463 bool useAsDefault, const QString &uiFileContent, QString &msgError, QgsMapLayer::StyleCategories categories )
5464{
5465
5466 QString sldStyle, qmlStyle;
5467 QDomDocument qmlDocument, sldDocument;
5468 QgsReadWriteContext context;
5469 exportNamedStyle( qmlDocument, msgError, context, categories );
5470 if ( !msgError.isNull() )
5471 {
5472 return;
5473 }
5474 qmlStyle = qmlDocument.toString();
5475
5476 this->exportSldStyle( sldDocument, msgError );
5477 if ( !msgError.isNull() )
5478 {
5479 return;
5480 }
5481 sldStyle = sldDocument.toString();
5482
5484 mDataSource, qmlStyle, sldStyle, name,
5485 description, uiFileContent, useAsDefault, msgError );
5486}
5487
5488
5489
5490QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &resultFlag, QgsMapLayer::StyleCategories categories )
5491{
5492 return loadNamedStyle( theURI, resultFlag, false, categories );
5493}
5494
5495bool QgsVectorLayer::loadAuxiliaryLayer( const QgsAuxiliaryStorage &storage, const QString &key )
5496{
5497 bool rc = false;
5498
5499 QString joinKey = mAuxiliaryLayerKey;
5500 if ( !key.isEmpty() )
5501 joinKey = key;
5502
5503 if ( storage.isValid() && !joinKey.isEmpty() )
5504 {
5505 QgsAuxiliaryLayer *alayer = nullptr;
5506
5507 int idx = fields().lookupField( joinKey );
5508
5509 if ( idx >= 0 )
5510 {
5511 alayer = storage.createAuxiliaryLayer( fields().field( idx ), this );
5512
5513 if ( alayer )
5514 {
5515 setAuxiliaryLayer( alayer );
5516 rc = true;
5517 }
5518 }
5519 }
5520
5521 return rc;
5522}
5523
5525{
5526 mAuxiliaryLayerKey.clear();
5527
5528 if ( mAuxiliaryLayer )
5529 removeJoin( mAuxiliaryLayer->id() );
5530
5531 if ( alayer )
5532 {
5533 addJoin( alayer->joinInfo() );
5534
5535 if ( !alayer->isEditable() )
5536 alayer->startEditing();
5537
5538 mAuxiliaryLayerKey = alayer->joinInfo().targetFieldName();
5539 }
5540
5541 mAuxiliaryLayer.reset( alayer );
5542 if ( mAuxiliaryLayer )
5543 mAuxiliaryLayer->setParent( this );
5544 updateFields();
5545}
5546
5548{
5549 return mAuxiliaryLayer.get();
5550}
5551
5553{
5554 return mAuxiliaryLayer.get();
5555}
5556
5557QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &resultFlag, bool loadFromLocalDB, QgsMapLayer::StyleCategories categories )
5558{
5559 QgsDataSourceUri dsUri( theURI );
5560 QString returnMessage;
5561 QString qml, errorMsg;
5562 if ( !loadFromLocalDB && mDataProvider && mDataProvider->isSaveAndLoadStyleToDatabaseSupported() )
5563 {
5565 }
5566 if ( !qml.isEmpty() )
5567 {
5568 QDomDocument myDocument( QStringLiteral( "qgis" ) );
5569 myDocument.setContent( qml );
5570 resultFlag = importNamedStyle( myDocument, errorMsg );
5571 returnMessage = QObject::tr( "Loaded from Provider" );
5572 }
5573 else
5574 {
5575 returnMessage = QgsMapLayer::loadNamedStyle( theURI, resultFlag, categories );
5576 }
5577
5578 if ( resultFlag )
5579 emit styleLoaded( categories );
5580
5581 return returnMessage;
5582}
5583
5584QSet<QgsMapLayerDependency> QgsVectorLayer::dependencies() const
5585{
5586 if ( mDataProvider )
5587 return mDataProvider->dependencies() + mDependencies;
5588 return mDependencies;
5589}
5590
5591void QgsVectorLayer::emitDataChanged()
5592{
5593 if ( mDataChangedFired )
5594 return;
5595
5596 updateExtents(); // reset cached extent to reflect data changes
5597
5598 mDataChangedFired = true;
5599 emit dataChanged();
5600 mDataChangedFired = false;
5601}
5602
5603void QgsVectorLayer::onAfterCommitChangesDependency()
5604{
5605 mDataChangedFired = true;
5606 reload();
5607 mDataChangedFired = false;
5608}
5609
5610bool QgsVectorLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
5611{
5612 QSet<QgsMapLayerDependency> deps;
5613 const auto constODeps = oDeps;
5614 for ( const QgsMapLayerDependency &dep : constODeps )
5615 {
5616 if ( dep.origin() == QgsMapLayerDependency::FromUser )
5617 deps << dep;
5618 }
5619
5620 QSet<QgsMapLayerDependency> toAdd = deps - dependencies();
5621
5622 // disconnect layers that are not present in the list of dependencies anymore
5623 for ( const QgsMapLayerDependency &dep : std::as_const( mDependencies ) )
5624 {
5625 QgsVectorLayer *lyr = static_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( dep.layerId() ) );
5626 if ( !lyr )
5627 continue;
5628 disconnect( lyr, &QgsVectorLayer::featureAdded, this, &QgsVectorLayer::emitDataChanged );
5629 disconnect( lyr, &QgsVectorLayer::featureDeleted, this, &QgsVectorLayer::emitDataChanged );
5630 disconnect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
5631 disconnect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );
5633 disconnect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::onAfterCommitChangesDependency );
5634 }
5635
5636 // assign new dependencies
5637 if ( mDataProvider )
5638 mDependencies = mDataProvider->dependencies() + deps;
5639 else
5640 mDependencies = deps;
5641 emit dependenciesChanged();
5642
5643 // connect to new layers
5644 for ( const QgsMapLayerDependency &dep : std::as_const( mDependencies ) )
5645 {
5646 QgsVectorLayer *lyr = static_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( dep.layerId() ) );
5647 if ( !lyr )
5648 continue;
5649 connect( lyr, &QgsVectorLayer::featureAdded, this, &QgsVectorLayer::emitDataChanged );
5650 connect( lyr, &QgsVectorLayer::featureDeleted, this, &QgsVectorLayer::emitDataChanged );
5651 connect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
5652 connect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );