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