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