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