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