QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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 = qgis::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 : qgis::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 : qgis::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 && mDataProvider && !mDataProvider->hasMetadata() && mReadExtentFromXml && !mXmlExtent.isNull() )
850  {
851  mExtent = mXmlExtent;
852  mValidExtent = true;
853  mLazyExtent = false;
854  }
855 
856  if ( !mValidExtent && mLazyExtent && mDataProvider && mDataProvider->isValid() )
857  {
858  // get the extent
859  QgsRectangle mbr = mDataProvider->extent();
860 
861  // show the extent
862  QgsDebugMsgLevel( QStringLiteral( "Extent of layer: %1" ).arg( mbr.toString() ), 3 );
863  // store the extent
864  mValidExtent = true;
865  mExtent = mbr;
866 
867  mLazyExtent = false;
868  }
869 
870  if ( mValidExtent )
871  return QgsMapLayer::extent();
872 
873  if ( !isValid() || !mDataProvider )
874  {
875  QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
876  return rect;
877  }
878 
879  if ( !mEditBuffer ||
880  ( mEditBuffer->mDeletedFeatureIds.isEmpty() && mEditBuffer->mChangedGeometries.isEmpty() ) ||
881  QgsDataSourceUri( mDataProvider->dataSourceUri() ).useEstimatedMetadata() )
882  {
883  mDataProvider->updateExtents();
884 
885  // get the extent of the layer from the provider
886  // but only when there are some features already
887  if ( mDataProvider->featureCount() != 0 )
888  {
889  QgsRectangle r = mDataProvider->extent();
890  rect.combineExtentWith( r );
891  }
892 
893  if ( mEditBuffer )
894  {
895  for ( QgsFeatureMap::const_iterator it = mEditBuffer->mAddedFeatures.constBegin(); it != mEditBuffer->mAddedFeatures.constEnd(); ++it )
896  {
897  if ( it->hasGeometry() )
898  {
899  QgsRectangle r = it->geometry().boundingBox();
900  rect.combineExtentWith( r );
901  }
902  }
903  }
904  }
905  else
906  {
908  .setNoAttributes() );
909 
910  QgsFeature fet;
911  while ( fit.nextFeature( fet ) )
912  {
913  if ( fet.hasGeometry() && fet.geometry().type() != QgsWkbTypes::UnknownGeometry )
914  {
915  QgsRectangle bb = fet.geometry().boundingBox();
916  rect.combineExtentWith( bb );
917  }
918  }
919  }
920 
921  if ( rect.xMinimum() > rect.xMaximum() && rect.yMinimum() > rect.yMaximum() )
922  {
923  // special case when there are no features in provider nor any added
924  rect = QgsRectangle(); // use rectangle with zero coordinates
925  }
926 
927  mValidExtent = true;
928  mExtent = rect;
929 
930  // Send this (hopefully) up the chain to the map canvas
931  emit recalculateExtents();
932 
933  return rect;
934 }
935 
937 {
938  return extent();
939 }
940 
942 {
943  if ( !isValid() || !mDataProvider )
944  {
945  QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
946  return customProperty( QStringLiteral( "storedSubsetString" ) ).toString();
947  }
948  return mDataProvider->subsetString();
949 }
950 
951 bool QgsVectorLayer::setSubsetString( const QString &subset )
952 {
953  if ( !isValid() || !mDataProvider )
954  {
955  QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider or while editing" ), 3 );
956  setCustomProperty( QStringLiteral( "storedSubsetString" ), subset );
957  return false;
958  }
959  else if ( mEditBuffer )
960  {
961  QgsDebugMsgLevel( QStringLiteral( "invoked while editing" ), 3 );
962  return false;
963  }
964 
965  if ( subset == mDataProvider->subsetString() )
966  return true;
967 
968  bool res = mDataProvider->setSubsetString( subset );
969 
970  // get the updated data source string from the provider
971  mDataSource = mDataProvider->dataSourceUri();
972  updateExtents();
973  updateFields();
974 
975  if ( res )
976  {
977  emit subsetStringChanged();
978  triggerRepaint();
979  }
980 
981  return res;
982 }
983 
985 {
986  if ( isValid() && mDataProvider && !mEditBuffer && ( isSpatial() && geometryType() != QgsWkbTypes::PointGeometry ) && ( mSimplifyMethod.simplifyHints() & simplifyHint ) && renderContext.useRenderingOptimization() )
987  {
988  double maximumSimplificationScale = mSimplifyMethod.maximumScale();
989 
990  // check maximum scale at which generalisation should be carried out
991  return !( maximumSimplificationScale > 1 && renderContext.rendererScale() <= maximumSimplificationScale );
992  }
993  return false;
994 }
995 
997 {
998  return mConditionalStyles;
999 }
1000 
1002 {
1003  if ( !isValid() || !mDataProvider )
1004  return QgsFeatureIterator();
1005 
1006  return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( new QgsVectorLayerFeatureSource( this ), true, request ) );
1007 }
1008 
1010 {
1011  QgsFeature feature;
1013  if ( feature.isValid() )
1014  return feature.geometry();
1015  else
1016  return QgsGeometry();
1017 }
1018 
1020 {
1021  if ( !isValid() || !mEditBuffer || !mDataProvider )
1022  return false;
1023 
1024 
1025  if ( mGeometryOptions->isActive() )
1026  {
1027  QgsGeometry geom = feature.geometry();
1028  mGeometryOptions->apply( geom );
1029  feature.setGeometry( geom );
1030  }
1031 
1032  bool success = mEditBuffer->addFeature( feature );
1033 
1034  if ( success )
1035  {
1036  updateExtents();
1037 
1038  if ( mJoinBuffer->containsJoins() )
1039  success = mJoinBuffer->addFeature( feature );
1040  }
1041 
1042  return success;
1043 }
1044 
1045 bool QgsVectorLayer::updateFeature( QgsFeature &updatedFeature, bool skipDefaultValues )
1046 {
1047  if ( !mEditBuffer || !mDataProvider )
1048  {
1049  return false;
1050  }
1051 
1052  QgsFeature currentFeature = getFeature( updatedFeature.id() );
1053  if ( currentFeature.isValid() )
1054  {
1055  bool hasChanged = false;
1056  bool hasError = false;
1057 
1058  if ( ( updatedFeature.hasGeometry() || currentFeature.hasGeometry() ) && !updatedFeature.geometry().equals( currentFeature.geometry() ) )
1059  {
1060  QgsGeometry geometry = updatedFeature.geometry();
1061  if ( changeGeometry( updatedFeature.id(), geometry, true ) )
1062  {
1063  hasChanged = true;
1064  updatedFeature.setGeometry( geometry );
1065  }
1066  else
1067  {
1068  QgsDebugMsgLevel( QStringLiteral( "geometry of feature %1 could not be changed." ).arg( updatedFeature.id() ), 3 );
1069  }
1070  }
1071 
1072  QgsAttributes fa = updatedFeature.attributes();
1073  QgsAttributes ca = currentFeature.attributes();
1074 
1075  for ( int attr = 0; attr < fa.count(); ++attr )
1076  {
1077  if ( fa.at( attr ) != ca.at( attr ) )
1078  {
1079  if ( changeAttributeValue( updatedFeature.id(), attr, fa.at( attr ), ca.at( attr ), true ) )
1080  {
1081  hasChanged = true;
1082  }
1083  else
1084  {
1085  QgsDebugMsgLevel( QStringLiteral( "attribute %1 of feature %2 could not be changed." ).arg( attr ).arg( updatedFeature.id() ), 3 );
1086  hasError = true;
1087  }
1088  }
1089  }
1090  if ( hasChanged && !mDefaultValueOnUpdateFields.isEmpty() && !skipDefaultValues )
1091  updateDefaultValues( updatedFeature.id(), updatedFeature );
1092 
1093  return !hasError;
1094  }
1095  else
1096  {
1097  QgsDebugMsgLevel( QStringLiteral( "feature %1 could not be retrieved" ).arg( updatedFeature.id() ), 3 );
1098  return false;
1099  }
1100 }
1101 
1102 
1103 bool QgsVectorLayer::insertVertex( double x, double y, QgsFeatureId atFeatureId, int beforeVertex )
1104 {
1105  if ( !isValid() || !mEditBuffer || !mDataProvider )
1106  return false;
1107 
1108  QgsVectorLayerEditUtils utils( this );
1109  bool result = utils.insertVertex( x, y, atFeatureId, beforeVertex );
1110  if ( result )
1111  updateExtents();
1112  return result;
1113 }
1114 
1115 
1116 bool QgsVectorLayer::insertVertex( const QgsPoint &point, QgsFeatureId atFeatureId, int beforeVertex )
1117 {
1118  if ( !isValid() || !mEditBuffer || !mDataProvider )
1119  return false;
1120 
1121  QgsVectorLayerEditUtils utils( this );
1122  bool result = utils.insertVertex( point, atFeatureId, beforeVertex );
1123  if ( result )
1124  updateExtents();
1125  return result;
1126 }
1127 
1128 
1129 bool QgsVectorLayer::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
1130 {
1131  if ( !isValid() || !mEditBuffer || !mDataProvider )
1132  return false;
1133 
1134  QgsVectorLayerEditUtils utils( this );
1135  bool result = utils.moveVertex( x, y, atFeatureId, atVertex );
1136 
1137  if ( result )
1138  updateExtents();
1139  return result;
1140 }
1141 
1142 bool QgsVectorLayer::moveVertex( const QgsPoint &p, QgsFeatureId atFeatureId, int atVertex )
1143 {
1144  if ( !isValid() || !mEditBuffer || !mDataProvider )
1145  return false;
1146 
1147  QgsVectorLayerEditUtils utils( this );
1148  bool result = utils.moveVertex( p, atFeatureId, atVertex );
1149 
1150  if ( result )
1151  updateExtents();
1152  return result;
1153 }
1154 
1156 {
1157  if ( !isValid() || !mEditBuffer || !mDataProvider )
1159 
1160  QgsVectorLayerEditUtils utils( this );
1161  EditResult result = utils.deleteVertex( featureId, vertex );
1162 
1163  if ( result == Success )
1164  updateExtents();
1165  return result;
1166 }
1167 
1168 
1170 {
1171  if ( !isValid() || !mDataProvider || !( mDataProvider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) )
1172  {
1173  return false;
1174  }
1175 
1176  if ( !isEditable() )
1177  {
1178  return false;
1179  }
1180 
1181  int deleted = 0;
1182  int count = mSelectedFeatureIds.size();
1183  // Make a copy since deleteFeature modifies mSelectedFeatureIds
1184  QgsFeatureIds selectedFeatures( mSelectedFeatureIds );
1185  const auto constSelectedFeatures = selectedFeatures;
1186  for ( QgsFeatureId fid : constSelectedFeatures )
1187  {
1188  deleted += deleteFeature( fid, context ); // removes from selection
1189  }
1190 
1191  triggerRepaint();
1192  updateExtents();
1193 
1194  if ( deletedCount )
1195  {
1196  *deletedCount = deleted;
1197  }
1198 
1199  return deleted == count;
1200 }
1201 
1202 static const QgsPointSequence vectorPointXY2pointSequence( const QVector<QgsPointXY> &points )
1203 {
1204  QgsPointSequence pts;
1205  pts.reserve( points.size() );
1206  QVector<const QgsPointXY>::iterator it = points.constBegin();
1207  while ( it != points.constEnd() )
1208  {
1209  pts.append( QgsPoint( *it ) );
1210  ++it;
1211  }
1212  return pts;
1213 }
1214 QgsGeometry::OperationResult QgsVectorLayer::addRing( const QVector<QgsPointXY> &ring, QgsFeatureId *featureId )
1215 {
1216  return addRing( vectorPointXY2pointSequence( ring ), featureId );
1217 }
1218 
1220 {
1221  if ( !isValid() || !mEditBuffer || !mDataProvider )
1222  return QgsGeometry::OperationResult::LayerNotEditable;
1223 
1224  QgsVectorLayerEditUtils utils( this );
1225  QgsGeometry::OperationResult result = QgsGeometry::OperationResult::AddRingNotInExistingFeature;
1226 
1227  //first try with selected features
1228  if ( !mSelectedFeatureIds.isEmpty() )
1229  {
1230  result = utils.addRing( ring, mSelectedFeatureIds, featureId );
1231  }
1232 
1233  if ( result != QgsGeometry::OperationResult::Success )
1234  {
1235  //try with all intersecting features
1236  result = utils.addRing( ring, QgsFeatureIds(), featureId );
1237  }
1238 
1239  return result;
1240 }
1241 
1243 {
1244  if ( !isValid() || !mEditBuffer || !mDataProvider )
1245  {
1246  delete ring;
1247  return QgsGeometry::OperationResult::LayerNotEditable;
1248  }
1249 
1250  if ( !ring )
1251  {
1252  return QgsGeometry::OperationResult::InvalidInputGeometryType;
1253  }
1254 
1255  if ( !ring->isClosed() )
1256  {
1257  delete ring;
1258  return QgsGeometry::OperationResult::AddRingNotClosed;
1259  }
1260 
1261  QgsVectorLayerEditUtils utils( this );
1262  QgsGeometry::OperationResult result = QgsGeometry::OperationResult::AddRingNotInExistingFeature;
1263 
1264  //first try with selected features
1265  if ( !mSelectedFeatureIds.isEmpty() )
1266  {
1267  result = utils.addRing( static_cast< QgsCurve * >( ring->clone() ), mSelectedFeatureIds, featureId );
1268  }
1269 
1270  if ( result != QgsGeometry::OperationResult::Success )
1271  {
1272  //try with all intersecting features
1273  result = utils.addRing( static_cast< QgsCurve * >( ring->clone() ), QgsFeatureIds(), featureId );
1274  }
1275 
1276  delete ring;
1277  return result;
1278 }
1279 
1280 QgsGeometry::OperationResult QgsVectorLayer::addPart( const QList<QgsPointXY> &points )
1281 {
1282  QgsPointSequence pts;
1283  pts.reserve( points.size() );
1284  for ( QList<QgsPointXY>::const_iterator it = points.constBegin(); it != points.constEnd() ; ++it )
1285  {
1286  pts.append( QgsPoint( *it ) );
1287  }
1288  return addPart( pts );
1289 }
1290 
1291 QgsGeometry::OperationResult QgsVectorLayer::addPart( const QVector<QgsPointXY> &points )
1292 {
1293  return addPart( vectorPointXY2pointSequence( points ) );
1294 }
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 = qgis::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 = qgis::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 : qgis::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 : qgis::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 : qgis::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 : qgis::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 : qgis::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 : qgis::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 ? mEditBuffer->mAddedFeatures.size() - mEditBuffer->mDeletedFeatureIds.size() : 0 );
3370 }
3371 
3373 {
3374  const QgsFeatureIds deletedFeatures( mEditBuffer ? mEditBuffer->deletedFeatureIds() : QgsFeatureIds() );
3375  const QgsFeatureMap addedFeatures( mEditBuffer ? 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 = !mEditBuffer->mDeletedFeatureIds.isEmpty() ||
3460  !mEditBuffer->mAddedFeatures.isEmpty() ||
3461  !mEditBuffer->mChangedGeometries.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 = qgis::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 )
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 ( mEditBuffer->mDeletedFeatureIds.isEmpty() &&
4095  mEditBuffer->mAddedFeatures.isEmpty() &&
4096  !mEditBuffer->mDeletedAttributeIds.contains( index ) &&
4097  mEditBuffer->mChangedAttributeValues.isEmpty() )
4098  {
4099  uniqueValues = mDataProvider->uniqueValues( index, limit );
4100  return uniqueValues;
4101  }
4102  FALLTHROUGH
4103  //we need to go through each feature
4104  case QgsFields::OriginJoin:
4106  {
4107  QgsAttributeList attList;
4108  attList << index;
4109 
4112  .setSubsetOfAttributes( attList ) );
4113 
4114  QgsFeature f;
4115  QVariant currentValue;
4116  QHash<QString, QVariant> val;
4117  while ( fit.nextFeature( f ) )
4118  {
4119  currentValue = f.attribute( index );
4120  val.insert( currentValue.toString(), currentValue );
4121  if ( limit >= 0 && val.size() >= limit )
4122  {
4123  break;
4124  }
4125  }
4126 
4127  return qgis::listToSet( val.values() );
4128  }
4129  }
4130 
4131  Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
4132  return uniqueValues;
4133 }
4134 
4135 QStringList QgsVectorLayer::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
4136 {
4137  QStringList results;
4138  if ( !mDataProvider )
4139  {
4140  return results;
4141  }
4142 
4143  QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
4144  switch ( origin )
4145  {
4147  return results;
4148 
4149  case QgsFields::OriginProvider: //a provider field
4150  {
4151  results = mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
4152 
4153  if ( mEditBuffer )
4154  {
4155  QgsFeatureMap added = mEditBuffer->addedFeatures();
4156  QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4157  while ( addedIt.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
4158  {
4159  addedIt.next();
4160  QVariant v = addedIt.value().attribute( index );
4161  if ( v.isValid() )
4162  {
4163  QString vs = v.toString();
4164  if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
4165  {
4166  results << vs;
4167  }
4168  }
4169  }
4170 
4171  QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4172  while ( it.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
4173  {
4174  it.next();
4175  QVariant v = it.value().value( index );
4176  if ( v.isValid() )
4177  {
4178  QString vs = v.toString();
4179  if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
4180  {
4181  results << vs;
4182  }
4183  }
4184  }
4185  }
4186 
4187  return results;
4188  }
4189 
4190  case QgsFields::OriginEdit:
4191  // the layer is editable, but in certain cases it can still be avoided going through all features
4192  if ( mEditBuffer->mDeletedFeatureIds.isEmpty() &&
4193  mEditBuffer->mAddedFeatures.isEmpty() &&
4194  !mEditBuffer->mDeletedAttributeIds.contains( index ) &&
4195  mEditBuffer->mChangedAttributeValues.isEmpty() )
4196  {
4197  return mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
4198  }
4199  FALLTHROUGH
4200  //we need to go through each feature
4201  case QgsFields::OriginJoin:
4203  {
4204  QgsAttributeList attList;
4205  attList << index;
4206 
4207  QgsFeatureRequest request;
4208  request.setSubsetOfAttributes( attList );
4210  QString fieldName = mFields.at( index ).name();
4211  request.setFilterExpression( QStringLiteral( "\"%1\" ILIKE '%%2%'" ).arg( fieldName, substring ) );
4212  QgsFeatureIterator fit = getFeatures( request );
4213 
4214  QgsFeature f;
4215  QString currentValue;
4216  while ( fit.nextFeature( f ) )
4217  {
4218  currentValue = f.attribute( index ).toString();
4219  if ( !results.contains( currentValue ) )
4220  results << currentValue;
4221 
4222  if ( ( limit >= 0 && results.size() >= limit ) || ( feedback && feedback->isCanceled() ) )
4223  {
4224  break;
4225  }
4226  }
4227 
4228  return results;
4229  }
4230  }
4231 
4232  Q_ASSERT_X( false, "QgsVectorLayer::uniqueStringsMatching()", "Unknown source of the field!" );
4233  return results;
4234 }
4235 
4236 QVariant QgsVectorLayer::minimumValue( int index ) const
4237 {
4238  return minimumOrMaximumValue( index, true );
4239 }
4240 
4241 QVariant QgsVectorLayer::maximumValue( int index ) const
4242 {
4243  return minimumOrMaximumValue( index, false );
4244 }
4245 
4246 QVariant QgsVectorLayer::minimumOrMaximumValue( int index, bool minimum ) const
4247 {
4248  if ( !mDataProvider )
4249  {
4250  return QVariant();
4251  }
4252 
4253  QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
4254 
4255  switch ( origin )
4256  {
4258  return QVariant();
4259 
4260  case QgsFields::OriginProvider: //a provider field
4261  {
4262  QVariant val = minimum ? mDataProvider->minimumValue( index ) : mDataProvider->maximumValue( index );
4263  if ( mEditBuffer )
4264  {
4265  QgsFeatureMap added = mEditBuffer->addedFeatures();
4266  QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4267  while ( addedIt.hasNext() )
4268  {
4269  addedIt.next();
4270  QVariant v = addedIt.value().attribute( index );
4271  if ( ( v.isValid() && minimum && qgsVariantLessThan( v, val ) )
4272  || ( v.isValid() && !minimum && qgsVariantGreaterThan( v, val ) ) )
4273  {
4274  val = v;
4275  }
4276  }
4277 
4278  QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4279  while ( it.hasNext() )
4280  {
4281  it.next();
4282  QVariant v = it.value().value( index );
4283  if ( ( v.isValid() && minimum && qgsVariantLessThan( v, val ) )
4284  || ( v.isValid() && !minimum && qgsVariantGreaterThan( v, val ) ) )
4285  {
4286  val = v;
4287  }
4288  }
4289  }
4290  return val;
4291  }
4292 
4293  case QgsFields::OriginEdit:
4294  {
4295  // the layer is editable, but in certain cases it can still be avoided going through all features
4296  if ( mEditBuffer->mDeletedFeatureIds.isEmpty() &&
4297  mEditBuffer->mAddedFeatures.isEmpty() &&
4298  !mEditBuffer->mDeletedAttributeIds.contains( index ) &&
4299  mEditBuffer->mChangedAttributeValues.isEmpty() )
4300  {
4301  return minimum ? mDataProvider->minimumValue( index ) : mDataProvider->maximumValue( index );
4302  }
4303  }
4304  FALLTHROUGH
4305  // no choice but to go through all features
4307  case QgsFields::OriginJoin:
4308  {
4309  // we need to go through each feature
4310  QgsAttributeList attList;
4311  attList << index;
4312 
4315  .setSubsetOfAttributes( attList ) );
4316 
4317  QgsFeature f;
4318  QVariant value;
4319  QVariant currentValue;
4320  bool firstValue = true;
4321  while ( fit.nextFeature( f ) )
4322  {
4323  currentValue = f.attribute( index );
4324  if ( currentValue.isNull() )
4325  continue;
4326  if ( firstValue )
4327  {
4328  value = currentValue;
4329  firstValue = false;
4330  }
4331  else
4332  {
4333  if ( ( minimum && qgsVariantLessThan( currentValue, value ) ) || ( !minimum && qgsVariantGreaterThan( currentValue, value ) ) )
4334  {
4335  value = currentValue;
4336  }
4337  }
4338  }
4339  return value;
4340  }
4341  }
4342 
4343  Q_ASSERT_X( false, "QgsVectorLayer::minimumOrMaximum()", "Unknown source of the field!" );
4344  return QVariant();
4345 }
4346 
4347 QVariant QgsVectorLayer::aggregate( QgsAggregateCalculator::Aggregate aggregate, const QString &fieldOrExpression,
4349  bool *ok, QgsFeatureIds *fids ) const
4350 {
4351  if ( ok )
4352  *ok = false;
4353 
4354  if ( !mDataProvider )
4355  {
4356  return QVariant();
4357  }
4358 
4359  // test if we are calculating based on a field
4360  int attrIndex = mFields.lookupField( fieldOrExpression );
4361  if ( attrIndex >= 0 )
4362  {
4363  // aggregate is based on a field - if it's a provider field, we could possibly hand over the calculation
4364  // to the provider itself
4365  QgsFields::FieldOrigin origin = mFields.fieldOrigin( attrIndex );
4366  if ( origin == QgsFields::OriginProvider )
4367  {
4368  bool providerOk = false;
4369  QVariant val = mDataProvider->aggregate( aggregate, attrIndex, parameters, context, providerOk, fids );
4370  if ( providerOk )
4371  {
4372  // provider handled calculation
4373  if ( ok )
4374  *ok = true;
4375  return val;
4376  }
4377  }
4378  }
4379 
4380  // fallback to using aggregate calculator to determine aggregate
4381  QgsAggregateCalculator c( this );
4382  if ( fids )
4383  c.setFidsFilter( *fids );
4384  c.setParameters( parameters );
4385  return c.calculate( aggregate, fieldOrExpression, context, ok );
4386 }
4387 
4388 void QgsVectorLayer::setFeatureBlendMode( QPainter::CompositionMode featureBlendMode )
4389 {
4390  if ( mFeatureBlendMode == featureBlendMode )
4391  return;
4392 
4393  mFeatureBlendMode = featureBlendMode;
4395  emit styleChanged();
4396 }
4397 
4398 QPainter::CompositionMode QgsVectorLayer::featureBlendMode() const
4399 {
4400  return mFeatureBlendMode;
4401 }
4402 
4403 void QgsVectorLayer::readSldLabeling( const QDomNode &node )
4404 {
4405  setLabeling( nullptr ); // start with no labeling
4406  setLabelsEnabled( false );
4407 
4408  QDomElement element = node.toElement();
4409  if ( element.isNull() )
4410  return;
4411 
4412  QDomElement userStyleElem = element.firstChildElement( QStringLiteral( "UserStyle" ) );
4413  if ( userStyleElem.isNull() )
4414  {
4415  QgsDebugMsgLevel( QStringLiteral( "Info: UserStyle element not found." ), 4 );
4416  return;
4417  }
4418 
4419  QDomElement featTypeStyleElem = userStyleElem.firstChildElement( QStringLiteral( "FeatureTypeStyle" ) );
4420  if ( featTypeStyleElem.isNull() )
4421  {
4422  QgsDebugMsgLevel( QStringLiteral( "Info: FeatureTypeStyle element not found." ), 4 );
4423  return;
4424  }
4425 
4426  // create empty FeatureTypeStyle element to merge TextSymbolizer's Rule's from all FeatureTypeStyle's
4427  QDomElement mergedFeatTypeStyle = featTypeStyleElem.cloneNode( false ).toElement();
4428 
4429  // use the RuleRenderer when more rules are present or the rule
4430  // has filters or min/max scale denominators set,
4431  // otherwise use the Simple labeling
4432  bool needRuleBasedLabeling = false;
4433  int ruleCount = 0;
4434 
4435  while ( !featTypeStyleElem.isNull() )
4436  {
4437  QDomElement ruleElem = featTypeStyleElem.firstChildElement( QStringLiteral( "Rule" ) );
4438  while ( !ruleElem.isNull() )
4439  {
4440  // test rule children element to check if we need to create RuleRenderer
4441  // and if the rule has a symbolizer
4442  bool hasTextSymbolizer = false;
4443  bool hasRuleBased = false;
4444  QDomElement ruleChildElem = ruleElem.firstChildElement();
4445  while ( !ruleChildElem.isNull() )
4446  {
4447  // rule has filter or min/max scale denominator, use the RuleRenderer
4448  if ( ruleChildElem.localName() == QLatin1String( "Filter" ) ||
4449  ruleChildElem.localName() == QLatin1String( "MinScaleDenominator" ) ||
4450  ruleChildElem.localName() == QLatin1String( "MaxScaleDenominator" ) )
4451  {
4452  hasRuleBased = true;
4453  }
4454  // rule has a renderer symbolizer, not a text symbolizer
4455  else if ( ruleChildElem.localName() == QLatin1String( "TextSymbolizer" ) )
4456  {
4457  QgsDebugMsgLevel( QStringLiteral( "Info: TextSymbolizer element found" ), 4 );
4458  hasTextSymbolizer = true;
4459  }
4460 
4461  ruleChildElem = ruleChildElem.nextSiblingElement();
4462  }
4463 
4464  if ( hasTextSymbolizer )
4465  {
4466  ruleCount++;
4467 
4468  // append a clone of all Rules to the merged FeatureTypeStyle element
4469  mergedFeatTypeStyle.appendChild( ruleElem.cloneNode().toElement() );
4470 
4471  if ( hasRuleBased )
4472  {
4473  QgsDebugMsgLevel( QStringLiteral( "Info: Filter or Min/MaxScaleDenominator element found: need a RuleBasedLabeling" ), 4 );
4474  needRuleBasedLabeling = true;
4475  }
4476  }
4477 
4478  // more rules present, use the RuleRenderer
4479  if ( ruleCount > 1 )
4480  {
4481  QgsDebugMsgLevel( QStringLiteral( "Info: More Rule elements found: need a RuleBasedLabeling" ), 4 );
4482  needRuleBasedLabeling = true;
4483  }
4484 
4485  // not use the rule based labeling if no rules with textSymbolizer
4486  if ( ruleCount == 0 )
4487  {
4488  needRuleBasedLabeling = false;
4489  }
4490 
4491  ruleElem = ruleElem.nextSiblingElement( QStringLiteral( "Rule" ) );
4492  }
4493  featTypeStyleElem = featTypeStyleElem.nextSiblingElement( QStringLiteral( "FeatureTypeStyle" ) );
4494  }
4495 
4496  if ( ruleCount == 0 )
4497  {
4498  QgsDebugMsgLevel( QStringLiteral( "Info: No TextSymbolizer element." ), 4 );
4499  return;
4500  }
4501 
4502  QDomElement ruleElem = mergedFeatTypeStyle.firstChildElement( QStringLiteral( "Rule" ) );
4503 
4504  if ( needRuleBasedLabeling )
4505  {
4506  QgsDebugMsgLevel( QStringLiteral( "Info: rule based labeling" ), 4 );
4507  QgsRuleBasedLabeling::Rule *rootRule = new QgsRuleBasedLabeling::Rule( nullptr );
4508  while ( !ruleElem.isNull() )
4509  {
4510 
4511  QString label, description, filterExp;
4512  int scaleMinDenom = 0, scaleMaxDenom = 0;
4513  QgsPalLayerSettings settings;
4514 
4515  // retrieve the Rule element child nodes
4516  QDomElement childElem = ruleElem.firstChildElement();
4517  while ( !childElem.isNull() )
4518  {
4519  if ( childElem.localName() == QLatin1String( "Name" ) )
4520  {
4521  // <se:Name> tag contains the rule identifier,
4522  // so prefer title tag for the label property value
4523  if ( label.isEmpty() )
4524  label = childElem.firstChild().nodeValue();
4525  }
4526  else if ( childElem.localName() == QLatin1String( "Description" ) )
4527  {
4528  // <se:Description> can contains a title and an abstract
4529  QDomElement titleElem = childElem.firstChildElement( QStringLiteral( "Title" ) );
4530  if ( !titleElem.isNull() )
4531  {
4532  label = titleElem.firstChild().nodeValue();
4533  }
4534 
4535  QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( "Abstract" ) );
4536  if ( !abstractElem.isNull() )
4537  {
4538  description = abstractElem.firstChild().nodeValue();
4539  }
4540  }
4541  else if ( childElem.localName() == QLatin1String( "Abstract" ) )
4542  {
4543  // <sld:Abstract> (v1.0)
4544  description = childElem.firstChild().nodeValue();
4545  }
4546  else if ( childElem.localName() == QLatin1String( "Title" ) )
4547  {
4548  // <sld:Title> (v1.0)
4549  label = childElem.firstChild().nodeValue();
4550  }
4551  else if ( childElem.localName() == QLatin1String( "Filter" ) )
4552  {
4553  QgsExpression *filter = QgsOgcUtils::expressionFromOgcFilter( childElem );
4554  if ( filter )
4555  {
4556  if ( filter->hasParserError() )
4557  {
4558  QgsDebugMsgLevel( QStringLiteral( "SLD Filter parsing error: %1" ).arg( filter->parserErrorString() ), 3 );
4559  }
4560  else
4561  {
4562  filterExp = filter->expression();
4563  }
4564  delete filter;
4565  }
4566  }
4567  else if ( childElem.localName() == QLatin1String( "MinScaleDenominator" ) )
4568  {
4569  bool ok;
4570  int v = childElem.firstChild().nodeValue().toInt( &ok );
4571  if ( ok )
4572  scaleMinDenom = v;
4573  }
4574  else if ( childElem.localName() == QLatin1String( "MaxScaleDenominator" ) )
4575  {
4576  bool ok;
4577  int v = childElem.firstChild().nodeValue().toInt( &ok );
4578  if ( ok )
4579  scaleMaxDenom = v;
4580  }
4581  else if ( childElem.localName() == QLatin1String( "TextSymbolizer" ) )
4582  {
4583  readSldTextSymbolizer( childElem, settings );
4584  }
4585 
4586  childElem = childElem.nextSiblingElement();
4587  }
4588 
4589  QgsRuleBasedLabeling::Rule *ruleLabeling = new QgsRuleBasedLabeling::Rule( new QgsPalLayerSettings( settings ), scaleMinDenom, scaleMaxDenom, filterExp, label );
4590  rootRule->appendChild( ruleLabeling );
4591 
4592  ruleElem = ruleElem.nextSiblingElement();
4593  }
4594 
4595  setLabeling( new QgsRuleBasedLabeling( rootRule ) );
4596  setLabelsEnabled( true );
4597  }
4598  else
4599  {
4600  QgsDebugMsgLevel( QStringLiteral( "Info: simple labeling" ), 4 );
4601  // retrieve the TextSymbolizer element child node
4602  QDomElement textSymbolizerElem = ruleElem.firstChildElement( QStringLiteral( "TextSymbolizer" ) );
4604  if ( readSldTextSymbolizer( textSymbolizerElem, s ) )
4605  {
4607  setLabelsEnabled( true );
4608  }
4609  }
4610 }
4611 
4612 bool QgsVectorLayer::readSldTextSymbolizer( const QDomNode &node, QgsPalLayerSettings &settings ) const
4613 {
4614  if ( node.localName() != QLatin1String( "TextSymbolizer" ) )
4615  {
4616  QgsDebugMsgLevel( QStringLiteral( "Not a TextSymbolizer element: %1" ).arg( node.localName() ), 3 );
4617  return false;
4618  }
4619  QDomElement textSymbolizerElem = node.toElement();
4620  // Label
4621  QDomElement labelElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Label" ) );
4622  if ( !labelElem.isNull() )
4623  {
4624  QDomElement propertyNameElem = labelElem.firstChildElement( QStringLiteral( "PropertyName" ) );
4625  if ( !propertyNameElem.isNull() )
4626  {
4627  // set labeling defaults
4628 
4629  // label attribute
4630  QString labelAttribute = propertyNameElem.text();
4631  settings.fieldName = labelAttribute;
4632  settings.isExpression = false;
4633 
4634  int fieldIndex = mFields.lookupField( labelAttribute );
4635  if ( fieldIndex == -1 )
4636  {
4637  // label attribute is not in columns, check if it is an expression
4638  QgsExpression exp( labelAttribute );
4639  if ( !exp.hasEvalError() )
4640  {
4641  settings.isExpression = true;
4642  }
4643  else
4644  {
4645  QgsDebugMsgLevel( QStringLiteral( "SLD label attribute error: %1" ).arg( exp.evalErrorString() ), 3 );
4646  }
4647  }
4648  }
4649  else
4650  {
4651  QgsDebugMsgLevel( QStringLiteral( "Info: PropertyName element not found." ), 4 );
4652  return false;
4653  }
4654  }
4655  else
4656  {
4657  QgsDebugMsgLevel( QStringLiteral( "Info: Label element not found." ), 4 );
4658  return false;
4659  }
4660 
4662  if ( textSymbolizerElem.hasAttribute( QStringLiteral( "uom" ) ) )
4663  {
4664  sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( textSymbolizerElem.attribute( QStringLiteral( "uom" ) ) );
4665  }
4666 
4667  QString fontFamily = QStringLiteral( "Sans-Serif" );
4668  int fontPointSize = 10;
4670  int fontWeight = -1;
4671  bool fontItalic = false;
4672  bool fontUnderline = false;
4673 
4674  // Font
4675  QDomElement fontElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Font" ) );
4676  if ( !fontElem.isNull() )
4677  {
4678  QgsStringMap fontSvgParams = QgsSymbolLayerUtils::getSvgParameterList( fontElem );
4679  for ( QgsStringMap::iterator it = fontSvgParams.begin(); it != fontSvgParams.end(); ++it )
4680  {
4681  QgsDebugMsgLevel( QStringLiteral( "found fontSvgParams %1: %2" ).arg( it.key(), it.value() ), 4 );
4682 
4683  if ( it.key() == QLatin1String( "font-family" ) )
4684  {
4685  fontFamily = it.value();
4686  }
4687  else if ( it.key() == QLatin1String( "font-style" ) )
4688  {
4689  fontItalic = ( it.value() == QLatin1String( "italic" ) ) || ( it.value() == QLatin1String( "Italic" ) );
4690  }
4691  else if ( it.key() == QLatin1String( "font-size" ) )
4692  {
4693  bool ok;
4694  int fontSize = it.value().toInt( &ok );
4695  if ( ok )
4696  {
4697  fontPointSize = fontSize;
4698  fontUnitSize = sldUnitSize;
4699  }
4700  }
4701  else if ( it.key() == QLatin1String( "font-weight" ) )
4702  {
4703  if ( ( it.value() == QLatin1String( "bold" ) ) || ( it.value() == QLatin1String( "Bold" ) ) )
4704  fontWeight = QFont::Bold;
4705  }
4706  else if ( it.key() == QLatin1String( "font-underline" ) )
4707  {
4708  fontUnderline = ( it.value() == QLatin1String( "underline" ) ) || ( it.value() == QLatin1String( "Underline" ) );
4709  }
4710  }
4711  }
4712 
4713  QgsTextFormat format;
4714  QFont font( fontFamily, fontPointSize, fontWeight, fontItalic );
4715  font.setUnderline( fontUnderline );
4716  format.setFont( font );
4717  format.setSize( fontPointSize );
4718  format.setSizeUnit( fontUnitSize );
4719 
4720  // Fill
4721  QDomElement fillElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Fill" ) );
4722  QColor textColor;
4723  Qt::BrushStyle textBrush = Qt::SolidPattern;
4724  QgsSymbolLayerUtils::fillFromSld( fillElem, textBrush, textColor );
4725  if ( textColor.isValid() )
4726  {
4727  QgsDebugMsgLevel( QStringLiteral( "Info: textColor %1." ).arg( QVariant( textColor ).toString() ), 4 );
4728  format.setColor( textColor );
4729  }
4730 
4731  QgsTextBufferSettings bufferSettings;
4732 
4733  // Halo
4734  QDomElement haloElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Halo" ) );
4735  if ( !haloElem.isNull() )
4736  {
4737  bufferSettings.setEnabled( true );
4738  bufferSettings.setSize( 1 );
4739 
4740  QDomElement radiusElem = haloElem.firstChildElement( QStringLiteral( "Radius" ) );
4741  if ( !radiusElem.isNull() )
4742  {
4743  bool ok;
4744  double bufferSize = radiusElem.text().toDouble( &ok );
4745  if ( ok )
4746  {
4747  bufferSettings.setSize( bufferSize );
4748  bufferSettings.setSizeUnit( sldUnitSize );
4749  }
4750  }
4751 
4752  QDomElement haloFillElem = haloElem.firstChildElement( QStringLiteral( "Fill" ) );
4753  QColor bufferColor;
4754  Qt::BrushStyle bufferBrush = Qt::SolidPattern;
4755  QgsSymbolLayerUtils::fillFromSld( haloFillElem, bufferBrush, bufferColor );
4756  if ( bufferColor.isValid() )
4757  {
4758  QgsDebugMsgLevel( QStringLiteral( "Info: bufferColor %1." ).arg( QVariant( bufferColor ).toString() ), 4 );
4759  bufferSettings.setColor( bufferColor );
4760  }
4761  }
4762 
4763  // LabelPlacement
4764  QDomElement labelPlacementElem = textSymbolizerElem.firstChildElement( QStringLiteral( "LabelPlacement" ) );
4765  if ( !labelPlacementElem.isNull() )
4766  {
4767  // PointPlacement
4768  QDomElement pointPlacementElem = labelPlacementElem.firstChildElement( QStringLiteral( "PointPlacement" ) );
4769  if ( !pointPlacementElem.isNull() )
4770  {
4773  {
4775  }
4776 
4777  QDomElement displacementElem = pointPlacementElem.firstChildElement( QStringLiteral( "Displacement" ) );
4778  if ( !displacementElem.isNull() )
4779  {
4780  QDomElement displacementXElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementX" ) );
4781  if ( !displacementXElem.isNull() )
4782  {
4783  bool ok;
4784  double xOffset = displacementXElem.text().toDouble( &ok );
4785  if ( ok )
4786  {
4787  settings.xOffset = xOffset;
4788  settings.offsetUnits = sldUnitSize;
4789  }
4790  }
4791  QDomElement displacementYElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementY" ) );
4792  if ( !displacementYElem.isNull() )
4793  {
4794  bool ok;
4795  double yOffset = displacementYElem.text().toDouble( &ok );
4796  if ( ok )
4797  {
4798  settings.yOffset = yOffset;
4799  settings.offsetUnits = sldUnitSize;
4800  }
4801  }
4802  }
4803  QDomElement anchorPointElem = pointPlacementElem.firstChildElement( QStringLiteral( "AnchorPoint" ) );
4804  if ( !anchorPointElem.isNull() )
4805  {
4806  QDomElement anchorPointXElem = anchorPointElem.firstChildElement( QStringLiteral( "AnchorPointX" ) );
4807  if ( !anchorPointXElem.isNull() )
4808  {
4809  bool ok;
4810  double xOffset = anchorPointXElem.text().toDouble( &ok );
4811  if ( ok )
4812  {
4813  settings.xOffset = xOffset;
4814  settings.offsetUnits = sldUnitSize;
4815  }
4816  }
4817  QDomElement anchorPointYElem = anchorPointElem.firstChildElement( QStringLiteral( "AnchorPointY" ) );
4818  if ( !anchorPointYElem.isNull() )
4819  {
4820  bool ok;
4821  double yOffset = anchorPointYElem.text().toDouble( &ok );
4822  if ( ok )
4823  {
4824  settings.yOffset = yOffset;
4825  settings.offsetUnits = sldUnitSize;
4826  }
4827  }
4828  }
4829 
4830  QDomElement rotationElem = pointPlacementElem.firstChildElement( QStringLiteral( "Rotation" ) );
4831  if ( !rotationElem.isNull() )
4832  {
4833  bool ok;
4834  double rotation = rotationElem.text().toDouble( &ok );
4835  if ( ok )
4836  {
4837  settings.angleOffset = 360 - rotation;
4838  }
4839  }
4840  }
4841  else
4842  {
4843  // PointPlacement
4844  QDomElement linePlacementElem = labelPlacementElem.firstChildElement( QStringLiteral( "LinePlacement" ) );
4845  if ( !linePlacementElem.isNull() )
4846  {
4848  }
4849  }
4850  }
4851 
4852  // read vendor options
4853  QgsStringMap vendorOptions;
4854  QDomElement vendorOptionElem = textSymbolizerElem.firstChildElement( QStringLiteral( "VendorOption" ) );
4855  while ( !vendorOptionElem.isNull() && vendorOptionElem.localName() == QLatin1String( "VendorOption" ) )
4856  {
4857  QString optionName = vendorOptionElem.attribute( QStringLiteral( "name" ) );
4858  QString optionValue;
4859  if ( vendorOptionElem.firstChild().nodeType() == QDomNode::TextNode )
4860  {
4861  optionValue = vendorOptionElem.firstChild().nodeValue();
4862  }
4863  else
4864  {
4865  if ( vendorOptionElem.firstChild().nodeType() == QDomNode::ElementNode &&
4866  vendorOptionElem.firstChild().localName() == QLatin1String( "Literal" ) )
4867  {
4868  QgsDebugMsg( vendorOptionElem.firstChild().localName() );
4869  optionValue = vendorOptionElem.firstChild().firstChild().nodeValue();
4870  }
4871  else
4872  {
4873  QgsDebugMsg( QStringLiteral( "unexpected child of %1 named %2" ).arg( vendorOptionElem.localName(), optionName ) );
4874  }
4875  }
4876 
4877  if ( !optionName.isEmpty() && !optionValue.isEmpty() )
4878  {
4879  vendorOptions[ optionName ] = optionValue;
4880  }
4881 
4882  vendorOptionElem = vendorOptionElem.nextSiblingElement();
4883  }
4884  if ( !vendorOptions.isEmpty() )
4885  {
4886  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
4887  {
4888  if ( it.key() == QLatin1String( "underlineText" ) && it.value() == QLatin1String( "true" ) )
4889  {
4890  font.setUnderline( true );
4891  format.setFont( font );
4892  }
4893  else if ( it.key() == QLatin1String( "strikethroughText" ) && it.value() == QLatin1String( "true" ) )
4894  {
4895  font.setStrikeOut( true );
4896  format.setFont( font );
4897  }
4898  else if ( it.key() == QLatin1String( "maxDisplacement" ) )
4899  {
4901  }
4902  else if ( it.key() == QLatin1String( "followLine" ) && it.value() == QLatin1String( "true" ) )
4903  {
4905  {
4907  }
4908  else
4909  {
4911  }
4912  }
4913  else if ( it.key() == QLatin1String( "maxAngleDelta" ) )
4914  {
4915  bool ok;
4916  double angle = it.value().toDouble( &ok );
4917  if ( ok )
4918  {
4919  settings.maxCurvedCharAngleIn = angle;
4920  settings.maxCurvedCharAngleOut = angle;
4921  }
4922  }
4923  // miscellaneous options
4924  else if ( it.key() == QLatin1String( "conflictResolution" ) && it.value() == QLatin1String( "false" ) )
4925  {
4926  settings.displayAll = true;
4927  }
4928  else if ( it.key() == QLatin1String( "forceLeftToRight" ) && it.value() == QLatin1String( "false" ) )
4929  {
4931  }
4932  else if ( it.key() == QLatin1String( "group" ) && it.value() == QLatin1String( "yes" ) )
4933  {
4934  settings.lineSettings().setMergeLines( true );
4935  }
4936  else if ( it.key() == QLatin1String( "labelAllGroup" ) && it.value() == QLatin1String( "true" ) )
4937  {
4938  settings.lineSettings().setMergeLines( true );
4939  }
4940  }
4941  }
4942 
4943  format.setBuffer( bufferSettings );
4944  settings.setFormat( format );
4945  return true;
4946 }
4947 
4948 QgsEditFormConfig QgsVectorLayer::editFormConfig() const
4949 {
4950  return mEditFormConfig;
4951 }
4952 
4953 void QgsVectorLayer::setEditFormConfig( const QgsEditFormConfig &editFormConfig )
4954 {
4955  if ( mEditFormConfig == editFormConfig )
4956  return;
4957 
4958  mEditFormConfig = editFormConfig;
4959  mEditFormConfig.onRelationsLoaded();
4960  emit editFormConfigChanged();
4961 }
4962 
4964 {
4965  return mMapTipTemplate;
4966 }
4967 
4968 void QgsVectorLayer::setMapTipTemplate( const QString &mapTip )
4969 {
4970  if ( mMapTipTemplate == mapTip )
4971  return;
4972 
4973  mMapTipTemplate = mapTip;
4974  emit mapTipTemplateChanged();
4975 }
4976 
4978 {
4979  QgsAttributeTableConfig config = mAttributeTableConfig;
4980 
4981  if ( config.isEmpty() )
4982  config.update( fields() );
4983 
4984  return config;
4985 }
4986 
4988 {
4989  if ( mAttributeTableConfig != attributeTableConfig )
4990  {
4991  mAttributeTableConfig = attributeTableConfig;
4992  emit configChanged();
4993  }
4994 }
4995 
4997 {
4999 }
5000 
5002 {
5004 }
5005 
5007 {
5008  if ( !mDiagramLayerSettings )
5009  mDiagramLayerSettings = new QgsDiagramLayerSettings();
5010  *mDiagramLayerSettings = s;
5011 }
5012 
5014 {
5015  QgsLayerMetadataFormatter htmlFormatter( metadata() );
5016  QString myMetadata = QStringLiteral( "<html>\n<body>\n" );
5017 
5018  // Begin Provider section
5019  myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
5020  myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
5021 
5022  // name
5023  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + name() + QStringLiteral( "</td></tr>\n" );
5024 
5025  // local path
5026  QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( mProviderKey, publicSource() );
5027  QString path;
5028  bool isLocalPath = false;
5029  if ( uriComponents.contains( QStringLiteral( "path" ) ) )
5030  {
5031  path = uriComponents[QStringLiteral( "path" )].toString();
5032  if ( QFile::exists( path ) )
5033  {
5034  isLocalPath = true;
5035  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" );
5036  }
5037  }
5038  if ( uriComponents.contains( QStringLiteral( "url" ) ) )
5039  {
5040  const QString url = uriComponents[QStringLiteral( "url" )].toString();
5041  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" );
5042  }
5043 
5044  // data source
5045  if ( publicSource() != path || !isLocalPath )
5046  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( publicSource() != path ? publicSource() : path ) + QStringLiteral( "</td></tr>\n" );
5047 
5048  // storage type
5049  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Storage" ) + QStringLiteral( "</td><td>" ) + storageType() + QStringLiteral( "</td></tr>\n" );
5050 
5051  // comment
5052  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Comment" ) + QStringLiteral( "</td><td>" ) + dataComment() + QStringLiteral( "</td></tr>\n" );
5053 
5054  // encoding
5055  const QgsVectorDataProvider *provider = dataProvider();
5056  if ( provider )
5057  {
5058  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Encoding" ) + QStringLiteral( "</td><td>" ) + provider->encoding() + QStringLiteral( "</td></tr>\n" );
5059  }
5060 
5061  if ( isSpatial() )
5062  {
5063  // geom type
5065  if ( type < 0 || type > QgsWkbTypes::NullGeometry )
5066  {
5067  QgsDebugMsgLevel( QStringLiteral( "Invalid vector type" ), 2 );
5068  }
5069  else
5070  {
5071  QString typeString( QStringLiteral( "%1 (%2)" ).arg( QgsWkbTypes::geometryDisplayString( geometryType() ),
5073  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Geometry" ) + QStringLiteral( "</td><td>" ) + typeString + QStringLiteral( "</td></tr>\n" );
5074  }
5075 
5076  // EPSG
5077  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "CRS" ) + QStringLiteral( "</td><td>" );
5078  if ( crs().isValid() )
5079  {
5080  myMetadata += crs().userFriendlyIdentifier( QgsCoordinateReferenceSystem::FullString ) + QStringLiteral( " - " );
5081  if ( crs().isGeographic() )
5082  myMetadata += tr( "Geographic" );
5083  else
5084  myMetadata += tr( "Projected" );
5085  }
5086  myMetadata += QLatin1String( "</td></tr>\n" );
5087 
5088  // Extent
5089  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
5090 
5091  // unit
5092  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Unit" ) + QStringLiteral( "</td><td>" ) + QgsUnitTypes::toString( crs().mapUnits() ) + QStringLiteral( "</td></tr>\n" );
5093 
5094  }
5095 
5096  // feature count
5097  QLocale locale = QLocale();
5098  locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
5099  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
5100  + tr( "Feature count" ) + QStringLiteral( "</td><td>" )
5101  + ( featureCount() == -1 ? tr( "unknown" ) : locale.toString( static_cast<qlonglong>( featureCount() ) ) )
5102  + QStringLiteral( "</td></tr>\n" );
5103 
5104  // End Provider section
5105  myMetadata += QLatin1String( "</table>\n<br><br>" );
5106 
5107  // identification section
5108  myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
5109  myMetadata += htmlFormatter.identificationSectionHtml( );
5110  myMetadata += QLatin1String( "<br><br>\n" );
5111 
5112  // extent section
5113  myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
5114  myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
5115  myMetadata += QLatin1String( "<br><br>\n" );
5116 
5117  // Start the Access section
5118  myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
5119  myMetadata += htmlFormatter.accessSectionHtml( );
5120  myMetadata += QLatin1String( "<br><br>\n" );
5121 
5122  // Fields section
5123  myMetadata += QStringLiteral( "<h1>" ) + tr( "Fields" ) + QStringLiteral( "</h1>\n<hr>\n<table class=\"list-view\">\n" );
5124 
5125  // primary key
5126  QgsAttributeList pkAttrList = primaryKeyAttributes();
5127  if ( !pkAttrList.isEmpty() )
5128  {
5129  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Primary key attributes" ) + QStringLiteral( "</td><td>" );
5130  const auto constPkAttrList = pkAttrList;
5131  for ( int idx : constPkAttrList )
5132  {
5133  myMetadata += fields().at( idx ).name() + ' ';
5134  }
5135  myMetadata += QLatin1String( "</td></tr>\n" );
5136  }
5137 
5138  const QgsFields myFields = fields();
5139 
5140  // count fields
5141  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Count" ) + QStringLiteral( "</td><td>" ) + QString::number( myFields.size() ) + QStringLiteral( "</td></tr>\n" );
5142 
5143  myMetadata += QLatin1String( "</table>\n<br><table width=\"100%\" class=\"tabular-view\">\n" );
5144  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" );
5145 
5146  for ( int i = 0; i < myFields.size(); ++i )
5147  {
5148  QgsField myField = myFields.at( i );
5149  QString rowClass;
5150  if ( i % 2 )
5151  rowClass = QStringLiteral( "class=\"odd-row\"" );
5152  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" );
5153  }
5154 
5155  //close field list
5156  myMetadata += QLatin1String( "</table>\n<br><br>" );
5157 
5158  // Start the contacts section
5159  myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
5160  myMetadata += htmlFormatter.contactsSectionHtml( );
5161  myMetadata += QLatin1String( "<br><br>\n" );
5162 
5163  // Start the links section
5164  myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
5165  myMetadata += htmlFormatter.linksSectionHtml( );
5166  myMetadata += QLatin1String( "<br><br>\n" );
5167 
5168  // Start the history section
5169  myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
5170  myMetadata += htmlFormatter.historySectionHtml( );
5171  myMetadata += QLatin1String( "<br><br>\n" );
5172 
5173  myMetadata += QLatin1String( "\n</body>\n</html>\n" );
5174  return myMetadata;
5175 }
5176 
5177 void QgsVectorLayer::invalidateSymbolCountedFlag()
5178 {
5179  mSymbolFeatureCounted = false;
5180 }
5181 
5182 void QgsVectorLayer::onFeatureCounterCompleted()
5183 {
5184  onSymbolsCounted();
5185  mFeatureCounter = nullptr;
5186 }
5187 
5188 void QgsVectorLayer::onFeatureCounterTerminated()
5189 {
5190  mFeatureCounter = nullptr;
5191 }
5192 
5193 void QgsVectorLayer::onJoinedFieldsChanged()
5194 {
5195  // some of the fields of joined layers have changed -> we need to update this layer's fields too
5196  updateFields();
5197 }
5198 
5199 void QgsVectorLayer::onFeatureDeleted( QgsFeatureId fid )
5200 {
5201  if ( mEditCommandActive )
5202  mDeletedFids << fid;
5203  else
5204  emit featuresDeleted( QgsFeatureIds() << fid );
5205 
5206  emit featureDeleted( fid );
5207 }
5208 
5209 void QgsVectorLayer::onRelationsLoaded()
5210 {
5211  mEditFormConfig.onRelationsLoaded();
5212 }
5213 
5214 void QgsVectorLayer::onSymbolsCounted()
5215 {
5216  if ( mFeatureCounter )
5217  {
5218  mSymbolFeatureCounted = true;
5219  mSymbolFeatureCountMap = mFeatureCounter->symbolFeatureCountMap();
5220  mSymbolFeatureIdMap = mFeatureCounter->symbolFeatureIdMap();
5222  }
5223 }
5224 
5225 QList<QgsRelation> QgsVectorLayer::referencingRelations( int idx ) const
5226 {
5227  return QgsProject::instance()->relationManager()->referencingRelations( this, idx );
5228 }
5229 
5230 QList<QgsWeakRelation> QgsVectorLayer::weakRelations() const
5231 {
5232  return mWeakRelations;
5233 }
5234 
5235 int QgsVectorLayer::listStylesInDatabase( QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError )
5236 {
5237  return QgsProviderRegistry::instance()->listStyles( mProviderKey, mDataSource, ids, names, descriptions, msgError );
5238 }
5239 
5240 QString QgsVectorLayer::getStyleFromDatabase( const QString &styleId, QString &msgError )
5241 {
5242  return QgsProviderRegistry::instance()->getStyleById( mProviderKey, mDataSource, styleId, msgError );
5243 }
5244 
5245 bool QgsVectorLayer::deleteStyleFromDatabase( const QString &styleId, QString &msgError )
5246 {
5247  return QgsProviderRegistry::instance()->deleteStyleById( mProviderKey, mDataSource, styleId, msgError );
5248 }
5249 
5250 
5251 void QgsVectorLayer::saveStyleToDatabase( const QString &name, const QString &description,
5252  bool useAsDefault, const QString &uiFileContent, QString &msgError )
5253 {
5254 
5255  QString sldStyle, qmlStyle;
5256  QDomDocument qmlDocument, sldDocument;
5257  QgsReadWriteContext context;
5258  exportNamedStyle( qmlDocument, msgError, context );
5259  if ( !msgError.isNull() )
5260  {
5261  return;
5262  }
5263  qmlStyle = qmlDocument.toString();
5264 
5265  this->exportSldStyle( sldDocument, msgError );
5266  if ( !msgError.isNull() )
5267  {
5268  return;
5269  }
5270  sldStyle = sldDocument.toString();
5271 
5273  mDataSource, qmlStyle, sldStyle, name,
5274  description, uiFileContent, useAsDefault, msgError );
5275 }
5276 
5277 
5278 
5279 QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &resultFlag, QgsMapLayer::StyleCategories categories )
5280 {
5281  return loadNamedStyle( theURI, resultFlag, false, categories );
5282 }
5283 
5284 bool QgsVectorLayer::loadAuxiliaryLayer( const QgsAuxiliaryStorage &storage, const QString &key )
5285 {
5286  bool rc = false;
5287 
5288  QString joinKey = mAuxiliaryLayerKey;
5289  if ( !key.isEmpty() )
5290  joinKey = key;
5291 
5292  if ( storage.isValid() && !joinKey.isEmpty() )
5293  {
5294  QgsAuxiliaryLayer *alayer = nullptr;
5295 
5296  int idx = fields().lookupField( joinKey );
5297 
5298  if ( idx >= 0 )
5299  {
5300  alayer = storage.createAuxiliaryLayer( fields().field( idx ), this );
5301 
5302  if ( alayer )
5303  {
5304  setAuxiliaryLayer( alayer );
5305  rc = true;
5306  }
5307  }
5308  }
5309 
5310  return rc;
5311 }
5312 
5314 {
5315  mAuxiliaryLayerKey.clear();
5316 
5317  if ( mAuxiliaryLayer )
5318  removeJoin( mAuxiliaryLayer->id() );
5319 
5320  if ( alayer )
5321  {
5322  addJoin( alayer->joinInfo() );
5323 
5324  if ( !alayer->isEditable() )
5325  alayer->startEditing();
5326 
5327  mAuxiliaryLayerKey = alayer->joinInfo().targetFieldName();
5328  }
5329 
5330  mAuxiliaryLayer.reset( alayer );
5331  if ( mAuxiliaryLayer )
5332  mAuxiliaryLayer->setParent( this );
5333  updateFields();
5334 }
5335 
5337 {
5338  return mAuxiliaryLayer.get();
5339 }
5340 
5342 {
5343  return mAuxiliaryLayer.get();
5344 }
5345 
5346 QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &resultFlag, bool loadFromLocalDB, QgsMapLayer::StyleCategories categories )
5347 {
5348  QgsDataSourceUri dsUri( theURI );
5349  QString returnMessage;
5350  QString qml, errorMsg;
5351  if ( !loadFromLocalDB && mDataProvider && mDataProvider->isSaveAndLoadStyleToDatabaseSupported() )
5352  {
5354  }
5355  if ( !qml.isEmpty() )
5356  {
5357  QDomDocument myDocument( QStringLiteral( "qgis" ) );
5358  myDocument.setContent( qml );
5359  resultFlag = importNamedStyle( myDocument, errorMsg );
5360  returnMessage = QObject::tr( "Loaded from Provider" );
5361  }
5362  else
5363  {
5364  returnMessage = QgsMapLayer::loadNamedStyle( theURI, resultFlag, categories );
5365  }
5366 
5367  if ( resultFlag )
5368  emit styleLoaded( categories );
5369 
5370  return returnMessage;
5371 }
5372 
5373 QSet<QgsMapLayerDependency> QgsVectorLayer::dependencies() const
5374 {
5375  if ( mDataProvider )
5376  return mDataProvider->dependencies() + mDependencies;
5377  return mDependencies;
5378 }
5379 
5380 void QgsVectorLayer::emitDataChanged()
5381 {
5382  if ( mDataChangedFired )
5383  return;
5384 
5385  updateExtents(); // reset cached extent to reflect data changes
5386 
5387  mDataChangedFired = true;
5388  emit dataChanged();
5389  mDataChangedFired = false;
5390 }
5391 
5392 void QgsVectorLayer::onAfterCommitChangesDependency()
5393 {
5394  mDataChangedFired = true;
5395  reload();
5396 }
5397 
5398 bool QgsVectorLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
5399 {
5400  QSet<QgsMapLayerDependency> deps;
5401  const auto constODeps = oDeps;
5402  for ( const QgsMapLayerDependency &dep : constODeps )
5403  {
5404  if ( dep.origin() == QgsMapLayerDependency::FromUser )
5405  deps << dep;
5406  }
5407 
5408  QSet<QgsMapLayerDependency> toAdd = deps - dependencies();
5409 
5410  // disconnect layers that are not present in the list of dependencies anymore
5411  for ( const QgsMapLayerDependency &dep : qgis::as_const( mDependencies ) )
5412  {
5413  QgsVectorLayer *lyr = static_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( dep.layerId() ) );
5414  if ( !lyr )
5415  continue;
5416  disconnect( lyr, &QgsVectorLayer::featureAdded, this, &QgsVectorLayer::emitDataChanged );
5417  disconnect( lyr, &QgsVectorLayer::featureDeleted, this, &QgsVectorLayer::emitDataChanged );
5418  disconnect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
5419  disconnect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );
5421  disconnect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::onAfterCommitChangesDependency );
5422  }
5423 
5424  // assign new dependencies
5425  if ( mDataProvider )
5426  mDependencies = mDataProvider->dependencies() + deps;
5427  else
5428  mDependencies = deps;
5429  emit dependenciesChanged();
5430 
5431  // connect to new layers
5432  for ( const QgsMapLayerDependency &dep : qgis::as_const( mDependencies ) )
5433  {
5434  QgsVectorLayer *lyr = static_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( dep.layerId() ) );
5435  if ( !lyr )
5436  continue;
5437  connect( lyr, &QgsVectorLayer::featureAdded, this, &QgsVectorLayer::emitDataChanged );
5438  connect( lyr, &QgsVectorLayer::featureDeleted, this, &QgsVectorLayer::emitDataChanged );
5439  connect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
5440  connect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );
5442  connect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::onAfterCommitChangesDependency );
5443  }
5444 
5445  // if new layers are present, emit a data change
5446  if ( ! toAdd.isEmpty() )
5447  emitDataChanged();
5448 
5449  return true;
5450 }
5451 
5452 QgsFieldConstraints::Constraints QgsVectorLayer::fieldConstraints( int fieldIndex ) const
5453 {
5454  if ( fieldIndex < 0 || fieldIndex >= mFields.count() || !mDataProvider )
5455  return QgsFieldConstraints::Constraints();
5456 
5457  QgsFieldConstraints::Constraints constraints = mFields.at( fieldIndex ).constraints().constraints();
5458 
5459  // make sure provider constraints are always present!
5460  if ( mFields.fieldOrigin( fieldIndex ) == QgsFields::OriginProvider )
5461  {
5462  constraints |= mDataProvider->fieldConstraints( mFields.fieldOriginIndex( fieldIndex ) );
5463  }
5464 
5465  return constraints;
5466 }
5467 
5468 QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength> QgsVectorLayer::fieldConstraintsAndStrength( int fieldIndex ) const
5469 {
5470  QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength > m;
5471 
5472  if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
5473  return m;
5474 
5475  QString name = mFields.at( fieldIndex ).name();
5476 
5477  QMap< QPair< QString, QgsFieldConstraints::Constraint >, QgsFieldConstraints::ConstraintStrength >::const_iterator conIt = mFieldConstraintStrength.constBegin();
5478  for ( ; conIt != mFieldConstraintStrength.constEnd(); ++conIt )
5479  {
5480  if ( conIt.key().first == name )
5481  {
5482  m[ conIt.key().second ] = mFieldConstraintStrength.value( conIt.key() );
5483  }
5484  }
5485 
5486  return m;
5487 }
5488 
5490 {
5491  if ( index < 0 || index >= mFields.count() )
5492  return;
5493 
5494  QString name = mFields.at( index ).name();
5495 
5496  // add constraint to existing constraints
5497  QgsFieldConstraints::Constraints constraints = mFieldConstraints.value( name, QgsFieldConstraints::Constraints() );
5498  constraints |= constraint;
5499  mFieldConstraints.insert( name, constraints );
5500 
5501  mFieldConstraintStrength.insert( qMakePair( name, constraint ), strength );
5502 
5503  updateFields();
5504 }
5505 
5507 {
5508  if ( index < 0 || index >= mFields.count() )
5509  return;
5510 
5511  QString name = mFields.at( index ).name();
5512 
5513  // remove constraint from existing constraints
5514  QgsFieldConstraints::Constraints constraints = mFieldConstraints.value( name, QgsFieldConstraints::Constraints() );
5515  constraints &= ~constraint;
5516  mFieldConstraints.insert( name, constraints );
5517 
5518  mFieldConstraintStrength.remove( qMakePair( name, constraint ) );
5519 
5520  updateFields();
5521 }
5522 
5523 QString QgsVectorLayer::constraintExpression( int index ) const
5524 {
5525  if ( index < 0 || index >= mFields.count() )
5526  return QString();
5527 
5528  return mFields.at( index ).constraints().constraintExpression();
5529 }
5530 
5531 QString QgsVectorLayer::constraintDescription( int index ) const
5532 {
5533  if ( index < 0 || index >= mFields.count() )
5534  return QString();
5535 
5536  return mFields.at( index ).constraints().constraintDescription();
5537 }
5538 
5539 void QgsVectorLayer::setConstraintExpression( int index, const QString &expression, const QString &description )
5540 {
5541  if ( index < 0 || index >= mFields.count() )
5542  return;
5543 
5544  if ( expression.isEmpty() )
5545  {
5546  mFieldConstraintExpressions.remove( mFields.at( index ).name() );
5547  }
5548  else
5549  {
5550  mFieldConstraintExpressions.insert( mFields.at( index ).name(), qMakePair( expression, description ) );
5551  }
5552  updateFields();
5553 }
5554 
5555 void QgsVectorLayer::setFieldConfigurationFlags( int index, QgsField::ConfigurationFlags flags )
5556 {
5557  if ( index < 0 || index >= mFields.count() )
5558  return;
5559 
5560  mFieldConfigurationFlags.insert( mFields.at( index ).name(), flags );
5561  updateFields();
5562 }
5563 
5565 {
5566  if ( index < 0 || index >= mFields.count() )
5567  return;
5568  QgsField::ConfigurationFlags flags = mFields.at( index ).configurationFlags();
5569  flags.setFlag( flag, active );
5571 }
5572 
5573 QgsField::ConfigurationFlags QgsVectorLayer::fieldConfigurationFlags( int index ) const
5574 {
5575 
5576  if ( index < 0 || index >= mFields.count() )
5578 
5579  return mFields.at( index ).configurationFlags();
5580 }
5581 
5583 {
5584  if ( index < 0 || index >= mFields.count() )
5585  return;
5586 
5587  if ( setup.isNull() )
5588  mFieldWidgetSetups.remove( mFields.at( index ).name() );
5589  else
5590  mFieldWidgetSetups.insert( mFields.at( index ).name(), setup );
5591  updateFields();
5592 }
5593 
5595 {
5596 
5597  if ( index < 0 || index >= mFields.count() )
5598  return QgsEditorWidgetSetup();
5599 
5600  return mFields.at( index ).editorWidgetSetup();
5601 }
5602 
5603 QgsAbstractVectorLayerLabeling *QgsVectorLayer::readLabelingFromCustomProperties()
5604 {
5606  if ( customProperty( QStringLiteral( "labeling" ) ).toString() == QLatin1String( "pal" ) )
5607  {
5608  if ( customProperty( QStringLiteral( "labeling/enabled" ), QVariant( false ) ).toBool() )
5609  {
5610  // try to load from custom properties
5611  QgsPalLayerSettings settings;
5612  settings.readFromLayerCustomProperties( this );
5613  labeling = new QgsVectorLayerSimpleLabeling( settings );
5614  }
5615 
5616  // also clear old-style labeling config
5617  removeCustomProperty( QStringLiteral( "labeling" ) );
5618  const auto constCustomPropertyKeys = customPropertyKeys();
5619  for ( const QString &key : constCustomPropertyKeys )
5620  {
5621  if ( key.startsWith( QLatin1String( "labeling/" ) ) )
5622  removeCustomProperty( key );
5623  }
5624  }
5625 
5626  return labeling;
5627 }
5628 
5630 {
5631  return mAllowCommit;
5632 }
5633 
5634 void QgsVectorLayer::setAllowCommit( bool allowCommit )
5635 {
5636  if ( mAllowCommit == allowCommit )
5637  return;
5638 
5639  mAllowCommit = allowCommit;
5640  emit allowCommitChanged();
5641 }
5642 
5644 {
5645  return mGeometryOptions.get();
5646 }
5647 
5648 void QgsVectorLayer::setReadExtentFromXml( bool readExtentFromXml )
5649 {
5650  mReadExtentFromXml = readExtentFromXml;
5651 }
5652 
5654 {
5655  return mReadExtentFromXml;
5656 }
5657 
5658 void QgsVectorLayer::onDirtyTransaction( const QString &sql, const QString &name )
5659 {
5661  if ( tr && mEditBuffer )
5662  {
5663  qobject_cast<QgsVectorLayerEditPassthrough *>( mEditBuffer )->update( tr, sql, name );
5664  }
5665 }
5666 
5667 QList<QgsVectorLayer *> QgsVectorLayer::DeleteContext::handledLayers( bool includeAuxiliaryLayers ) const
5668 {
5669  QList<QgsVectorLayer *> layers;
5670  QMap<QgsVectorLayer *, QgsFeatureIds>::const_iterator i;
5671  for ( i = mHandledFeatures.begin(); i != mHandledFeatures.end(); ++i )
5672  {
5673  if ( includeAuxiliaryLayers || !qobject_cast< QgsAuxiliaryLayer * >( i.key() ) )
5674  layers.append( i.key() );
5675  }
5676  return layers;
5677 }
5678 
5680 {
5681  return mHandledFeatures[layer];
5682 }
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.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
const QgsExpressionNode * rootNode() const
Returns the root node of the expression.
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
QVariant evaluate()
Evaluate the feature and return the result.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
An interface for objects which generate feature renderers for vector layers.
static QgsFeatureRenderer * defaultRenderer(QgsWkbTypes::GeometryType geomType)
Returns a new renderer - used by default in vector layers.
Definition: qgsrenderer.cpp:77
virtual void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const
used from subclasses to create SLD Rule elements following SLD v1.1 specs
Definition: qgsrenderer.h:312
virtual QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context)
store renderer info to XML element
static QgsFeatureRenderer * loadSld(const QDomNode &node, QgsWkbTypes::GeometryType geomType, QString &errorMessage)
Create a new renderer according to the information contained in the UserStyle element of a SLD style ...
static QgsFeatureRenderer * load(QDomElement &symbologyElem, const QgsReadWriteContext &context)
create a renderer from XML element
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
@ SubsetOfAttributes
Fetch only a subset of attributes (setSubsetOfAttributes sets this flag)
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets feature ID that should be fetched.
virtual bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags())
Adds a single feature to the sink.
virtual QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const
Returns the set of unique values contained within the specified fieldIndex from this source.
SpatialIndexPresence
Enumeration of spatial index presence states.
@ SpatialIndexUnknown
Spatial index presence cannot be determined, index may or may not exist.
FeatureAvailability
Possible return value for hasFeatures() to determine if a source is empty.
virtual QgsFeatureIds allFeatureIds() const
Returns a list of all feature IDs for features present in the source.
virtual SpatialIndexPresence hasSpatialIndex() const
Returns an enum value representing the presence of a valid spatial index on the source,...
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
bool setAttribute(int field, const QVariant &attr)
Set an attribute's value by field index.
Definition: qgsfeature.cpp:236
QgsAttributes attributes
Definition: qgsfeature.h:65
QgsFields fields
Definition: qgsfeature.h:66
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:204
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:190
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:287
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:144
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
Stores information about constraints which may be present on a field.
ConstraintStrength
Strength of constraints.
void setConstraintStrength(Constraint constraint, ConstraintStrength strength)
Sets the strength of a constraint.
void setConstraintExpression(const QString &expression, const QString &description=QString())
Set the constraint expression for the field.
@ ConstraintOriginProvider
Constraint was set at data provider.
@ ConstraintOriginLayer
Constraint was set by layer.
ConstraintStrength constraintStrength(Constraint constraint) const
Returns the strength of a field constraint, or ConstraintStrengthNotSet if the constraint is not pres...
ConstraintOrigin constraintOrigin(Constraint constraint) const
Returns the origin of a field constraint, or ConstraintOriginNotSet if the constraint is not present ...
QString constraintExpression() const
Returns the constraint expression for the field, if set.
Constraint
Constraints which may be present on a field.
@ ConstraintNotNull
Field may not be null.
@ ConstraintUnique
Field must have a unique value.
@ ConstraintExpression
Field has an expression constraint set. See constraintExpression().
QString constraintDescription() const
Returns the descriptive name for the constraint expression.
Q_GADGET Constraints constraints
void setConstraint(Constraint constraint, ConstraintOrigin origin=ConstraintOriginLayer)
Sets a constraint on the field.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:138
QString name
Definition: qgsfield.h:60
int precision
Definition: qgsfield.h:57
int length
Definition: qgsfield.h:56
QString displayName() const
Returns the name to use when displaying this field.
Definition: qgsfield.cpp:88
ConfigurationFlags configurationFlags
Definition: qgsfield.h:64
QString alias
Definition: qgsfield.h:61
QgsDefaultValue defaultValueDefinition
Definition: qgsfield.h:62
QString comment
Definition: qgsfield.h:59
QgsFieldConstraints constraints
Definition: qgsfield.h:63
ConfigurationFlag
Configuration flags for fields These flags are meant to be user-configurable and are not describing a...
Definition: qgsfield.h:84
@ HideFromWfs
Fields is available if layer is served as WFS from QGIS server.
@ None
No flag is defined.
@ HideFromWms
Fields is available if layer is served as WMS from QGIS server.
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition: qgsfield.cpp:559
Container of fields for a vector layer.
Definition: qgsfields.h:45
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:202
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:207
@ OriginExpression
Field is calculated from an expression.
Definition: qgsfields.h:54
@ OriginEdit
Field has been temporarily added in editing mode (originIndex = index in the list of added attributes...
Definition: qgsfields.h:53
@ OriginUnknown
It has not been specified where the field comes from.
Definition: qgsfields.h:50
@ OriginJoin
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfields.h:52
@ OriginProvider
Field comes from the underlying data provider of the vector layer (originIndex = index in provider's ...
Definition: qgsfields.h:51
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
FieldOrigin fieldOrigin(int fieldIdx) const
Gets field's origin (value from an enumeration)
Definition: qgsfields.cpp:189
bool isEmpty() const
Checks whether the container is empty.
Definition: qgsfields.cpp:128
int size() const
Returns number of items.
Definition: qgsfields.cpp:138
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
int fieldOriginIndex(int fieldIdx) const
Gets field's origin index (its meaning is specific to each type of origin)
Definition: qgsfields.cpp:197
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
The QgsGeometryOptions class contains options to automatically adjust geometries to constraints on a ...
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
bool equals(const QgsGeometry &geometry) const
Test if this geometry is exactly equal to another geometry.
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:127
OperationResult
Success or failure of a geometry operation.
Definition: qgsgeometry.h:136
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
void setMergeLines(bool merge)
Sets whether connected line features with identical label text should be merged prior to generating l...
Class for metadata formatter.
QString linksSectionHtml() const
Formats the "Links" section according to a metadata object.
QString extentSectionHtml(const bool showSpatialExtent=true) const
Formats the "Extents" section according to a metadata object (extent and temporal).
QString contactsSectionHtml() const
Formats the "Contacts" section according to a metadata object.
QString identificationSectionHtml() const
Formats the "Identification" section according to a metadata object.
QString historySectionHtml() const
Formats the "History" section according to a metadata object.
QString accessSectionHtml() const
Formats the "Access" section according to a metadata object.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:122
This class models dependencies with or between map layers.
static QString typeToString(QgsMapLayerType type)
Converts a map layer type to a string value.
virtual void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads configuration from a DOM element previously written by writeXml()
virtual QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Writes configuration to a DOM element, to be used later with readXml()
static QgsMapLayerLegend * defaultVectorLegend(QgsVectorLayer *vl)
Create new legend implementation for vector layer.
Base class for utility classes that encapsulate information necessary for rendering of map layers.
Base class for storage of map layer temporal properties.
Base class for all map layer types.
Definition: qgsmaplayer.h:85
QString name
Definition: qgsmaplayer.h:88
void readStyleManager(const QDomNode &layerNode)
Read style manager's configuration (if any). To be called by subclasses.
virtual void exportNamedStyle(QDomDocument &doc, QString &errorMsg, const QgsReadWriteContext &context=QgsReadWriteContext(), QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const
Export the properties of this layer as named style in a QDomDocument.
void dependenciesChanged()
Emitted when dependencies are changed.
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager's configuration (if exists). To be called by subclasses.
QgsMapLayerLegend * legend() const
Can be nullptr.
virtual bool importNamedStyle(QDomDocument &doc, QString &errorMsg, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Import the properties of this layer from a QDomDocument.
void recalculateExtents() const
This is used to send a request that any mapcanvas using this layer update its extents.
virtual QgsRectangle extent() const
Returns the extent of the layer.
QString source() const
Returns the source for the layer.
Q_INVOKABLE QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
void removeCustomProperty(const QString &key)
Remove a custom property from layer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
QgsMapLayerType type
Definition: qgsmaplayer.h:92
void configChanged()
Emitted whenever the configuration is changed.
void setMinimumScale(double scale)
Sets the minimum map scale (i.e.
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:91
void writeCustomProperties(QDomNode &layerNode, QDomDocument &doc) const
Write custom properties to project file.
QgsRectangle mExtent
Extent of the layer.
Definition: qgsmaplayer.h:1606
virtual QString loadDefaultStyle(bool &resultFlag)
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
void setMaximumScale(double scale)
Sets the maximum map scale (i.e.
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:90
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
virtual void setOpacity(double opacity)
Sets the opacity for the layer, where opacity is a value between 0 (totally transparent) and 1....
void setFlags(QgsMapLayer::LayerFlags flags)
Returns the flags for this layer.
QSet< QgsMapLayerDependency > mDependencies
List of layers that may modify this layer on modification.
Definition: qgsmaplayer.h:1645
void readCustomProperties(const QDomNode &layerNode, const QString &keyStartsWith=QString())
Read custom properties from project file.
virtual void setMetadata(const QgsLayerMetadata &metadata)
Sets the layer's metadata store.
Q_INVOKABLE void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
QString mProviderKey
Data provider key (name of the data provider)
Definition: qgsmaplayer.h:1658
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
void styleChanged()
Signal emitted whenever a change affects the layer's style.
QUndoStack * undoStack()
Returns pointer to layer's undo stack.
void rendererChanged()
Signal emitted when renderer is changed.
void setScaleBasedVisibility(bool enabled)
Sets whether scale based visibility is enabled for the layer.
void dataSourceChanged()
Emitted whenever the layer's data source has been changed.
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
virtual QString loadNamedStyle(const QString &uri, bool &resultFlag, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Retrieve a named style for this layer if one exists (either as a .qml file on disk or as a record in ...
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
void styleLoaded(QgsMapLayer::StyleCategories categories)
Emitted when a style has been loaded.
void dataChanged()
Data of layer changed.
void willBeDeleted()
Emitted in the destructor when the layer is about to be deleted, but it is still in a perfectly valid...
void setName(const QString &name)
Set the display name of the layer.
virtual void setExtent(const QgsRectangle &rect)
Sets the extent.
virtual void resolveReferences(QgsProject *project)
Resolve references to other layers (kept as layer IDs after reading XML) into layer objects.
bool isValid
Definition: qgsmaplayer.h:93
QString mDataSource
Data source description string, varies by layer type.
Definition: qgsmaplayer.h:1612
@ FlagTrustLayerMetadata
Trust layer metadata. Improves layer load time by skipping expensive checks like primary key unicity,...
Definition: qgsmaplayer.h:585
@ FlagDontResolveLayers
Don't resolve layer paths or create data providers for layers.
Definition: qgsmaplayer.h:584
void setValid(bool valid)
Sets whether layer is valid or not.
void readCommonStyle(const QDomElement &layerElement, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)
Read style data common to all layer types.
QgsMapLayer::ReadFlags mReadFlags
Read flags. It's up to the subclass to respect these when restoring state from XML.
Definition: qgsmaplayer.h:1663
double minimumScale() const
Returns the minimum map scale (i.e.
void repaintRequested(bool deferredUpdate=false)
By emitting this signal the layer tells that either appearance or content have been changed and any v...
virtual void exportSldStyle(QDomDocument &doc, QString &errorMsg) const
Export the properties of this layer as SLD style in a QDomDocument.
Q_INVOKABLE QStringList customPropertyKeys() const
Returns list of all keys within custom properties.
QgsProject * project() const
Returns the parent project if this map layer is added to a project.
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
double opacity
Definition: qgsmaplayer.h:94
bool mValid
Indicates if the layer is valid and can be drawn.
Definition: qgsmaplayer.h:1609
@ GeometryOptions
Geometry validation configuration.
Definition: qgsmaplayer.h:181
@ AttributeTable
Attribute table settings: choice and order of columns, conditional styling.
Definition: qgsmaplayer.h:178
@ LayerConfiguration
General configuration: identifiable, removable, searchable, display expression, read-only.
Definition: qgsmaplayer.h:169
@ Symbology
Symbology.
Definition: qgsmaplayer.h:170
@ MapTips
Map tips.
Definition: qgsmaplayer.h:176
@ Rendering
Rendering: scale visibility, simplify method, opacity.
Definition: qgsmaplayer.h:179
@ Relations
Relations.
Definition: qgsmaplayer.h:182
@ CustomProperties
Custom properties (by plugins for instance)
Definition: qgsmaplayer.h:180
@ Actions
Actions.
Definition: qgsmaplayer.h:175
@ Forms
Feature form.
Definition: qgsmaplayer.h:174
@ Fields
Aliases, widgets, WMS/WFS, expressions, constraints, virtual fields.
Definition: qgsmaplayer.h:173
@ Legend
Legend settings (since QGIS 3.16)
Definition: qgsmaplayer.h:184
@ Diagrams
Diagrams.
Definition: qgsmaplayer.h:177
@ Labeling
Labeling.
Definition: qgsmaplayer.h:172
void setProviderType(const QString &providerType)
Sets the providerType (provider key)
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
double maximumScale() const
Returns the maximum map scale (i.e.
bool mShouldValidateCrs
true if the layer's CRS should be validated and invalid CRSes are not permitted.
Definition: qgsmaplayer.h:1670
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
static QgsExpression * expressionFromOgcFilter(const QDomElement &element, QgsVectorLayer *layer=nullptr)
Parse XML with OGC filter into QGIS expression.
static QgsPainting::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
Definition: qgspainting.cpp:80
static QPainter::CompositionMode getCompositionMode(QgsPainting::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:20
BlendMode
Blending modes enum defining the available composition modes that can be used when rendering a layer.
Definition: qgspainting.h:37
Contains settings for how a map layer will be labeled.
double yOffset
Vertical offset of label.
double maxCurvedCharAngleIn
Maximum angle between inside curved label characters (valid range 20.0 to 60.0).
void setFormat(const QgsTextFormat &format)
Sets the label text formatting settings, e.g., font settings, buffer settings, etc.
bool displayAll
If true, all features will be labelled even when overlaps occur.
double xOffset
Horizontal offset of label.
@ ShowAll
Show upside down for all labels, including dynamic ones.
QgsUnitTypes::RenderUnit offsetUnits
Units for offsets of label.
@ PerimeterCurved
Arranges candidates following the curvature of a polygon's boundary. Applies to polygon layers only.
@ Curved
Arranges candidates following the curvature of a line feature. Applies to line layers only.
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
@ AroundPoint
Arranges candidates in a circle around a point (or centroid of a polygon). Applies to point or polygo...
@ Line
Arranges candidates parallel to a generalised line representing the feature or parallel to a polygon'...
double angleOffset
Label rotation, in degrees clockwise.
double maxCurvedCharAngleOut
Maximum angle between outside curved label characters (valid range -20.0 to -95.0)
const QgsLabelLineSettings & lineSettings() const
Returns the label line settings, which contain settings related to how the label engine places and fo...
bool isExpression
true if this label is made from a expression string, e.g., FieldName || 'mm'
UpsideDownLabels upsidedownLabels
Controls whether upside down labels are displayed and how they are handled.
QString fieldName
Name of field (or an expression) to use for label text.
Resolves relative paths into absolute paths and vice versa.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
A class to represent a 2D point.
Definition: qgspointxy.h:44
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:38
virtual QString translate(const QString &context, const QString &sourceText, const char *disambiguation=nullptr, int n=-1) const =0
The derived translate() translates with QTranslator and qm file the sourceText.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:99
QgsRelationManager * relationManager
Definition: qgsproject.h:109
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:501
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
QgsPathResolver pathResolver() const
Returns path resolver object with considering whether the project uses absolute or relative paths and...
QMap< QString, QgsMapLayer * > mapLayers(const bool validOnly=false) const
Returns a map of all registered layers by layer ID.
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
Definition for a property.
Definition: qgsproperty.h:48
@ Double
Double value (including negative values)
Definition: qgsproperty.h:58
@ Boolean
Boolean value.
Definition: qgsproperty.h:54
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
bool deleteStyleById(const QString &providerKey, const QString &uri, QString styleId, QString &errCause)
Deletes a layer style defined by styleId.
QString loadStyle(const QString &providerKey, const QString &uri, QString &errCause)
Loads a layer style defined by uri.
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QString getStyleById(const QString &providerKey, const QString &uri, QString styleId, QString &errCause)
Gets a layer style defined by styleId.
int listStyles(const QString &providerKey, const QString &uri, QStringList &ids, QStringList &names, QStringList &descriptions, QString &errCause)
Lists stored layer styles in the provider defined by providerKey and uri.
bool saveStyle(const QString &providerKey, const QString &uri, const QString &qmlStyle, const QString &sldStyle, const QString &styleName, const QString &styleDescription, const QString &uiFileContent, bool useAsDefault, QString &errCause)
Saves a layer style to provider.
Allows entering a context category and takes care of leaving this category on deletion of the class.
The class is used as a container of context for various read/write operations on other objects.
const QgsProjectTranslator * projectTranslator() const
Returns the project translator.
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
MAYBE_UNUSED NODISCARD QgsReadWriteContextCategoryPopper enterCategory(const QString &category, const QString &details=QString())
Push a category to the stack.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:447
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:209
void set(const QgsPointXY &p1, const QgsPointXY &p2)
Sets the rectangle from two QgsPoints.
Definition: qgsrectangle.h:105
void setMinimal() SIP_HOLDGIL
Set a rectangle so that min corner is at max and max corner is at min.
Definition: qgsrectangle.h:151
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
Definition: qgsrectangle.h:359
void normalize()
Normalize the rectangle so it has non-negative width/height.
Definition: qgsrectangle.h:182
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
QList< QgsRelation > referencingRelations(const QgsVectorLayer *layer=nullptr, int fieldIdx=-2) const
Gets all relations where the specified layer (and field) is the referencing part (i....
void relationsLoaded()
Emitted when the relations were loaded after reading a project.
@ Normal
A normal relation.
Definition: qgsrelation.h:61
@ Composition
Fix relation, related elements are part of the parent and a parent copy will copy any children or del...
Definition: qgsrelation.h:73
Contains information about the context of a rendering operation.
double rendererScale() const
Returns the renderer map scale.
bool useRenderingOptimization() const
Returns true if the rendering optimization (geometry simplification) can be executed.
A child rule for QgsRuleBasedLabeling.
void appendChild(QgsRuleBasedLabeling::Rule *rule)
add child rule, take ownership, sets this as parent
Rule based labeling for a vector layer.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
T flagValue(const QString &key, const T &defaultValue, const Section section=NoSection)
Returns the setting value for a setting based on a flag.
Definition: qgssettings.h:330
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
T enumValue(const QString &key, const T &defaultValue, const Section section=NoSection)
Returns the setting value for a setting based on an enum.
Definition: qgssettings.h:252
Renders the diagrams for all features with the same settings.
Manages stored expressions regarding creation, modification and storing in the project.
bool writeXml(QDomNode &layerNode) const
Writes the stored expressions out in XML format.
bool readXml(const QDomNode &layerNode)
Reads the stored expressions in in XML format.
An interface for classes which can visit style entity (e.g.
static QgsUnitTypes::RenderUnit decodeSldUom(const QString &str, double *scaleFactor=nullptr)
Decodes a SLD unit of measure string to a render unit.
static QgsStringMap getSvgParameterList(QDomElement &element)
static void mergeScaleDependencies(double mScaleMinDenom, double mScaleMaxDenom, QVariantMap &props)
Merges the local scale limits, if any, with the ones already in the map, if any.
static bool fillFromSld(QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color)
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
void taskCompleted()
Will be emitted by task to indicate its successful completion.
virtual void cancel()
Notifies the task that it should terminate.
void taskTerminated()
Will be emitted by task if it has terminated for any reason other then completion (e....
bool isActive() const
Returns true if the temporal property is active.
Container for settings relating to a text buffer.
void setColor(const QColor &color)
Sets the color for the buffer.
void setEnabled(bool enabled)
Sets whether the text buffer will be drawn.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units used for the buffer size.
void setSize(double size)
Sets the size of the buffer.
Container for all settings relating to text rendering.
Definition: qgstextformat.h:41
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setSize(double size)
Sets the size for rendered text.
void setFont(const QFont &font)
Sets the font used for rendering text.
void setBuffer(const QgsTextBufferSettings &bufferSettings)
Sets the text's buffer settings.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the size of rendered text.
This class allows including a set of layers in a database-side transaction, provided the layer data p...
QString createSavepoint(QString &error)
creates a save point returns empty string on error returns the last created savepoint if it's not dir...
void dirtied(const QString &sql, const QString &name)
Emitted if a sql query is executed and the underlying data is modified.
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:167
@ RenderPoints
Points (e.g., for font sizes)
Definition: qgsunittypes.h:172
@ RenderPixels
Pixels.
Definition: qgsunittypes.h:170
This is the base class for vector data providers.
virtual QString dataComment() const override
Returns a short comment for the data that this provider is providing access to (e....
@ ReadLayerMetadata
Provider can read layer metadata from data store. Since QGIS 3.0. See QgsDataProvider::layerMetadata(...
@ SelectAtId
Fast access to features using their ID.
@ DeleteFeatures
Allows deletion of features.
@ CreateLabeling
Provider can set labeling settings using backend-specific formatting information. Since QGIS 3....
@ CreateRenderer
Provider can create feature renderers using backend-specific formatting information....
QgsWkbTypes::Type wkbType() const override=0
Returns the geometry type which is returned by this layer.
virtual bool isSaveAndLoadStyleToDatabaseSupported() const
It returns false by default.
static const int EditingCapabilities
Bitmask of all provider's editing capabilities.
virtual QgsFeatureRenderer * createRenderer(const QVariantMap &configuration=QVariantMap()) const
Creates a new vector layer feature renderer, using provider backend specific information.
virtual QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
virtual QStringList uniqueStringsMatching(int index, const QString &substring, int limit=-1, QgsFeedback *feedback=nullptr) const
Returns unique string values of an attribute which contain a specified subset string.
void raiseError(const QString &msg) const
Signals an error in this provider.
virtual bool empty() const
Returns true if the layer does not contain any feature.
virtual QgsAttributeList pkAttributeIndexes() const
Returns list of indexes of fields that make up the primary key.
virtual void handlePostCloneOperations(QgsVectorDataProvider *source)
Handles any post-clone operations required after this vector data provider was cloned from the source...
virtual QSet< QgsMapLayerDependency > dependencies() const
Gets the list of layer ids on which this layer depends.
virtual void setEncoding(const QString &e)
Set encoding used for accessing data from layer.
virtual bool hasMetadata() const
Returns true if the data source has metadata, false otherwise.
QVariant maximumValue(int index) const override
Returns the maximum value of an attribute.
long featureCount() const override=0
Number of features in the layer.
QgsFields fields() const override=0
Returns the fields associated with this data provider.
QVariant minimumValue(int index) const override
Returns the minimum value of an attribute.
virtual QVariant aggregate(QgsAggregateCalculator::Aggregate aggregate, int index, const QgsAggregateCalculator::AggregateParameters &parameters, QgsExpressionContext *context, bool &ok, QgsFeatureIds *fids=nullptr) const
Calculates an aggregated value from the layer's features.
QString encoding() const
Returns the encoding which is used for accessing data.
virtual QVariant defaultValue(int fieldIndex) const
Returns any literal default values which are present at the provider for a specified field index.
QgsFieldConstraints::Constraints fieldConstraints(int fieldIndex) const
Returns any constraints which are present at the provider for a specified field index.
virtual QgsTransaction * transaction() const
Returns the transaction this data provider is included in, if any.
virtual QgsAbstractVectorLayerLabeling * createLabeling(const QVariantMap &configuration=QVariantMap()) const
Creates labeling settings, using provider backend specific information.
virtual Q_INVOKABLE QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
QgsVectorDataProviderTemporalCapabilities * temporalCapabilities() override
Returns the provider's temporal capabilities.
QString capabilitiesString() const
Returns the above in friendly format.
void committedAttributesDeleted(const QString &layerId, const QgsAttributeList &deletedAttributes)
Signals emitted after committing changes.
virtual bool deleteFeature(QgsFeatureId fid)
Delete a feature from the layer (but does not commit it)
QgsFeatureMap mAddedFeatures
New features which are not committed.
QgsFeatureIds deletedFeatureIds() const
Returns a list of deleted feature IDs which are not committed.
QgsChangedAttributesMap changedAttributeValues() const
Returns a map of features with changed attributes values which are not committed.
void committedAttributeValuesChanges(const QString &layerId, const QgsChangedAttributesMap &changedAttributesValues)
virtual bool renameAttribute(int attr, const QString &newName)
Renames an attribute field (but does not commit it)
void geometryChanged(QgsFeatureId fid, const QgsGeometry &geom)
Emitted when a feature's geometry is changed.
virtual bool addAttribute(const QgsField &field)
Add an attribute field (but does not commit it) returns true if the field was added.
void committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)
virtual bool addFeatures(QgsFeatureList &features)
Insert a copy of the given features into the layer (but does not commit it)
QgsGeometryMap mChangedGeometries
Changed geometries which are not committed.
virtual bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues)
Changes values of attributes (but does not commit it).
QgsAttributeList mDeletedAttributeIds
Deleted attributes fields which are not committed. The list is kept sorted.
QgsFeatureMap addedFeatures() const
Returns a map of new features which are not committed.
QgsFeatureIds mDeletedFeatureIds
Deleted feature IDs which are not committed.
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
void updateFields(QgsFields &fields)
void committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)
void featureDeleted(QgsFeatureId fid)
void attributeAdded(int idx)
void committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)
virtual bool addFeature(QgsFeature &f)
Adds a feature.
virtual void rollBack()
Stop editing and discard the edits.
void attributeDeleted(int idx)
void featureAdded(QgsFeatureId fid)
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &)
QgsChangedAttributesMap mChangedAttributeValues
Changed attributes values which are not committed.
virtual bool commitChanges(QStringList &commitErrors)
Attempts to commit any changes to disk.
virtual bool deleteAttribute(int attr)
Delete an attribute field (but does not commit it)
virtual bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant())
Changed an attribute value (but does not commit it)
virtual bool changeGeometry(QgsFeatureId fid, const QgsGeometry &geom)
Change feature's geometry.
void layerModified()
Emitted when modifications has been done on layer.
void committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)
Q_DECL_DEPRECATED QgsGeometry::OperationResult addRing(const QVector< QgsPointXY > &ring, const QgsFeatureIds &targetFeatureIds=QgsFeatureIds(), QgsFeatureId *modifiedFeatureId=nullptr)
Adds a ring to polygon/multipolygon features.
int translateFeature(QgsFeatureId featureId, double dx, double dy)
Translates feature by dx, dy.
bool insertVertex(double x, double y, QgsFeatureId atFeatureId, int beforeVertex)
Insert a new vertex before the given vertex number, in the given ring, item (first number is index 0)...
QgsVectorLayer::EditResult deleteVertex(QgsFeatureId featureId, int vertex)
Deletes a vertex from a feature.
Q_DECL_DEPRECATED QgsGeometry::OperationResult addPart(const QVector< QgsPointXY > &ring, QgsFeatureId featureId)
Adds a new part polygon to a multipart feature.
int addTopologicalPoints(const QgsGeometry &geom)
Adds topological points for every vertex of the geometry.
Q_DECL_DEPRECATED QgsGeometry::OperationResult splitFeatures(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits features cut by the given line.
bool moveVertex(double x, double y, QgsFeatureId atFeatureId, int atVertex)
Moves the vertex at the given position number, ring and item (first number is index 0),...
Q_DECL_DEPRECATED QgsGeometry::OperationResult splitParts(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits parts cut by the given line.
Counts the features in a QgsVectorLayer in task.
QHash< QString, long > symbolFeatureCountMap() const
Returns the count for each symbol.
QHash< QString, QgsFeatureIds > symbolFeatureIdMap() const
Returns the QgsFeatureIds for each symbol.
Manages joined fields for a vector layer.
void resolveReferences(QgsProject *project)
Resolves layer IDs of joined layers using given project's available layers.
bool addJoin(const QgsVectorLayerJoinInfo &joinInfo)
Joins another vector layer to this layer.
void readXml(const QDomNode &layer_node)
Reads joins from project file.
void writeXml(QDomNode &layer_node, QDomDocument &document) const
Saves mVectorJoins to xml under the layer node.
const QgsVectorJoinList & vectorJoins() const
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant())
Changes attribute value in joined layers.
bool removeJoin(const QString &joinLayerId)
Removes a vector layer join.
bool containsJoins() const
Quick way to test if there is any join at all.
bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues=QgsAttributeMap())
Changes attributes' values in joined layers.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a list of features in joined layers.
void joinedFieldsChanged()
Emitted whenever the list of joined fields changes (e.g.
void updateFields(QgsFields &fields)
Updates field map with joined attributes.
bool deleteFeature(QgsFeatureId fid, QgsVectorLayer::DeleteContext *context=nullptr) const
Deletes a feature from joined layers.
Defines left outer join from our vector layer to some other vector layer.
QString targetFieldName() const
Returns name of the field of our layer that will be used for join.
QString joinLayerId() const
ID of the joined layer - may be used to resolve reference to the joined layer.
Implementation of threaded rendering for vector layers.
Manages QGIS Server properties for a vector layer.
Basic implementation of the labeling interface.
Implementation of map layer temporal properties for vector layers.
void guessDefaultsFromFields(const QgsFields &fields)
Attempts to setup the temporal properties by scanning a set of fields and looking for standard naming...
void setDefaultsFromDataProviderTemporalCapabilities(const QgsDataProviderTemporalCapabilities *capabilities) override
Sets the layers temporal settings to appropriate defaults based on a provider's temporal capabilities...
static QString guessFriendlyIdentifierField(const QgsFields &fields)
Given a set of fields, attempts to pick the "most useful" field for user-friendly identification of f...
Represents a vector layer which manages a vector based data sets.
void setLabeling(QgsAbstractVectorLayerLabeling *labeling)
Sets labeling configuration.
QString attributeDisplayName(int index) const
Convenience function that returns the attribute alias if defined or the field name else.
Q_INVOKABLE QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
VertexMarkerType
Editing vertex markers.
QVariant maximumValue(int index) const FINAL
Returns the maximum value for an attribute column or an invalid variant in case of error.
int addExpressionField(const QString &exp, const QgsField &fld)
Add a new field which is calculated by the expression specified.
void committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)
Emitted when features are added to the provider.
void setExtent(const QgsRectangle &rect) FINAL
Sets the extent.
QgsRectangle sourceExtent() const FINAL
Returns the extent of all geometries from the source.
void featureBlendModeChanged(QPainter::CompositionMode blendMode)
Signal emitted when setFeatureBlendMode() is called.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const FINAL
bool writeStyle(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const FINAL
void addFeatureRendererGenerator(QgsFeatureRendererGenerator *generator)
Adds a new feature renderer generator to the layer.
Q_DECL_DEPRECATED void setExcludeAttributesWfs(const QSet< QString > &att)
A set of attributes that are not advertised in WFS requests with QGIS server.
void removeFieldAlias(int index)
Removes an alias (a display name) for attributes to display in dialogs.
void setAuxiliaryLayer(QgsAuxiliaryLayer *layer=nullptr)
Sets the current auxiliary layer.
void beforeRemovingExpressionField(int idx)
Will be emitted, when an expression field is going to be deleted from this vector layer.
QString loadDefaultStyle(bool &resultFlag) FINAL
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
void committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)
Emitted when geometry changes are saved to the provider.
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
void beforeCommitChanges(bool stopEditing)
Emitted before changes are committed to the data provider.
Q_INVOKABLE bool startEditing()
Makes the layer editable.
QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength > fieldConstraintsAndStrength(int fieldIndex) const
Returns a map of constraint with their strength for a specific field of the layer.
bool addJoin(const QgsVectorLayerJoinInfo &joinInfo)
Joins another vector layer to this layer.
QSet< QgsMapLayerDependency > dependencies() const FINAL
Gets the list of dependencies.
QgsVectorLayer(const QString &path=QString(), const QString &baseName=QString(), const QString &providerLib="ogr", const QgsVectorLayer::LayerOptions &options=QgsVectorLayer::LayerOptions())
Constructor - creates a vector layer.
QgsMapLayerTemporalProperties * temporalProperties() override
Returns temporal properties associated with the vector layer.
void mapTipTemplateChanged()
Emitted when the map tip changes.
QgsDefaultValue defaultValueDefinition(int index) const
Returns the definition of the expression used when calculating the default value for a field.
QgsExpressionContextScope * createExpressionContextScope() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext) FINAL
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context.
QgsVectorLayerFeatureCounter * countSymbolFeatures(bool storeSymbolFids=false)
Count features for symbols.
QPainter::CompositionMode featureBlendMode() const
Returns the current blending mode for features.
QString constraintExpression(int index) const
Returns the constraint expression for for a specified field index, if set.
bool addAttribute(const QgsField &field)
Add an attribute field (but does not commit it) returns true if the field was added.
void attributeAdded(int idx)
Will be emitted, when a new attribute has been added to this vector layer.
QString capabilitiesString() const
Capabilities for this layer, comma separated and translated.
void deselect(QgsFeatureId featureId)
Deselects feature by its ID.
virtual int listStylesInDatabase(QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError)
Lists all the style in db split into related to the layer and not related to.
void allowCommitChanged()
Emitted whenever the allowCommitChanged() property of this layer changes.
friend class QgsVectorLayerEditBuffer
void editCommandStarted(const QString &text)
Signal emitted when a new edit command has been started.
void updateFields()
Will regenerate the fields property of this layer by obtaining all fields from the dataProvider,...
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
virtual QString loadNamedStyle(const QString &theURI, bool &resultFlag, bool loadFromLocalDb, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Loads a named style from file/local db/datasource db.
void setFieldConstraint(int index, QgsFieldConstraints::Constraint constraint, QgsFieldConstraints::ConstraintStrength strength=QgsFieldConstraints::ConstraintStrengthHard)
Sets a constraint for a specified field index.
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
bool loadAuxiliaryLayer(const QgsAuxiliaryStorage &storage, const QString &key=QString())
Loads the auxiliary layer for this vector layer.
bool deleteFeature(QgsFeatureId fid, DeleteContext *context=nullptr)
Deletes a feature from the layer (but does not commit it).
bool insertVertex(double x, double y, QgsFeatureId atFeatureId, int beforeVertex)
Inserts a new vertex before the given vertex number, in the given ring, item (first number is index 0...
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QString mapTipTemplate
QString htmlMetadata() const FINAL
Obtain a formatted HTML string containing assorted metadata for this layer.
Q_INVOKABLE QgsRectangle boundingBoxOfSelected() const
Returns the bounding box of the selected features. If there is no selection, QgsRectangle(0,...
QgsFields fields() const FINAL
Returns the list of fields of this layer.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a list of features to the sink.
Q_INVOKABLE QgsFeatureList selectedFeatures() const
Returns a copy of the user-selected features.
QString expressionField(int index) const
Returns the expression used for a given expression field.
bool readSymbology(const QDomNode &layerNode, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) FINAL
void removeFeatureRendererGenerator(const QString &id)
Removes the feature renderer with matching id from the layer.
friend class QgsVectorLayerEditPassthrough
void setSimplifyMethod(const QgsVectorSimplifyMethod &simplifyMethod)
Sets the simplification settings for fast rendering of features.
Q_DECL_DEPRECATED QgsGeometry::OperationResult splitFeatures(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits features cut by the given line.
void editCommandDestroyed()
Signal emitted, when an edit command is destroyed.
QgsFieldConstraints::Constraints fieldConstraints(int fieldIndex) const
Returns any constraints which are present for a specified field index.
bool deleteFeatures(const QgsFeatureIds &fids, DeleteContext *context=nullptr)
Deletes a set of features from the layer (but does not commit it)
void setMapTipTemplate(const QString &mapTipTemplate)
The mapTip is a pretty, html representation for feature information.
Q_DECL_DEPRECATED QSet< QString > excludeAttributesWms() const
A set of attributes that are not advertised in WMS requests with QGIS server.
QgsFeatureIds symbolFeatureIds(const QString &legendKey) const
Ids of features rendered with specified legend key.
const QgsDiagramLayerSettings * diagramLayerSettings() const
void removeFieldConstraint(int index, QgsFieldConstraints::Constraint constraint)
Removes a constraint for a specified field index.
void editingStarted()
Emitted when editing on this layer has started.
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
virtual QString getStyleFromDatabase(const QString &styleId, QString &msgError)
Returns the named style corresponding to style id provided.
void featuresDeleted(const QgsFeatureIds &fids)
Emitted when features have been deleted.
void setLabelsEnabled(bool enabled)
Sets whether labels should be enabled for the layer.
void subsetStringChanged()
Emitted when the layer's subset string has changed.
void setFieldConfigurationFlags(int index, QgsField::ConfigurationFlags flags)
Sets the configuration flags of the field at given index.
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer.
void setCoordinateSystem()
Setup the coordinate system transformation for the layer.
void committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)
Emitted when features are deleted from the provider.
void updateExpressionField(int index, const QString &exp)
Changes the expression used to define an expression based (virtual) field.
~QgsVectorLayer() override
QgsCoordinateReferenceSystem sourceCrs() const FINAL
Returns the coordinate reference system for features in the source.
void endEditCommand()
Finish edit command and add it to undo/redo stack.
void destroyEditCommand()
Destroy active command and reverts all changes in it.
bool isAuxiliaryField(int index, int &srcIndex) const
Returns true if the field comes from the auxiliary layer, false otherwise.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QList< QgsRelation > referencingRelations(int idx) const
Returns the layer's relations, where the foreign key is on this layer.
Q_DECL_DEPRECATED QSet< QString > excludeAttributesWfs() const
A set of attributes that are not advertised in WFS requests with QGIS server.
void setDefaultValueDefinition(int index, const QgsDefaultValue &definition)
Sets the definition of the expression to use when calculating the default value for a field.
bool diagramsEnabled() const
Returns whether the layer contains diagrams which are enabled and should be drawn.
void setAllowCommit(bool allowCommit)
Controls, if the layer is allowed to commit changes.
bool setDependencies(const QSet< QgsMapLayerDependency > &layers) FINAL
Sets the list of dependencies.
void symbolFeatureCountMapChanged()
Emitted when the feature count for symbols on this layer has been recalculated.
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
EditResult
Result of an edit operation.
@ Success
Edit operation was successful.
@ InvalidLayer
Edit failed due to invalid layer.
void setFeatureBlendMode(QPainter::CompositionMode blendMode)
Sets the blending mode used for rendering each feature.
Q_INVOKABLE void selectByExpression(const QString &expression, QgsVectorLayer::SelectBehavior behavior=QgsVectorLayer::SetSelection)
Selects matching features using an expression.
QString constraintDescription(int index) const
Returns the descriptive name for the constraint expression for a specified field index.
void writeCustomSymbology(QDomElement &element, QDomDocument &doc, QString &errorMessage) const
Signal emitted whenever the symbology (QML-file) for this layer is being written.
void setProviderEncoding(const QString &encoding)
Sets the text encoding of the data provider.
bool writeSld(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QVariantMap &props=QVariantMap()) const
Writes the symbology of the layer into the document provided in SLD 1.1 format.
void setDisplayExpression(const QString &displayExpression)
Set the preview expression, used to create a human readable preview string.
virtual bool deleteAttribute(int attr)
Deletes an attribute field (but does not commit it).
void resolveReferences(QgsProject *project) FINAL
Resolves references to other layers (kept as layer IDs after reading XML) into layer objects.
bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues=QgsAttributeMap(), bool skipDefaultValues=false)
Changes attributes' values for a feature (but does not immediately commit the changes).
bool removeJoin(const QString &joinLayerId)
Removes a vector layer join.
Q_INVOKABLE void invertSelectionInRectangle(QgsRectangle &rect)
Inverts selection of features found within the search rectangle (in layer's coordinates)
void setRenderer(QgsFeatureRenderer *r)
Sets the feature renderer which will be invoked to represent this layer in 2D map views.
Q_INVOKABLE void selectAll()
Select all the features.
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
QStringList commitErrors() const
Returns a list containing any error messages generated when attempting to commit changes to the layer...
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
bool readExtentFromXml() const
Returns true if the extent is read from the XML document when data source has no metadata,...
QString dataComment() const
Returns a description for this layer as defined in the data provider.
virtual void saveStyleToDatabase(const QString &name, const QString &description, bool useAsDefault, const QString &uiFileContent, QString &msgError)
Saves named and sld style of the layer to the style table in the db.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Q_DECL_DEPRECATED QgsGeometry::OperationResult addRing(const QVector< QgsPointXY > &ring, QgsFeatureId *featureId=nullptr)
Adds a ring to polygon/multipolygon features.
QgsGeometryOptions * geometryOptions() const
Configuration and logic to apply automatically on any edit happening on this layer.
QgsStringMap attributeAliases() const
Returns a map of field name to attribute alias.
Q_INVOKABLE int translateFeature(QgsFeatureId featureId, double dx, double dy)
Translates feature by dx, dy.
SelectBehavior
Selection behavior.
@ RemoveFromSelection
Remove from current selection.
@ IntersectSelection
Modify current selection to include only select features which match.
@ AddToSelection
Add selection to current selection.
@ SetSelection
Set selection, removing any existing selection.
virtual void updateExtents(bool force=false)
Update the extents for the layer.
void attributeDeleted(int idx)
Will be emitted, when an attribute has been deleted from this vector layer.
QgsActionManager * actions()
Returns all layer actions defined on this layer.
void beforeEditingStarted()
Emitted before editing on this layer is started.
void committedAttributeValuesChanges(const QString &layerId, const QgsChangedAttributesMap &changedAttributesValues)
Emitted when attribute value changes are saved to the provider.
QString subsetString
void committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)
Emitted when attributes are added to the provider.
void setEditFormConfig(const QgsEditFormConfig &editFormConfig)
Sets the editFormConfig (configuration) of the form used to represent this vector layer.
void committedAttributesDeleted(const QString &layerId, const QgsAttributeList &deletedAttributes)
Emitted when attributes are deleted from the provider.
QString displayExpression
void displayExpressionChanged()
Emitted when the display expression changes.
QVariant minimumValue(int index) const FINAL
Returns the minimum value for an attribute column or an invalid variant in case of error.
EditResult deleteVertex(QgsFeatureId featureId, int vertex)
Deletes a vertex from a feature.
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
void setEditorWidgetSetup(int index, const QgsEditorWidgetSetup &setup)
The editor widget setup defines which QgsFieldFormatter and editor widget will be used for the field ...
void setConstraintExpression(int index, const QString &expression, const QString &description=QString())
Sets the constraint expression for the specified field index.
Q_INVOKABLE bool rollBack(bool deleteBuffer=true)
Stops a current editing operation and discards any uncommitted edits.
bool readStyle(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) FINAL
void layerModified()
Emitted when modifications has been done on layer.
bool updateFeature(QgsFeature &feature, bool skipDefaultValues=false)
Updates an existing feature in the layer, replacing the attributes and geometry for the feature with ...
Q_INVOKABLE bool commitChanges(bool stopEditing=true)
Attempts to commit to the underlying data provider any buffered changes made since the last to call t...
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
bool setReadOnly(bool readonly=true)
Makes layer read-only (editing disabled) or not.
QgsField::ConfigurationFlags fieldConfigurationFlags(int index) const
Returns the configuration flags of the field at given index.
void editFormConfigChanged()
Will be emitted whenever the edit form configuration of this layer changes.
Q_INVOKABLE void modifySelection(const QgsFeatureIds &selectIds, const QgsFeatureIds &deselectIds)
Modifies the current selection on this layer.
void reselect()
Reselects the previous set of selected features.
void select(QgsFeatureId featureId)
Selects feature by its ID.
QgsEditorWidgetSetup editorWidgetSetup(int index) const
The editor widget setup defines which QgsFieldFormatter and editor widget will be used for the field ...
virtual bool deleteStyleFromDatabase(const QString &styleId, QString &msgError)
Deletes a style from the database.
void setReadExtentFromXml(bool readExtentFromXml)
Flag allowing to indicate if the extent has to be read from the XML document when data source has no ...
void afterCommitChanges()
Emitted after changes are committed to the data provider.
static Q_DECL_DEPRECATED void drawVertexMarker(double x, double y, QPainter &p, QgsVectorLayer::VertexMarkerType type, int vertexSize)
Draws a vertex symbol at (screen) coordinates x, y.
QgsVectorLayer * clone() const override
Returns a new instance equivalent to this one.
Q_DECL_DEPRECATED QgsGeometry::OperationResult addPart(const QList< QgsPointXY > &ring)
Adds a new part polygon to a multipart feature.
QgsAttributeTableConfig attributeTableConfig() const
Returns the attribute table configuration object.
bool readSld(const QDomNode &node, QString &errorMessage) FINAL
QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
QStringList uniqueStringsMatching(int index, const QString &substring, int limit=-1, QgsFeedback *feedback=nullptr) const
Returns unique string values of an attribute which contain a specified subset string.
void raiseError(const QString &msg)
Signals an error related to this vector layer.
void editCommandEnded()
Signal emitted, when an edit command successfully ended.
void supportsEditingChanged()
Emitted when the read only state or the data provider of this layer is changed.
SpatialIndexPresence hasSpatialIndex() const override
void readOnlyChanged()
Emitted when the read only state of this layer is changed.
void removeExpressionField(int index)
Removes an expression field.
virtual void setTransformContext(const QgsCoordinateTransformContext &transformContext) override
Sets the coordinate transform context to transformContext.
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &value)
Emitted whenever an attribute value change is done in the edit buffer.
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false)
Changes an attribute value for a feature (but does not immediately commit the changes).
void setFieldConfigurationFlag(int index, QgsField::ConfigurationFlag flag, bool active)
Sets the given configuration flag for the field at given index to be active or not.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a single feature to the sink.
Q_INVOKABLE bool deleteSelectedFeatures(int *deletedCount=nullptr, DeleteContext *context=nullptr)
Deletes the selected features.
void setFieldAlias(int index, const QString &aliasString)
Sets an alias (a display name) for attributes to display in dialogs.
friend class QgsVectorLayerFeatureSource
QgsRectangle extent() const FINAL
Returns the extent of the layer.
Q_DECL_DEPRECATED void setExcludeAttributesWms(const QSet< QString > &att)
A set of attributes that are not advertised in WMS requests with QGIS server.
void setAttributeTableConfig(const QgsAttributeTableConfig &attributeTableConfig)
Sets the attribute table configuration object.
virtual bool setSubsetString(const QString &subset)
Sets the string (typically sql) used to define a subset of the layer.
Q_INVOKABLE void selectByRect(QgsRectangle &rect, QgsVectorLayer::SelectBehavior behavior=QgsVectorLayer::SetSelection)
Selects features found within the search rectangle (in layer's coordinates)
bool readXml(const QDomNode &layer_node, QgsReadWriteContext &context) FINAL
Reads vector layer specific state from project file Dom node.
FeatureAvailability hasFeatures() const FINAL
Determines if this vector layer has features.
void afterRollBack()
Emitted after changes are rolled back.
QString decodedSource(const QString &source, const QString &provider, const QgsReadWriteContext &context) const FINAL
Called by readLayerXML(), used by derived classes to decode provider's specific data source from proj...
Q_DECL_DEPRECATED QgsGeometry::OperationResult splitParts(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits parts cut by the given line.
void setDiagramLayerSettings(const QgsDiagramLayerSettings &s)
QList< QgsWeakRelation > weakRelations() const
Returns the layer's weak relations as specified in the layer's style.
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
void beforeAddingExpressionField(const QString &fieldName)
Will be emitted, when an expression field is going to be added to this vector layer.
bool deleteAttributes(const QList< int > &attrs)
Deletes a list of attribute fields (but does not commit it)
void updatedFields()
Emitted whenever the fields available from this layer have been changed.
QVariant defaultValue(int index, const QgsFeature &feature=QgsFeature(), QgsExpressionContext *context=nullptr) const
Returns the calculated default value for the specified field index.
void featureAdded(QgsFeatureId fid)
Emitted when a new feature has been added to the layer.
long featureCount() const FINAL
Returns feature count including changes which have not yet been committed If you need only the count ...
QString sourceName() const FINAL
Returns a friendly display name for the source.
QString attributeAlias(int index) const
Returns the alias of an attribute name or a null string if there is no alias.
void featureDeleted(QgsFeatureId fid)
Emitted when a feature has been deleted.
Q_INVOKABLE void removeSelection()
Clear selection.
bool allowCommit() const
Controls, if the layer is allowed to commit changes.
QgsConditionalLayerStyles * conditionalStyles() const
Returns the conditional styles that are set for this layer.
void readCustomSymbology(const QDomElement &element, QString &errorMessage)
Signal emitted whenever the symbology (QML-file) for this layer is being read.
void reload() FINAL
Synchronises with changes in the datasource.
const QList< QgsVectorLayerJoinInfo > vectorJoins() const
bool renameAttribute(int index, const QString &newName)
Renames an attribute field (but does not commit it).
bool simplifyDrawingCanbeApplied(const QgsRenderContext &renderContext, QgsVectorSimplifyMethod::SimplifyHint simplifyHint) const
Returns whether the VectorLayer can apply the specified simplification hint.
void beforeRollBack()
Emitted before changes are rolled back.
QgsAttributeList primaryKeyAttributes() const
Returns the list of attributes which make up the layer's primary keys.
const QgsAbstractVectorLayerLabeling * labeling() const
Access to const labeling configuration.
bool writeXml(QDomNode &layer_node, QDomDocument &doc, const QgsReadWriteContext &context) const FINAL
Writes vector layer specific state to project file Dom node.
QString encodedSource(const QString &source, const QgsReadWriteContext &context) const FINAL
Called by writeLayerXML(), used by derived classes to encode provider's specific data source to proje...
void beginEditCommand(const QString &text)
Create edit command for undo/redo operations.
QString displayField() const
This is a shorthand for accessing the displayExpression if it is a simple field.
const QgsDiagramRenderer * diagramRenderer() const
Q_INVOKABLE void selectByIds(const QgsFeatureIds &ids, QgsVectorLayer::SelectBehavior behavior=QgsVectorLayer::SetSelection)
Selects matching features using a list of feature IDs.
QVariant aggregate(QgsAggregateCalculator::Aggregate aggregate, const QString &fieldOrExpression, const QgsAggregateCalculator::AggregateParameters &parameters=QgsAggregateCalculator::AggregateParameters(), QgsExpressionContext *context=nullptr, bool *ok=nullptr, QgsFeatureIds *fids=nullptr) const
Calculates an aggregated value from the layer's features.
void setDiagramRenderer(QgsDiagramRenderer *r)
Sets diagram rendering object (takes ownership)
void geometryChanged(QgsFeatureId fid, const QgsGeometry &geometry)
Emitted whenever a geometry change is done in the edit buffer.
QgsEditFormConfig editFormConfig
QList< const QgsFeatureRendererGenerator * > featureRendererGenerators() const
Returns a list of the feature renderer generators owned by the layer.
bool moveVertex(double x, double y, QgsFeatureId atFeatureId, int atVertex)
Moves the vertex at the given position number, ring and item (first number is index 0),...
QgsGeometry getGeometry(QgsFeatureId fid) const
Queries the layer for the geometry at the given id.
int addTopologicalPoints(const QgsGeometry &geom)
Adds topological points for every vertex of the geometry.
const QgsVectorSimplifyMethod & simplifyMethod() const
Returns the simplification settings for fast rendering of features.
void beforeModifiedCheck() const
Emitted when the layer is checked for modifications. Use for last-minute additions.
Q_INVOKABLE void invertSelection()
Selects not selected features and deselects selected ones.
bool changeGeometry(QgsFeatureId fid, QgsGeometry &geometry, bool skipDefaultValue=false)
Changes a feature's geometry within the layer's edit buffer (but does not immediately commit the chan...
Q_DECL_DEPRECATED void setDataSource(const QString &dataSource, const QString &baseName, const QString &provider, bool loadDefaultStyleFlag=false)
Update the data source of the layer.
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const FINAL
Calculates a list of unique values contained within an attribute in the layer.
QgsFeatureRenderer * renderer()
Returns the feature renderer used for rendering the features in the layer in 2D map views.
bool forceLocalOptimization() const
Gets where the simplification executes, after fetch the geometries from provider, or when supported,...
void setSimplifyHints(SimplifyHints simplifyHints)
Sets the simplification hints of the vector layer managed.
float maximumScale() const
Gets the maximum scale at which the layer should be simplified.
void setThreshold(float threshold)
Sets the simplification threshold of the vector layer managed.
void setSimplifyAlgorithm(SimplifyAlgorithm simplifyAlgorithm)
Sets the local simplification algorithm of the vector layer managed.
void setForceLocalOptimization(bool localOptimization)
Sets where the simplification executes, after fetch the geometries from provider, or when supported,...
SimplifyHints simplifyHints() const
Gets the simplification hints of the vector layer managed.
SimplifyAlgorithm simplifyAlgorithm() const
Gets the local simplification algorithm of the vector layer managed.
float threshold() const
Gets the simplification threshold of the vector layer managed.
SimplifyHint
Simplification flags for fast rendering of features.
SimplifyAlgorithm
Types of local simplification algorithms that can be used.
void setMaximumScale(float maximumScale)
Sets the maximum scale at which the layer should be simplified.
@ Referencing
The layer is referencing.
@ Referenced
The layer is referenced.
static void writeXml(const QgsVectorLayer *layer, WeakRelationType type, const QgsRelation &relation, QDomNode &node, QDomDocument &doc)
Writes a weak relation infoto an XML structure.
static QgsWeakRelation readXml(const QgsVectorLayer *layer, WeakRelationType type, const QDomNode &node, const QgsPathResolver resolver)
Returns a weak relation for the given layer.
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:938
static QString geometryDisplayString(GeometryType type) SIP_HOLDGIL
Returns a display string for a geometry type.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
static QString displayString(Type type) SIP_HOLDGIL
Returns a non-translated display string type for a WKB type, e.g., the geometry name used in WKT geom...
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
static QgsRectangle readRectangle(const QDomElement &element)
Definition: qgsxmlutils.cpp:39
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgsmaplayer.h:69
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is less than the second.
Definition: qgis.cpp:121
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is greater than the second.
Definition: qgis.cpp:189
#define FALLTHROUGH
Definition: qgis.h:829
QString qgsEnumValueToKey(const T &value)
Returns the value for the given key of an enum.
Definition: qgis.h:507
T qgsFlagKeysToValue(const QString &keys, const T &defaultValue)
Returns the value corresponding to the given keys of a flag.
Definition: qgis.h:562
QMap< QString, QString > QgsStringMap
Definition: qgis.h:759
QString qgsFlagValueToKeys(const T &value)
Returns the value for the given keys of a flag.
Definition: qgis.h:550
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true)
Returns the value corresponding to the given key of an enum.
Definition: qgis.h:520
QVector< QgsPoint > QgsPointSequence
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:614
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
QList< int > QgsAttributeList
Definition: qgsfield.h:26
const QgsField & field
Definition: qgsfield.h:472
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
#define RENDERER_TAG_NAME
Definition: qgsrenderer.h:51
bool saveStyle_t(const QString &uri, const QString &qmlStyle, const QString &sldStyle, const QString &styleName, const QString &styleDescription, const QString &uiFileContent, bool useAsDefault, QString &errCause)
int listStyles_t(const QString &uri, QStringList &ids, QStringList &names, QStringList &descriptions, QString &errCause)
QString getStyleById_t(const QString &uri, QString styleID, QString &errCause)
bool deleteStyleById_t(const QString &uri, QString styleID, QString &errCause)
QString loadStyle_t(const QString &uri, QString &errCause)
QMap< QgsFeatureId, QgsFeature > QgsFeatureMap
A bundle of parameters controlling aggregate calculation.
Setting options for creating vector data providers.
Context for cascade delete features.
QList< QgsVectorLayer * > handledLayers(bool includeAuxiliaryLayers=true) const
Returns a list of all layers affected by the delete operation.
QMap< QgsVectorLayer *, QgsFeatureIds > mHandledFeatures
QgsFeatureIds handledFeatures(QgsVectorLayer *layer) const
Returns a list of feature IDs from the specified layer affected by the delete operation.
Setting options for loading vector layers.
QgsWkbTypes::Type fallbackWkbType
Fallback geometry type.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
bool loadDefaultStyle
Set to true if the default layer style should be loaded.
QgsCoordinateTransformContext transformContext
Coordinate transform context.
QgsCoordinateReferenceSystem fallbackCrs
Fallback layer coordinate reference system.