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