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