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